From 28d0f0626d8e6d6294c8cc4572525d1bb70ecc70 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:28:20 -0500 Subject: [PATCH] Import 2.3.26pre3 --- CREDITS | 3 +- Documentation/Configure.help | 20 +- Documentation/computone.txt | 2 +- Documentation/digiboard.txt | 6 +- Documentation/filesystems/bfs.txt | 13 +- Documentation/ftape.txt | 6 +- Documentation/hayes-esp.txt | 2 +- Documentation/ide.txt | 2 +- Documentation/joystick-parport.txt | 2 +- Documentation/joystick.txt | 16 +- Documentation/modules.txt | 12 +- Documentation/networking/arcnet-hardware.txt | 21 +- Documentation/networking/baycom.txt | 2 +- Documentation/networking/ltpc.txt | 2 +- Documentation/networking/soundmodem.txt | 2 +- Documentation/parport.txt | 2 +- Documentation/sound/AWE32 | 2 +- Documentation/sound/AudioExcelDSP16 | 4 +- Documentation/sound/CMI8330 | 2 +- Documentation/sound/Introduction | 8 +- Documentation/sound/OPL3-SA2 | 2 +- Documentation/sound/Opti | 6 +- Documentation/sound/README.modules | 4 +- Documentation/sound/Wavefront | 2 +- MAINTAINERS | 4 +- arch/alpha/config.in | 5 + arch/alpha/defconfig | 2 + arch/arm/config.in | 5 + arch/arm/defconfig | 2 + arch/i386/mm/init.c | 10 +- arch/m68k/config.in | 5 + arch/m68k/defconfig | 2 + arch/mips/config.in | 3 + arch/mips/defconfig | 2 + arch/ppc/amiga/Makefile | 3 +- arch/ppc/amiga/amiints.c | 50 +- arch/ppc/amiga/cia.c | 236 +- arch/ppc/amiga/config.c | 4 +- arch/ppc/common_defconfig | 165 +- arch/ppc/config.in | 7 + arch/ppc/defconfig | 2 + arch/ppc/kernel/Makefile | 8 +- arch/ppc/kernel/apus_setup.c | 244 +- arch/ppc/kernel/head.S | 143 +- arch/ppc/kernel/irq.c | 38 +- arch/ppc/kernel/mk_defs.c | 3 + arch/ppc/kernel/pmac_setup.c | 5 +- arch/ppc/kernel/pmac_support.c | 4 + arch/ppc/kernel/ppc_ksyms.c | 2 + arch/ppc/kernel/process.c | 79 +- arch/ppc/kernel/setup.c | 3 + arch/ppc/kernel/traps.c | 36 + arch/ppc/lib/checksum.S | 4 + arch/ppc/mm/init.c | 2 +- arch/sh/config.in | 29 +- arch/sh/defconfig | 19 +- arch/sh/kernel/entry.S | 60 +- arch/sh/kernel/head.S | 7 +- arch/sh/kernel/irq_onchip.c | 128 +- arch/sh/kernel/process.c | 4 +- arch/sh/kernel/setup.c | 24 +- arch/sh/kernel/sys_sh.c | 5 +- arch/sh/kernel/time.c | 14 +- arch/sh/lib/checksum.S | 4 +- arch/sh/mm/fault.c | 104 +- arch/sh/mm/init.c | 7 +- arch/sparc/config.in | 5 + arch/sparc/defconfig | 2 + arch/sparc64/config.in | 5 + arch/sparc64/defconfig | 2 + drivers/block/hpt34x.c | 3 +- drivers/block/icside.c | 3 +- drivers/block/ide-cd.c | 37 +- drivers/block/ide-disk.c | 13 +- drivers/block/ide-dma.c | 3 +- drivers/block/ide-floppy.c | 9 +- drivers/block/ide-pmac.c | 3 +- drivers/block/ide-tape.c | 9 +- drivers/block/ide.c | 63 +- drivers/block/loop.c | 4 +- drivers/block/pdc4030.c | 20 +- drivers/block/trm290.c | 3 +- drivers/char/README.computone | 2 +- drivers/char/ip2/ip2.h | 7 +- drivers/char/isicom.c | 2 +- drivers/char/joystick/joy-amiga.c | 4 +- drivers/char/joystick/joy-analog.c | 4 +- drivers/char/joystick/joy-analog.h | 4 +- drivers/char/joystick/joy-assasin.c | 6 +- drivers/char/joystick/joy-gravis.c | 2 +- drivers/char/joystick/joy-lightning.c | 4 +- drivers/char/joystick/joy-logitech.c | 4 +- drivers/char/joystick/joy-sidewinder.c | 4 +- drivers/char/joystick/joy-thrustmaster.c | 4 +- drivers/char/joystick/joy-turbografx.c | 4 +- drivers/char/joystick/joystick.c | 4 +- drivers/char/sysrq.c | 2 +- drivers/net/arcnet.c | 4 +- drivers/net/sis900.c | 2824 +++++++----------- drivers/net/sis900.h | 248 ++ drivers/parport/share.c | 2 +- drivers/scsi/ide-scsi.c | 17 +- drivers/scsi/scsi.c | 2 +- drivers/usb/CREDITS | 2 +- drivers/usb/README.dc2xx | 105 + drivers/usb/acm.c | 257 +- drivers/usb/audio.c | 9 +- drivers/usb/cpia.c | 9 +- drivers/usb/dc2xx.c | 106 +- drivers/usb/ezusb.c | 10 +- drivers/usb/hp_scanner.c | 6 +- drivers/usb/hub.c | 18 +- drivers/usb/keyboard.c | 9 +- drivers/usb/mouse.c | 6 +- drivers/usb/printer.c | 6 +- drivers/usb/proc_usb.c | 14 +- drivers/usb/uhci.c | 262 +- drivers/usb/uhci.h | 12 +- drivers/usb/usb-core.c | 3 +- drivers/usb/usb-serial.c | 3 - drivers/usb/usb.c | 413 +-- drivers/usb/usb.h | 69 +- drivers/usb/usb_scsi.c | 6 +- drivers/usb/uss720.c | 6 +- drivers/video/fbmem.c | 2 +- fs/adfs/inode.c | 2 +- fs/bfs/bfs_defs.h | 1 + fs/bfs/file.c | 10 +- fs/bfs/inode.c | 21 +- fs/buffer.c | 1 + fs/ext2/file.c | 15 +- fs/ext2/inode.c | 20 +- fs/fat/file.c | 5 +- fs/fat/inode.c | 189 +- fs/hfs/file.c | 1 - fs/lockd/mon.c | 10 +- fs/ncpfs/inode.c | 14 +- fs/ncpfs/mmap.c | 5 + fs/ncpfs/ncplib_kernel.h | 3 +- fs/proc/array.c | 3 +- fs/proc/kcore.c | 1 + fs/read_write.c | 8 +- fs/sysv/namei.c | 2 +- fs/udf/super.c | 4 +- fs/udf/truncate.c | 2 +- include/asm-i386/pgtable.h | 1 - include/asm-ppc/amigaints.h | 136 +- include/asm-ppc/pgtable.h | 9 +- include/asm-ppc/processor.h | 5 + include/asm-ppc/system.h | 2 + include/asm-sh/bitops.h | 19 +- include/asm-sh/io.h | 36 + include/asm-sh/ioctls.h | 12 +- include/asm-sh/irq.h | 8 + include/asm-sh/mmu_context.h | 44 +- include/asm-sh/page.h | 11 +- include/asm-sh/pgtable-2level.h | 4 +- include/asm-sh/pgtable.h | 23 +- include/asm-sh/resource.h | 20 +- include/asm-sh/spinlock.h | 47 - include/asm-sh/string.h | 20 +- include/asm-sh/uaccess.h | 22 +- include/linux/bfs_fs.h | 4 +- include/linux/bfs_fs_i.h | 6 +- include/linux/bfs_fs_sb.h | 24 +- include/linux/highmem.h | 1 + include/linux/ide.h | 9 +- include/linux/joystick.h | 2 +- include/linux/msdos_fs_sb.h | 1 + include/linux/pagemap.h | 6 +- ipc/shm.c | 20 +- ipc/util.c | 2 +- mm/filemap.c | 56 +- mm/memory.c | 14 +- mm/swapfile.c | 4 +- 175 files changed, 3953 insertions(+), 3229 deletions(-) create mode 100644 drivers/net/sis900.h create mode 100644 drivers/usb/README.dc2xx diff --git a/CREDITS b/CREDITS index 4d61d7474f66..851e85409d34 100644 --- a/CREDITS +++ b/CREDITS @@ -1612,10 +1612,11 @@ S: 644 00 Brno S: Czech Republic N: Vojtech Pavlik -E: vojtech@ucw.cz +E: vojtech@suse.cz D: Joystick driver D: arcnet-hardware readme D: Minor ARCnet hacking +D: USB hacking S: Ucitelska 1576 S: Prague 8 S: 182 00 Czech Republic diff --git a/Documentation/Configure.help b/Documentation/Configure.help index c51ded49a917..02983530ef34 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -2993,7 +2993,7 @@ CONFIG_UNIX here and read Documentation/modules.txt. The module will be called unix.o. If you try building this as a module and you have said Y to "Kernel module loader support" above, be sure to add 'alias net-pf-1 - unix' to your /etc/conf.modules file. Note that several important + unix' to your /etc/modules.conf file. Note that several important services won't work correctly if you say M here and then neglect to load the module. @@ -3717,7 +3717,7 @@ CONFIG_PACKET whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt; if you use modprobe or kmod, you may also want to add "alias net-pf-17 af_packet" to - /etc/conf.modules. + /etc/modules.conf. If unsure, say Y. @@ -7858,6 +7858,18 @@ CONFIG_USB_CPIA The module will be called cpia.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +USB Kodak DC-2xx Camera support +CONFIG_USB_DC2XX + Say Y here if you want to connect this type of still camera to + your computer's USB port. See drivers/usb/README.dc2xx for more + information; some non-Kodak cameras may also work with this + driver, given application support (such as www.gPhoto.org). + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dc2xx.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + USB SCSI Support CONFIG_USB_SCSI Say Y here if you want to connect SCSI devices to your computer's @@ -7994,7 +8006,9 @@ CONFIG_BFS_FS during the boot process. It is usually mounted under /stand and corresponds to the slice marked as "STAND" in the UnixWare partition. This is useful if you want to access files on your /stand - slice from Linux. If you don't know what it is, say N. + slice from Linux. More information on this filesystem can be found in + Documentation/filesystems/bfs.txt file. If you do not know what it is, + say N. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), diff --git a/Documentation/computone.txt b/Documentation/computone.txt index c1577ec21098..9d39a878aaf4 100644 --- a/Documentation/computone.txt +++ b/Documentation/computone.txt @@ -59,7 +59,7 @@ d) Run "make config" or "make menuconfig" or "make xconfig" e) Set address on ISA cards then: edit /usr/src/linux/drivers/char/ip2/ip2.h if needed or - edit /etc/conf.modules (or /etc/modules.conf) if needed (module). + edit /etc/modules.conf if needed (module). or both to match this setting. f) Run "make dep" g) Run "make modules" diff --git a/Documentation/digiboard.txt b/Documentation/digiboard.txt index cb63042c21a1..eee81a0cff97 100644 --- a/Documentation/digiboard.txt +++ b/Documentation/digiboard.txt @@ -29,7 +29,7 @@ The driver can be built direct into the kernel or as a module. The pcxx driver can be configured using the command line feature while loading the kernel with LILO or LOADLIN or, if built as a module, with arguments to insmod and modprobe or with parameters in -/etc/conf.modules for modprobe and kerneld. +/etc/modules.conf for modprobe and kerneld. After configuring the driver you need to create the device special files as described in "Device file creation:" below and set the appropriate @@ -96,13 +96,13 @@ devices following that board, you can empty the io-value for that board: The remaining board still uses ttyD8-ttyD15 and cud8-cud15. -Example line for /etc/conf.modules for use with kerneld and as default +Example line for /etc/modules.conf for use with kerneld and as default parameters for modprobe: options pcxx io=0x200 numports=8 For kerneld to work you will likely need to add these two lines to your -/etc/conf.modules: +/etc/modules.conf: alias char-major-22 pcxx alias char-major-23 pcxx diff --git a/Documentation/filesystems/bfs.txt b/Documentation/filesystems/bfs.txt index bd672888a465..a6179cad9612 100644 --- a/Documentation/filesystems/bfs.txt +++ b/Documentation/filesystems/bfs.txt @@ -1,8 +1,13 @@ The BFS filesystem is used on SCO UnixWare machines for /stand slice. -There are no special mount options supported by bfs at this time. -You can mount it only read-only at this stage. Even if you attempt to -mount it read-write it will be automatically mounted read-only, unless -you have enabled "BFS write support" when configuring the kernel. +By default, if you attempt to mount it read-write it will be automatically +mounted read-only. If you want to enable (limited) write support, you need +to select "BFS write support" when configuring the kernel. The write support +at this stage is limited to the blocks preallocated for a given inode. +This means that writes beyond the value of inode->iu_eblock will fail with EIO. +In particular, this means you can create empty files but not write data to them +or you can write data to the existing files and increase their size but not the +number of blocks allocated to them. I am currently working on removing this +limitation, i.e. ability to migrate inodes within BFS filesystem. In order to access /stand partition under Linux you obviously need to know the partition number and the kernel must support UnixWare disk slices diff --git a/Documentation/ftape.txt b/Documentation/ftape.txt index 7de46c2e0461..525df9f892fc 100644 --- a/Documentation/ftape.txt +++ b/Documentation/ftape.txt @@ -244,14 +244,14 @@ C. Boot and load time configuration insmod ftape.o ft_tracing=4 - or by editing the file `/etc/conf.modules' in which case they take + or by editing the file `/etc/modules.conf' in which case they take effect each time when the module is loaded with `modprobe' (please refer to the modules documentation, i.e. `modules.txt' and the respective manual pages). Thus, you should add a line options ftape ft_tracing=4 - to `/etc/conf.modules` if you intend to increase the debugging + to `/etc/modules.conf` if you intend to increase the debugging output of the driver. @@ -299,7 +299,7 @@ C. Boot and load time configuration 5. Example module parameter setting ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To do the same, but with ftape compiled as a loadable kernel - module, add the following line to `/etc/conf.modules': + module, add the following line to `/etc/modules.conf': options ftape ft_probe_fc10=1 ft_tracing=4 diff --git a/Documentation/hayes-esp.txt b/Documentation/hayes-esp.txt index e0a570185275..85885da94a6f 100644 --- a/Documentation/hayes-esp.txt +++ b/Documentation/hayes-esp.txt @@ -109,7 +109,7 @@ option with a space. For example: insmod esp dma=3 trigger=512 The esp module can be automatically loaded when needed. To cause this to -happen, add the following lines to /etc/conf.modules (replacing the last line +happen, add the following lines to /etc/modules.conf (replacing the last line with options for your configuration): alias char-major-57 esp diff --git a/Documentation/ide.txt b/Documentation/ide.txt index 866a3a9097fa..df417541d924 100644 --- a/Documentation/ide.txt +++ b/Documentation/ide.txt @@ -245,7 +245,7 @@ When using ide.c/ide-tape.c as modules in combination with kerneld, add: alias block-major-3 ide-probe alias char-major-37 ide-tape -respectively to /etc/conf.modules. +respectively to /etc/modules.conf. When ide.c is used as a module, you can pass command line parameters to the driver using the "options=" keyword to insmod, while replacing any ',' with diff --git a/Documentation/joystick-parport.txt b/Documentation/joystick-parport.txt index 6bf2cd9c2ab0..880150b9ecd0 100644 --- a/Documentation/joystick-parport.txt +++ b/Documentation/joystick-parport.txt @@ -1,5 +1,5 @@ Linux Joystick parport drivers v1.2 BETA - (c) 1998 Vojtech Pavlik + (c) 1998 Vojtech Pavlik (c) 1998 Andree Borrmann ---------------------------------------------------------------------------- diff --git a/Documentation/joystick.txt b/Documentation/joystick.txt index 9e3a2320a6d6..ab8a454a2ee6 100644 --- a/Documentation/joystick.txt +++ b/Documentation/joystick.txt @@ -1,5 +1,5 @@ Linux Joystick driver v1.2.13 - (c) 1996-1998 Vojtech Pavlik + (c) 1996-1998 Vojtech Pavlik ---------------------------------------------------------------------------- 0. Disclaimer @@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Should you need to contact me, the author, you can do so either by e-mail -- mail your message to , or by paper mail: Vojtech Pavlik, +- mail your message to , or by paper mail: Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic For your convenience, the GNU General Public License version 2 is included @@ -58,20 +58,20 @@ them. Bug reports and success stories are also welcome. The joystick package is available at the following FTP sites: ftp://atrey.karlin.mff.cuni.cz/pub/linux/joystick/ - ftp://artax.karlin.mff.cuni.cz/pub/linux/joystick/ - The joystick driver is also included in the Linux 2.1 kernels: + The joystick driver is also included in the Linux 2.1+ kernels: - ftp://linux.kernel.org/pub/linux/kernel/v2.1/ + ftp://linux.kernel.org/pub/linux/kernel/ And a homepage of the driver is at: - http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/ - http://artax.karlin.mff.cuni.cz/~vojtech/joystick/ + http://www.suse.cz/development/joystick/ - A mirror of the homepage is at: + Mirrors of the homepage are at: + http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/ http://www.trylinux.com/projects/joystick/ + http://www.linuxgames.com/joystick/ There is also a mailing list for the driver at: diff --git a/Documentation/modules.txt b/Documentation/modules.txt index cf8b422140e4..e7e371945222 100644 --- a/Documentation/modules.txt +++ b/Documentation/modules.txt @@ -117,7 +117,7 @@ Using the modprobe utility, you can load any module like this: without paying much attention to which kernel you are running, or what other modules this module depends on. -With the help of the modprobe configuration file: "/etc/conf.modules" +With the help of the modprobe configuration file: "/etc/modules.conf" you can tune the behaviour of modprobe in many ways, including an automatic setting of insmod options for each module. And, yes, there _are_ man-pages for all this... @@ -164,10 +164,10 @@ This is what happens: fits this symbolic description. - modprobe looks into its internal "alias" translation table to see if there is a match. This table can be reconfigured - and expanded by having "alias" lines in "/etc/conf.modules". + and expanded by having "alias" lines in "/etc/modules.conf". - insmod is then asked to insert the module(s) that modprobe has decided that the kernel needs. Every module will be - configured according to the "options" lines in "/etc/conf.modules". + configured according to the "options" lines in "/etc/modules.conf". - modprobe exits and kerneld tells the kernel that the request succeeded (or failed...) - The kernel uses the freshly installed feature just as if it @@ -191,7 +191,7 @@ for maintainers of distributions. To use kerneld with the least amount of "hassle", you need modprobe from a release that can be considered "recent" w.r.t. your kernel, and also -a configuration file for modprobe ("/etc/conf.modules"). +a configuration file for modprobe ("/etc/modules.conf"). Since modprobe already knows about most modules, the minimal configuration file could look something like this: @@ -208,10 +208,6 @@ You could add these lines as well, but they are only "cosmetic": alias net-pf-4 off # if you don't use the ipx module alias net-pf-5 off # if you don't use the appletalk module -Finally, for the "purists": -You can name the modprobe configuration either "/etc/conf.modules" or -"/etc/modules.conf", since modprobe knows what to do in each case... - Written by: Jacques Gelinas diff --git a/Documentation/networking/arcnet-hardware.txt b/Documentation/networking/arcnet-hardware.txt index 638bb8abfff4..b84cdc4d648e 100644 --- a/Documentation/networking/arcnet-hardware.txt +++ b/Documentation/networking/arcnet-hardware.txt @@ -78,7 +78,7 @@ CABLING ARCNET NETWORKS ----------------------- This section was rewritten by - Vojtech Pavlik + Vojtech Pavlik using information from several people, including: Avery Pennraun Stephen A. Wood @@ -270,7 +270,7 @@ All ARCnet cards should have a total of four or five different settings: that IRQ2 is the same as IRQ9, as far as Linux is concerned. You can "cat /proc/interrupts" for a somewhat complete list of which ones are in use at any given time. Here is a list of common usages from Vojtech - Pavlik : + Pavlik : ("Not on bus" means there is no way for a card to generate this interrupt) IRQ 0 - Timer 0 (Not on bus) @@ -347,8 +347,7 @@ All ARCnet cards should have a total of four or five different settings: network. Also, on many cards (not mine, though) there are red and green LED's. -Vojtech Pavlik tells me this is what they -mean: +Vojtech Pavlik tells me this is what they mean: GREEN RED Status ----- --- ------ OFF OFF Power off @@ -1735,11 +1734,11 @@ JP 6 : IRQ set (ONLY ONE jumper on 1-5 for IRQ 2-6) ** Acer ** 8-bit card, Model 5210-003 -------------------------- - - from Vojtech Pavlik using portions of - the existing arcnet-hardware file. + - from Vojtech Pavlik using portions of the existing + arcnet-hardware file. -This is a 90C26 based card. Its configuration seems similar to -the SMC PC100, but has some additional jumpers I don't know. +This is a 90C26 based card. Its configuration seems similar to the SMC +PC100, but has some additional jumpers I don't know the meaning of. __ | | @@ -1903,7 +1902,7 @@ guess the purpose. ** Datapoint? ** LAN-ARC-8, an 8-bit card ------------------------ - - from Vojtech Pavlik + - from Vojtech Pavlik This is another SMC 90C65-based ARCnet card. I couldn't identify the manufacturer, but it might be DataPoint, because the card has the @@ -2043,7 +2042,7 @@ parameters. These two switches are normally left in the OFF position. ** Topware ** 8-bit card, TA-ARC/10 ------------------------- - - from Vojtech Pavlik + - from Vojtech Pavlik This is another very similar 90C65 card. Most of the switches and jumpers are the same as on other clones. @@ -2752,7 +2751,7 @@ Setting the Timeouts ** No Name ** 8-bit cards ("Made in Taiwan R.O.C.") ----------- - - from Vojtech Pavlik + - from Vojtech Pavlik I have named this ARCnet card "NONAME", since I got only the card with no manual at all and the only text identifying the manufacturer is diff --git a/Documentation/networking/baycom.txt b/Documentation/networking/baycom.txt index 71e0c76dfde7..b9d58fe2f6b8 100644 --- a/Documentation/networking/baycom.txt +++ b/Documentation/networking/baycom.txt @@ -93,7 +93,7 @@ Every time a driver is inserted into the kernel, it has to know which modems it should access at which ports. This can be done with the setbaycom utility. If you are only using one modem, you can also configure the driver from the insmod command line (or by means of an option line in -/etc/conf.modules). +/etc/modules.conf). Examples: insmod baycom_ser_fdx mode="ser12*" iobase=0x3f8 irq=4 diff --git a/Documentation/networking/ltpc.txt b/Documentation/networking/ltpc.txt index ed9983f0786b..b93585b9571c 100644 --- a/Documentation/networking/ltpc.txt +++ b/Documentation/networking/ltpc.txt @@ -25,7 +25,7 @@ the driver will try to determine them itself. If you load the driver as a module, you can pass the parameters "io=", "irq=", and "dma=" on the command line with insmod or modprobe, or add -them as options in /etc/conf.modules: +them as options in /etc/modules.conf: alias lt0 ltpc # autoload the module when the interface is configured options ltpc io=0x240 irq=9 dma=1 diff --git a/Documentation/networking/soundmodem.txt b/Documentation/networking/soundmodem.txt index 202101d186e2..f6d49e9af01b 100644 --- a/Documentation/networking/soundmodem.txt +++ b/Documentation/networking/soundmodem.txt @@ -39,7 +39,7 @@ Every time the driver is inserted into the kernel, it has to know which modems it should access at which ports. This can be done with the setbaycom utility. If you are only using one modem, you can also configure the driver from the insmod command line (or by means of an option line in -/etc/conf.modules). +/etc/modules.conf). Examples: insmod soundmodem mode="sbc:afsk1200" iobase=0x220 irq=5 dma=1 diff --git a/Documentation/parport.txt b/Documentation/parport.txt index c932216df82a..db0c13e0b3dc 100644 --- a/Documentation/parport.txt +++ b/Documentation/parport.txt @@ -35,7 +35,7 @@ auto-detected IRQ. Currently, PC-style (parport_pc), Sun Ultra/AX KMod ---- -If you use kmod, you will find it useful to edit /etc/conf.modules. +If you use kmod, you will find it useful to edit /etc/modules.conf. Here is an example of the lines that need to be added: post-install parport modprobe -k parport_pc diff --git a/Documentation/sound/AWE32 b/Documentation/sound/AWE32 index edc0b880e309..a0f18d640a93 100644 --- a/Documentation/sound/AWE32 +++ b/Documentation/sound/AWE32 @@ -83,7 +83,7 @@ Compile it. Copy sfxload program to /usr/bin. To enable AWE general midi synthesis you should also get the sound bank file for general midi from http://members.xoom.com/yar/synthgm.sbk.gz. Copy it to /usr and gunzip it there. -7) Edit /etc/conf.modules, inserting at the end of the file: +7) Edit /etc/modules.conf, inserting at the end of the file: alias midi awe_wave post-install awe_wave /usr/bin/sfxload /usr/synthfm.sbk diff --git a/Documentation/sound/AudioExcelDSP16 b/Documentation/sound/AudioExcelDSP16 index 855ee59deec0..f4ffd9d0c2e1 100644 --- a/Documentation/sound/AudioExcelDSP16 +++ b/Documentation/sound/AudioExcelDSP16 @@ -41,7 +41,7 @@ mpu_base I/O base address for activate MPU-401 mode (0x300, 0x310, 0x320 or 0x330) mpu_irq MPU-401 irq line (5, 7, 9, 10 or 0) -The /etc/conf.modules will have lines like this: +The /etc/modules.conf will have lines like this: options opl3 io=0x388 options ad1848 io=0x530 irq=11 dma=3 @@ -51,7 +51,7 @@ Where the aedsp16 options are the options for this driver while opl3 and ad1848 are the corresponding options for the MSS and OPL3 modules. Loading MSS and OPL3 needs to pre load the aedsp16 module to set up correctly -the sound card. Installation dependencies must be written in the conf.modules +the sound card. Installation dependencies must be written in the modules.conf file: pre-install ad1848 modprobe aedsp16 diff --git a/Documentation/sound/CMI8330 b/Documentation/sound/CMI8330 index fca15f6069e6..a12bed1d2df9 100644 --- a/Documentation/sound/CMI8330 +++ b/Documentation/sound/CMI8330 @@ -88,7 +88,7 @@ CONFIG_SOUND_MSS=m -Alma Chao suggests the following /etc/conf.modules: +Alma Chao suggests the following /etc/modules.conf: alias sound ad1848 alias synth0 opl3 diff --git a/Documentation/sound/Introduction b/Documentation/sound/Introduction index f33121e0ccbf..0e9bbc865818 100644 --- a/Documentation/sound/Introduction +++ b/Documentation/sound/Introduction @@ -145,7 +145,7 @@ MODPROBE: ========= If loading via modprobe, these common files are automatically loaded -when requested by modprobe. For example, my /etc/conf.modules contains: +when requested by modprobe. For example, my /etc/modules.conf contains: alias sound sb options sb io=0x240 irq=9 dma=3 dma16=5 mpu_io=0x300 @@ -205,7 +205,7 @@ http://www.opensound.com. Before loading the commercial sound driver, you should do the following: 1. remove sound modules (detailed above) -2. remove the sound modules from /etc/conf.modules +2. remove the sound modules from /etc/modules.conf 3. move the sound modules from /lib/modules//misc (for example, I make a /lib/modules//misc/tmp directory and copy the sound module files to that @@ -241,7 +241,7 @@ twice, you need to do the following: sb.o could be copied (or symlinked) to sb1.o for the second SoundBlasster. -2. Make a second entry in /etc/conf.modules, for example, +2. Make a second entry in /etc/modules.conf, for example, sound1 or sb1. This second entry should refer to the new module names for example sb1, and should include the I/O, etc. for the second sound card. @@ -333,7 +333,7 @@ There are several ways of configuring your sound: 2) On the command line when using insmod or in a bash script using command line calls to load sound. -3) In /etc/conf.modules when using modprobe. +3) In /etc/modules.conf when using modprobe. 4) Via Red Hat's /usr/sbin/sndconfig program (text based). diff --git a/Documentation/sound/OPL3-SA2 b/Documentation/sound/OPL3-SA2 index a51a4aebbaad..e6bca70896d4 100644 --- a/Documentation/sound/OPL3-SA2 +++ b/Documentation/sound/OPL3-SA2 @@ -125,7 +125,7 @@ and I'll try my best to help. Lastly, if you're using modules and want to set up automatic module loading with kmod, the kernel module loader, here is the section I -currently use in my conf.modules file: +currently use in my modules.conf file: # Sound alias char-major-14 opl3sa2 diff --git a/Documentation/sound/Opti b/Documentation/sound/Opti index 34b0f433127d..07318d2435fe 100644 --- a/Documentation/sound/Opti +++ b/Documentation/sound/Opti @@ -18,7 +18,7 @@ force the card into a mode in which it can be programmed. If you have another OS installed on your computer it is recommended that Linux and the other OS use the same resources. -Also, it is recommended that resources specified in /etc/conf.modules +Also, it is recommended that resources specified in /etc/modules.conf and resources specified in /etc/isapnp.conf agree. Compiling the sound driver @@ -68,9 +68,9 @@ address is hard-coded into the driver. Using kmod and autoloading the sound driver ------------------------------------------- Comment: as of linux-2.1.90 kmod is replacing kerneld. -The config file '/etc/conf.modules' is used as before. +The config file '/etc/modules.conf' is used as before. -This is the sound part of my /etc/conf.modules file. +This is the sound part of my /etc/modules.conf file. Following that I will explain each line. alias mixer0 mad16 diff --git a/Documentation/sound/README.modules b/Documentation/sound/README.modules index 91d0445860c9..9cc30a3ac837 100644 --- a/Documentation/sound/README.modules +++ b/Documentation/sound/README.modules @@ -26,7 +26,7 @@ Note that it is no longer necessary or possible to configure sound in the drivers/sound dir. Now one simply configures and makes one's kernel and modules in the usual way. - Then, add to your /etc/modules.conf or /etc/conf.modules something like: + Then, add to your /etc/modules.conf something like: alias char-major-14 sb post-install sb /sbin/modprobe "-k" "adlib_card" @@ -82,7 +82,7 @@ wasteful of RAM, but it guarantees that sound always works. To make the sound driver use persistent DMA buffers we need to pass the sound.o module a "dmabuf=1" command-line argument. This is normally done -in /etc/conf.modules (or the more proper /etc/modules.conf) like so: +in /etc/modules.conf like so: options sound dmabuf=1 diff --git a/Documentation/sound/Wavefront b/Documentation/sound/Wavefront index 66501a5663b3..f1dcf975f801 100644 --- a/Documentation/sound/Wavefront +++ b/Documentation/sound/Wavefront @@ -190,7 +190,7 @@ Here's my autoconf.h SOUND section: 6) How do I configure my card ? ************************************************************ -You need to edit /etc/conf.modules. Here's mine (edited to show the +You need to edit /etc/modules.conf. Here's mine (edited to show the relevant details): # Sound system diff --git a/MAINTAINERS b/MAINTAINERS index f055c2a6afcb..14efbdd5dfb4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -490,9 +490,9 @@ S: Maintained JOYSTICK DRIVER P: Vojtech Pavlik -M: vojtech@ucw.cz +M: vojtech@suse.cz L: linux-joystick@atrey.karlin.mff.cuni.cz -W: http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/ +W: http://www.suse.cz/development/joystick/ S: Maintained KERNEL AUTOMOUNTER (AUTOFS) diff --git a/arch/alpha/config.in b/arch/alpha/config.in index 525305c764e6..f6dc93f61ad9 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -172,6 +172,11 @@ bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL +if [ "$CONFIG_PROC_FS" = "y" ]; then + choice 'Kernel core (/proc/kcore) format' \ + "ELF CONFIG_KCORE_ELF \ + A.OUT CONFIG_KCORE_AOUT" ELF +fi tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig index 186505edad64..54a05ea5a291 100644 --- a/arch/alpha/defconfig +++ b/arch/alpha/defconfig @@ -47,6 +47,8 @@ CONFIG_PCI=y CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set CONFIG_SYSCTL=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y diff --git a/arch/arm/config.in b/arch/arm/config.in index 81c95f6be806..249759e1ad69 100644 --- a/arch/arm/config.in +++ b/arch/arm/config.in @@ -144,6 +144,11 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL tristate 'Math emulation' CONFIG_NWFPE +if [ "$CONFIG_PROC_FS" = "y" ]; then + choice 'Kernel core (/proc/kcore) format' \ + "ELF CONFIG_KCORE_ELF \ + A.OUT CONFIG_KCORE_AOUT" ELF +fi tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC diff --git a/arch/arm/defconfig b/arch/arm/defconfig index d289870eae28..ef7d1e3157dc 100644 --- a/arch/arm/defconfig +++ b/arch/arm/defconfig @@ -49,6 +49,8 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_NWFPE=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index d2089fbd0e1c..48b4b83ec06f 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -379,10 +379,16 @@ void __init zap_low_mappings (void) { int i; /* - * Zap initial low-memory mappings: + * Zap initial low-memory mappings. + * + * Note that "pgd_clear()" doesn't do it for + * us in this case, because pgd_clear() is a + * no-op in the 2-level case (pmd_clear() is + * the thing that clears the page-tables in + * that case). */ for (i = 0; i < USER_PTRS_PER_PGD; i++) - pgd_clear(swapper_pg_dir + i); + pgd_val(swapper_pg_dir[i]) = 0; } /* diff --git a/arch/m68k/config.in b/arch/m68k/config.in index a458ff609349..4888b4b48af2 100644 --- a/arch/m68k/config.in +++ b/arch/m68k/config.in @@ -70,6 +70,11 @@ bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL +if [ "$CONFIG_PROC_FS" = "y" ]; then + choice 'Kernel core (/proc/kcore) format' \ + "ELF CONFIG_KCORE_ELF \ + A.OUT CONFIG_KCORE_AOUT" ELF +fi tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig index 109ce19fa86f..b88a48984fd8 100644 --- a/arch/m68k/defconfig +++ b/arch/m68k/defconfig @@ -38,6 +38,8 @@ CONFIG_M68040=y CONFIG_NET=y CONFIG_SYSVIPC=y CONFIG_SYSCTL=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_ZORRO=y diff --git a/arch/mips/config.in b/arch/mips/config.in index 26356e86f82e..b856a2ac08d2 100644 --- a/arch/mips/config.in +++ b/arch/mips/config.in @@ -69,6 +69,9 @@ else bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN fi +if [ "$CONFIG_PROC_FS" = "y" ]; then + define_bool CONFIG_KCORE_ELF y +fi define_bool CONFIG_ELF_KERNEL y if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then diff --git a/arch/mips/defconfig b/arch/mips/defconfig index 2f3af4f3da03..8f00bc812047 100644 --- a/arch/mips/defconfig +++ b/arch/mips/defconfig @@ -35,6 +35,8 @@ CONFIG_CPU_R4X00=y CONFIG_PCI_QUIRKS=y CONFIG_PCI_OLD_PROC=y CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set CONFIG_ELF_KERNEL=y # CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y diff --git a/arch/ppc/amiga/Makefile b/arch/ppc/amiga/Makefile index 2d5ec4811494..8288eabc2cb7 100644 --- a/arch/ppc/amiga/Makefile +++ b/arch/ppc/amiga/Makefile @@ -9,7 +9,8 @@ O_TARGET := amiga.o O_OBJS := config.o amiints.o cia.o time.o \ - bootinfo.o amisound.o chipram.o ints.o + bootinfo.o amisound.o chipram.o + OX_OBJS := amiga_ksyms.o ifdef CONFIG_AMIGA_PCMCIA diff --git a/arch/ppc/amiga/amiints.c b/arch/ppc/amiga/amiints.c index 408f8211c3d5..75d90312baa5 100644 --- a/arch/ppc/amiga/amiints.c +++ b/arch/ppc/amiga/amiints.c @@ -53,10 +53,10 @@ #include #endif -extern int cia_request_irq(struct ciabase *base,int irq, +extern int cia_request_irq(int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id); -extern void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id); +extern void cia_free_irq(unsigned int irq, void *dev_id); extern void cia_init_IRQ(struct ciabase *base); extern int cia_get_irq_list(struct ciabase *base, char *buf); @@ -89,7 +89,8 @@ static void ami_badint(int irq, void *dev_id, struct pt_regs *fp) * the amiga IRQ handling routines. */ -void __init amiga_init_IRQ(void) +__init +void amiga_init_IRQ(void) { int i; @@ -216,13 +217,8 @@ int amiga_request_irq(unsigned int irq, return sys_request_irq(irq - IRQ_AMIGA_AUTO, handler, flags, devname, dev_id); - if (irq >= IRQ_AMIGA_CIAB) - return cia_request_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, - handler, flags, devname, dev_id); - if (irq >= IRQ_AMIGA_CIAA) - return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, - handler, flags, devname, dev_id); + return cia_request_irq(irq, handler, flags, devname, dev_id); /* * IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared, @@ -262,13 +258,8 @@ void amiga_free_irq(unsigned int irq, void *dev_id) if (irq >= IRQ_AMIGA_AUTO) sys_free_irq(irq - IRQ_AMIGA_AUTO, dev_id); - if (irq >= IRQ_AMIGA_CIAB) { - cia_free_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, dev_id); - return; - } - if (irq >= IRQ_AMIGA_CIAA) { - cia_free_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, dev_id); + cia_free_irq(irq, dev_id); return; } @@ -314,17 +305,9 @@ void amiga_enable_irq(unsigned int irq) return; } - if (irq >= IRQ_AMIGA_CIAB) { - cia_set_irq(&ciab_base, (1 << (irq - IRQ_AMIGA_CIAB))); - cia_able_irq(&ciab_base, CIA_ICR_SETCLR | - (1 << (irq - IRQ_AMIGA_CIAB))); - return; - } - if (irq >= IRQ_AMIGA_CIAA) { - cia_set_irq(&ciaa_base, (1 << (irq - IRQ_AMIGA_CIAA))); - cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | - (1 << (irq - IRQ_AMIGA_CIAA))); + cia_set_irq(irq, 0); + cia_able_irq(irq, 1); return; } @@ -349,13 +332,8 @@ void amiga_disable_irq(unsigned int irq) return; } - if (irq >= IRQ_AMIGA_CIAB) { - cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB)); - return; - } - if (irq >= IRQ_AMIGA_CIAA) { - cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA)); + cia_able_irq(irq, 0); return; } @@ -528,10 +506,20 @@ static void ami_int7(int irq, void *dev_id, struct pt_regs *fp) panic ("level 7 interrupt received\n"); } +#ifdef CONFIG_APUS +/* The PPC irq handling links all handlers requested on the same vector + and executes them in a loop. Having ami_badint at the end of the chain + is a bad idea. */ +void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = { + NULL, ami_int1, NULL, NULL /* FB expects to replace ami_int3*/, + ami_int4, ami_int5, NULL, ami_int7 +}; +#else void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = { ami_badint, ami_int1, ami_badint, ami_int3, ami_int4, ami_int5, ami_badint, ami_int7 }; +#endif int amiga_get_irq_list(char *buf) { diff --git a/arch/ppc/amiga/cia.c b/arch/ppc/amiga/cia.c index ea35c79b3122..85133f8dace3 100644 --- a/arch/ppc/amiga/cia.c +++ b/arch/ppc/amiga/cia.c @@ -1 +1,235 @@ -#include "../../m68k/amiga/cia.c" +/* + * linux/arch/m68k/amiga/cia.c - CIA support + * + * Copyright (C) 1996 Roman Zippel + * + * The concept of some functions bases on the original Amiga OS function + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct ciabase { + volatile struct CIA *cia; + u_char icr_mask, icr_data; + u_short int_mask; + int handler_irq, cia_irq, server_irq; + char *name; + struct irq_server server; + irq_handler_t irq_list[CIA_IRQS]; +} ciaa_base = { + &ciaa, 0, 0, IF_PORTS, + IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA, + IRQ_AMIGA_PORTS, + "CIAA handler", {0, 0} +}, ciab_base = { + &ciab, 0, 0, IF_EXTER, + IRQ_AMIGA_AUTO_6, IRQ_AMIGA_CIAB, + IRQ_AMIGA_EXTER, + "CIAB handler", {0, 0} +}; + +#define CIA_SET_BASE_ADJUST_IRQ(base, irq) \ +do { \ + if (irq >= IRQ_AMIGA_CIAB) { \ + base = &ciab_base; \ + irq =- IRQ_AMIGA_CIAB; \ + } else { \ + base = &ciaa_base; \ + irq =- IRQ_AMIGA_CIAA; \ + } \ +} while (0) + +/* + * Cause or clear CIA interrupts, return old interrupt status. + */ + +static unsigned char cia_set_irq_private(struct ciabase *base, + unsigned char mask) +{ + u_char old; + + old = (base->icr_data |= base->cia->icr); + if (mask & CIA_ICR_SETCLR) + base->icr_data |= mask; + else + base->icr_data &= ~mask; + if (base->icr_data & base->icr_mask) + custom.intreq = IF_SETCLR | base->int_mask; + return old & base->icr_mask; +} + +unsigned char cia_set_irq(unsigned int irq, int set) +{ + struct ciabase *base; + unsigned char mask; + + if (irq >= IRQ_AMIGA_CIAB) + mask = (1 << (irq - IRQ_AMIGA_CIAB)); + else + mask = (1 << (irq - IRQ_AMIGA_CIAA)); + mask |= (set) ? CIA_ICR_SETCLR : 0; + + CIA_SET_BASE_ADJUST_IRQ(base, irq); + + return cia_set_irq_private(base, mask); +} + +unsigned char cia_get_irq_mask(unsigned int irq) +{ + struct ciabase *base; + + CIA_SET_BASE_ADJUST_IRQ(base, irq); + + return base->cia->icr; +} + +/* + * Enable or disable CIA interrupts, return old interrupt mask, + * interrupts will only be enabled if a handler exists + */ + +static unsigned char cia_able_irq_private(struct ciabase *base, + unsigned char mask) +{ + u_char old, tmp; + int i; + + old = base->icr_mask; + base->icr_data |= base->cia->icr; + base->cia->icr = mask; + if (mask & CIA_ICR_SETCLR) + base->icr_mask |= mask; + else + base->icr_mask &= ~mask; + base->icr_mask &= CIA_ICR_ALL; + for (i = 0, tmp = 1; i < CIA_IRQS; i++, tmp <<= 1) { + if ((tmp & base->icr_mask) && !base->irq_list[i].handler) { + base->icr_mask &= ~tmp; + base->cia->icr = tmp; + } + } + if (base->icr_data & base->icr_mask) + custom.intreq = IF_SETCLR | base->int_mask; + return old; +} + +unsigned char cia_able_irq(unsigned int irq, int enable) +{ + struct ciabase *base; + unsigned char mask; + + if (irq >= IRQ_AMIGA_CIAB) + mask = (1 << (irq - IRQ_AMIGA_CIAB)); + else + mask = (1 << (irq - IRQ_AMIGA_CIAA)); + mask |= (enable) ? CIA_ICR_SETCLR : 0; + + CIA_SET_BASE_ADJUST_IRQ(base, irq); + + return cia_able_irq_private(base, mask); +} + +int cia_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + u_char mask; + struct ciabase *base; + + CIA_SET_BASE_ADJUST_IRQ(base, irq); + + base->irq_list[irq].handler = handler; + base->irq_list[irq].flags = flags; + base->irq_list[irq].dev_id = dev_id; + base->irq_list[irq].devname = devname; + + /* enable the interrupt */ + mask = 1 << irq; + cia_set_irq_private(base, mask); + cia_able_irq_private(base, CIA_ICR_SETCLR | mask); + return 0; +} + +void cia_free_irq(unsigned int irq, void *dev_id) +{ + struct ciabase *base; + + CIA_SET_BASE_ADJUST_IRQ(base, irq); + + if (base->irq_list[irq].dev_id != dev_id) + printk("%s: removing probably wrong IRQ %i from %s\n", + __FUNCTION__, base->cia_irq + irq, + base->irq_list[irq].devname); + + base->irq_list[irq].handler = NULL; + base->irq_list[irq].flags = 0; + + cia_able_irq_private(base, 1 << irq); +} + +static void cia_handler(int irq, void *dev_id, struct pt_regs *fp) +{ + struct ciabase *base = (struct ciabase *)dev_id; + int mach_irq, i; + unsigned char ints; + + mach_irq = base->cia_irq; + irq = SYS_IRQS + mach_irq; + ints = cia_set_irq_private(base, CIA_ICR_ALL); + custom.intreq = base->int_mask; + for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) { + if (ints & 1) { + kstat.irqs[0][irq]++; + base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp); + } + ints >>= 1; + } + amiga_do_irq_list(base->server_irq, fp, &base->server); +} + +void __init cia_init_IRQ(struct ciabase *base) +{ + int i; + + /* init isr handlers */ + for (i = 0; i < CIA_IRQS; i++) { + base->irq_list[i].handler = NULL; + base->irq_list[i].flags = 0; + } + + /* clear any pending interrupt and turn off all interrupts */ + cia_set_irq_private(base, CIA_ICR_ALL); + cia_able_irq_private(base, CIA_ICR_ALL); + + /* install CIA handler */ + request_irq(base->handler_irq, cia_handler, 0, base->name, base); + + custom.intena = IF_SETCLR | base->int_mask; +} + +int cia_get_irq_list(struct ciabase *base, char *buf) +{ + int i, j, len = 0; + + j = base->cia_irq; + for (i = 0; i < CIA_IRQS; i++) { + len += sprintf(buf+len, "cia %2d: %10d ", j + i, + kstat.irqs[0][SYS_IRQS + j + i]); + len += sprintf(buf+len, " "); + len += sprintf(buf+len, "%s\n", base->irq_list[i].devname); + } + return len; +} diff --git a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c index 47b8f64ea6f1..c66e2359bf82 100644 --- a/arch/ppc/amiga/config.c +++ b/arch/ppc/amiga/config.c @@ -461,6 +461,8 @@ static void __init amiga_sched_init(void (*timer_routine)(int, void *, #define TICK_SIZE 10000 +extern unsigned char cia_get_irq_mask(unsigned int irq); + /* This is always executed with interrupts disabled. */ static unsigned long amiga_gettimeoffset (void) { @@ -481,7 +483,7 @@ static unsigned long amiga_gettimeoffset (void) if (ticks > jiffy_ticks / 2) /* check for pending interrupt */ - if (cia_set_irq(&ciab_base, 0) & CIA_ICR_TA) + if (cia_get_irq_mask(IRQ_AMIGA_CIAB) & CIA_ICR_TA) offset = 10000; ticks = jiffy_ticks - ticks; diff --git a/arch/ppc/common_defconfig b/arch/ppc/common_defconfig index 0bcbf06aa5cd..8b232d723cc7 100644 --- a/arch/ppc/common_defconfig +++ b/arch/ppc/common_defconfig @@ -1,13 +1,19 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + # # Platform support # CONFIG_PPC=y CONFIG_6xx=y # CONFIG_PPC64 is not set +# CONFIG_82xx is not set # CONFIG_8xx is not set # CONFIG_PMAC is not set # CONFIG_PREP is not set @@ -15,17 +21,19 @@ CONFIG_6xx=y CONFIG_ALL_PPC=y # CONFIG_GEMINI is not set # CONFIG_APUS is not set -# CONFIG_MBX is not set # CONFIG_SMP is not set CONFIG_6xx=y # -# General setup +# Loadable module support # -CONFIG_EXPERIMENTAL=y CONFIG_MODULES=y CONFIG_MODVERSIONS=y CONFIG_KMOD=y + +# +# General setup +# CONFIG_PCI=y CONFIG_NET=y CONFIG_SYSCTL=y @@ -34,6 +42,11 @@ CONFIG_SYSVIPC=y CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_BINFMT_MISC is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set # CONFIG_PARPORT is not set CONFIG_VGA_CONSOLE=y CONFIG_FB=y @@ -41,7 +54,6 @@ CONFIG_FB_COMPAT_XPMAC=y CONFIG_PMAC_PBOOK=y CONFIG_MAC_FLOPPY=y CONFIG_MAC_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set CONFIG_ADB=y CONFIG_ADB_CUDA=y CONFIG_ADB_MACIO=y @@ -57,21 +69,27 @@ CONFIG_BOOTX_TEXT=y # Plug and Play configuration # # CONFIG_PNP is not set -# CONFIG_ISAPNP is not set # # Block devices # CONFIG_BLK_DEV_FD=y CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set CONFIG_BLK_DEV_IDECD=y -# CONFIG_IDECD_SLOTS is not set # CONFIG_BLK_DEV_IDETAPE is not set CONFIG_BLK_DEV_IDEFLOPPY=y # CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set # CONFIG_BLK_DEV_IDEPCI is not set @@ -83,12 +101,17 @@ CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set # CONFIG_BLK_CPQ_DA is not set + +# +# Additional Block Devices +# CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y # CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_DAC960 is not set CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set CONFIG_BLK_DEV_IDE_MODES=y @@ -115,10 +138,18 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_MROUTE is not set CONFIG_IP_ALIAS=y CONFIG_SYN_COOKIES=y + +# +# (it is safe to leave these untouched) +# CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set + +# +# +# # CONFIG_IPX is not set CONFIG_ATALK=m # CONFIG_DECNET is not set @@ -140,11 +171,19 @@ CONFIG_ATALK=m # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y # CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -179,6 +218,7 @@ CONFIG_AIC7XXX_RESET_DELAY=15 # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SIM710 is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_NCR53C8XX is not set CONFIG_SCSI_SYM53C8XX=y @@ -226,17 +266,22 @@ CONFIG_NETDEVICES=y CONFIG_NET_ETHERNET=y CONFIG_MACE=y CONFIG_BMAC=y +# CONFIG_NCR885E is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_YELLOWFIN is not set # CONFIG_RTL8139 is not set # CONFIG_SIS900 is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set +# CONFIG_DM9102 is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y CONFIG_PCNET32=y +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_ACENIC is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -252,7 +297,6 @@ CONFIG_DE4X5=y # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set # CONFIG_ZNET is not set -# CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set @@ -265,13 +309,18 @@ CONFIG_DE4X5=y # CONFIG_IPDDP is not set CONFIG_PPP=y # CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set # CONFIG_PPP_DEFLATE is not set # CONFIG_PPP_BSDCOMP is not set # CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# # CONFIG_NET_RADIO is not set # -# Token ring devices +# Token Ring driver support # # CONFIG_TR is not set # CONFIG_NET_FC is not set @@ -281,17 +330,7 @@ CONFIG_PPP=y # # Wan interfaces # -# CONFIG_HOSTESS_SV11 is not set -# CONFIG_COSA is not set -# CONFIG_SEALEVEL_4021 is not set -# CONFIG_DLCI is not set - -# -# PCMCIA network devices -# -# CONFIG_PCMCIA_PCNET is not set -# CONFIG_PCMCIA_3C589 is not set -# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_WAN is not set # # Amateur Radio support @@ -311,6 +350,11 @@ CONFIG_PPP=y # # Console drivers # + +# +# Frame-buffer support +# +CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set @@ -328,6 +372,8 @@ CONFIG_FB_MATROX_MYSTIQUE=y CONFIG_FB_MATROX_G100=y # CONFIG_FB_MATROX_MULTIHEAD is not set CONFIG_FB_ATY=y +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_3DFX is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -362,7 +408,7 @@ CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set -# CONFIG_ADB_MOUSE is not set +# CONFIG_ADBMOUSE is not set CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set @@ -403,11 +449,11 @@ CONFIG_NVRAM=y CONFIG_AUTOFS_FS=y # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set +CONFIG_HFS_FS=y +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y # CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set +CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set @@ -420,6 +466,7 @@ CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y +# CONFIG_BFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set @@ -446,7 +493,39 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set # CONFIG_SUN_PARTITION is not set -# CONFIG_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set # # Sound @@ -463,27 +542,27 @@ CONFIG_DMASOUND=y # CONFIG_SOUND_MSNDPIN is not set CONFIG_SOUND_OSS=y # CONFIG_SOUND_DMAP is not set -# CONFIG_SOUND_PAS is not set -# CONFIG_SOUND_SB is not set -# CONFIG_SOUND_ADLIB is not set -# CONFIG_SOUND_GUS is not set -# CONFIG_SOUND_MPU401 is not set -# CONFIG_SOUND_PSS is not set -# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +CONFIG_SOUND_CS4232=m # CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_VMIDI is not set # CONFIG_SOUND_TRIX is not set -# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set # CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_SB is not set # CONFIG_SOUND_WAVEFRONT is not set -CONFIG_SOUND_CS4232=m -# CONFIG_SOUND_OPL3SA2 is not set # CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_SGALAXY is not set -# CONFIG_SOUND_AD1816 is not set -# CONFIG_SOUND_OPL3SA1 is not set -# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_YM3812 is not set -# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set # CONFIG_SOUND_UART6850 is not set # diff --git a/arch/ppc/config.in b/arch/ppc/config.in index c26497adf021..c21f6feca701 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -44,6 +44,10 @@ else fi bool 'Symmetric multi-processing support' CONFIG_SMP +if [ "$CONFIG_6xx" != "y" ];then + bool 'AltiVec Support' CONFIG_ALTIVEC +fi + if [ "$CONFIG_ALL_PPC" != "y" ];then define_bool CONFIG_MACH_SPECIFIC y fi @@ -85,6 +89,9 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT # only elf supported, a.out is not -- Cort +if [ "$CONFIG_PROC_FS" = "y" ]; then + define_bool CONFIG_KCORE_ELF y +fi define_bool CONFIG_BINFMT_ELF y define_bool CONFIG_KERNEL_ELF y tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig index cebd77dfe68a..04967cd9da76 100644 --- a/arch/ppc/defconfig +++ b/arch/ppc/defconfig @@ -43,6 +43,8 @@ CONFIG_NET=y CONFIG_SYSCTL=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_KCORE_AOUT is not set +CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_BINFMT_MISC is not set diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 2f190db09424..3677276b537d 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -60,15 +60,12 @@ ifdef CONFIG_MBX O_OBJS += i8259.o endif else -ifeq ($(CONFIG_APUS),y) -O_OBJS += apus_setup.o prom.o open_pic.o -else -ifneq ($(CONFIG_8xx),y) O_OBJS += chrp_setup.o chrp_pci.o chrp_time.o \ pmac_time.o pmac_pci.o pmac_setup.o \ prom.o open_pic.o feature.o \ i8259.o pmac_pic.o indirect_pci.o \ gemini_pci.o gemini_prom.o gemini_setup.o + ifeq ($(CONFIG_NVRAM),y) O_OBJS += pmac_support.o endif @@ -83,7 +80,8 @@ endif ifeq ($(CONFIG_PMAC), y) endif -endif +ifdef CONFIG_APUS +O_OBJS += apus_setup.o endif endif diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c index 353482a18170..a7b057fa164e 100644 --- a/arch/ppc/kernel/apus_setup.c +++ b/arch/ppc/kernel/apus_setup.c @@ -32,7 +32,10 @@ #include #define ide_init_hwif_ports m68k_ide_init_hwif_ports #define ide_default_irq m68k_ide_default_irq +#undef ide_request_irq #define ide_request_irq m68k_ide_request_irq +#undef ide_free_irq +#define ide_free_irq m68k_ide_free_irq #define ide_default_io_base m68k_ide_default_io_base #define ide_check_region m68k_ide_check_region #define ide_request_region m68k_ide_request_region @@ -40,7 +43,6 @@ #define ide_fix_driveid m68k_ide_fix_driveid #define ide_init_default_hwifs m68k_ide_init_default_hwifs #define select_t m68k_select_t -#define ide_free_irq m68k_ide_free_irq //#include #include #undef ide_free_irq @@ -59,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +74,8 @@ unsigned long m68k_machtype __apusdata; char debug_device[6] __apusdata = ""; +extern void amiga_init_IRQ(void); + void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata; /* machine dependent keyboard functions */ int (*mach_keyb_init) (void) __initdata; @@ -162,57 +167,6 @@ int apus_set_rtc_time(unsigned long nowtime) #endif } -__apus -int apus_request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, - void *dev_id) -{ -#ifdef CONFIG_APUS - extern int amiga_request_irq(unsigned int irq, - void (*handler)(int, void *, - struct pt_regs *), - unsigned long flags, - const char *devname, - void *dev_id); - - return amiga_request_irq (irq, handler, flags, devname, dev_id); -#else - return 0; -#endif -} - -__apus -void apus_free_irq(unsigned int irq, void *dev_id) -{ -#ifdef CONFIG_APUS - extern void amiga_free_irq(unsigned int irq, void *dev_id); - - amiga_free_irq (irq, dev_id); -#endif -} - -__apus -void apus_process_int(unsigned long vec, void *fp) -{ -#ifdef CONFIG_APUS - extern void process_int(unsigned long vec, struct pt_regs *fp); - - process_int (vec, (struct pt_regs*)fp); -#endif -} - -__apus -int apus_get_irq_list(char *buf) -{ -#ifdef CONFIG_APUS - extern int m68k_get_irq_list (char*); - - return m68k_get_irq_list (buf); -#else - return 0; -#endif -} /* Here some functions we don't support, but which the other ports reference */ @@ -297,6 +251,7 @@ void __init apus_setup_arch(void) config_amiga(); +#if 0 /* Enable for logging - also include logging.o in Makefile rule */ { #define LOG_SIZE 4096 void* base; @@ -310,6 +265,7 @@ void __init apus_setup_arch(void) LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE); } #endif +#endif } __apus @@ -760,67 +716,122 @@ void apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, m68k_ide_init_hwif_ports(hw, data_port, ctrl_port, irq); } #endif -/****************************************************** from irq.c */ -#define VEC_SPUR (24) +/****************************************************** IRQ stuff */ -void -apus_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake) +__apus +int apus_get_irq_list(char *buf) { - int old_level, new_level; +#ifdef CONFIG_APUS + extern int amiga_get_irq_list(char *buf); + + return amiga_get_irq_list (buf); +#else + return 0; +#endif +} - new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK; - - if (0 != new_level && 7 != new_level) { - old_level = ~(regs->mq) & IPLEMU_IPLMASK; +/* IPL must be between 0 and 7 */ +__apus +static inline void apus_set_IPL(int ipl) +{ + APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | ((~ipl) & IPLEMU_IPLMASK)); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); +} - apus_process_int (VEC_SPUR+new_level, regs); - - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); - APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET - | (~(old_level) & IPLEMU_IPLMASK))); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); - } +__apus +static inline unsigned long apus_get_IPL(void) +{ + unsigned short __f; + APUS_READ(APUS_IPL_EMU, __f); + return ((~__f) & IPLEMU_IPLMASK); } __apus -static void apus_save_flags(unsigned long* flags) +static inline unsigned long apus_get_prev_IPL(void) { unsigned short __f; APUS_READ(APUS_IPL_EMU, __f); - return ((~__f) & IPLEMU_IPLMASK) << 8; + return ((~__f >> 3) & IPLEMU_IPLMASK); +} + + +__apus +static void apus_save_flags(unsigned long* flags) +{ + *flags = apus_get_IPL(); } __apus static void apus_restore_flags(unsigned long flags) { - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET - | (~(flags >> 8) & IPLEMU_IPLMASK)); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); + apus_set_IPL(flags); } __apus static void apus_sti(void) { - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_IPLMASK); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); + apus_set_IPL(0); } __apus static void apus_cli(void) { - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); + apus_set_IPL(7); +} + + +#ifdef CONFIG_APUS +void free_irq(unsigned int irq, void *dev_id) +{ + extern void amiga_free_irq(unsigned int irq, void *dev_id); + + amiga_free_irq (irq, dev_id); +} + +int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char * devname, void *dev_id) +{ + extern int amiga_request_irq(unsigned int irq, + void (*handler)(int, void *, + struct pt_regs *), + unsigned long flags, + const char *devname, + void *dev_id); + + return amiga_request_irq (irq, handler, irqflags, devname, dev_id); +} +#endif + +__apus +int apus_get_irq(struct pt_regs* regs) +{ +#ifdef CONFIG_APUS + int level = apus_get_IPL(); + unsigned short ints = custom.intreqr & custom.intenar; + + if (0 == level) + return -1; + if (7 == level) + return -2; + + return level; +#else + return 0; +#endif +} + + +__apus +void apus_post_irq(int level) +{ + /* Restore IPL to the previous value */ + apus_set_IPL(apus_get_IPL()); } + + /****************************************************** keyboard */ __apus static int apus_kbd_setkeycode(unsigned int scancode, unsigned int keycode) @@ -859,36 +870,54 @@ static void apus_kbd_init_hw(void) #ifdef CONFIG_APUS extern int amiga_keyb_init(void); -printk("**** " __FUNCTION__ "\n"); amiga_keyb_init(); #endif } /****************************************************** init */ -extern void amiga_disable_irq(unsigned int irq); -extern void amiga_enable_irq(unsigned int irq); -extern void m68k_init_IRQ (void); - -struct hw_interrupt_type amiga_irq_ctl = { - " Amiga ", - NULL, - NULL, - NULL, - amiga_enable_irq, - amiga_disable_irq, - NULL, - 0 + +/* The number of spurious interrupts */ +volatile unsigned int num_spurious; + +#define NUM_IRQ_NODES 100 +static irq_node_t nodes[NUM_IRQ_NODES]; + +extern void (*amiga_default_handler[AUTO_IRQS])(int, void *, struct pt_regs *); + +static const char *default_names[SYS_IRQS] = { + "spurious int", "int1 handler", "int2 handler", "int3 handler", + "int4 handler", "int5 handler", "int6 handler", "int7 handler" }; +irq_node_t *new_irq_node(void) +{ + irq_node_t *node; + short i; + + for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) + if (!node->handler) + return node; + + printk ("new_irq_node: out of nodes\n"); + return NULL; +} + __init void apus_init_IRQ(void) { int i; - for (i = 0; i < NR_IRQS; i++) - irq_desc[i].ctl = &amiga_irq_ctl; - m68k_init_IRQ (); + for (i = 0; i < NUM_IRQ_NODES; i++) + nodes[i].handler = NULL; + + for (i = 0; i < AUTO_IRQS; i++) { + if (amiga_default_handler[i] != NULL) + sys_request_irq(i, amiga_default_handler[i], + 0, default_names[i], NULL); + } + + amiga_init_IRQ(); int_control.int_sti = apus_sti; int_control.int_cli = apus_cli; @@ -924,7 +953,8 @@ void apus_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.get_cpuinfo = apus_get_cpuinfo; ppc_md.irq_cannonicalize = NULL; ppc_md.init_IRQ = apus_init_IRQ; - ppc_md.do_IRQ = apus_do_IRQ; + ppc_md.get_irq = apus_get_irq; + ppc_md.post_irq = apus_post_irq; #ifdef CONFIG_HEARTBEAT ppc_md.heartbeat = apus_heartbeat; ppc_md.heartbeat_count = 1; @@ -969,3 +999,9 @@ void apus_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_ide_md.io_base = _IO_BASE; #endif } + + +/*************************************************** coexistence */ +void __init adbdev_init(void) +{ +} diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index b3b07a003b83..bcf656404fba 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -365,10 +365,10 @@ InstructionAccess: /* External interrupt */ . = 0x500; HardwareInterrupt: -#ifndef CONFIG_APUS EXCEPTION_PROLOG; addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL +#ifndef CONFIG_APUS li r4,0 bl transfer_to_handler .globl do_IRQ_intercept @@ -376,9 +376,6 @@ do_IRQ_intercept: .long do_IRQ; .long ret_from_except #else - EXCEPTION_PROLOG; - addi r3,r1,STACK_FRAME_OVERHEAD - li r20,MSR_KERNEL bl apus_interrupt_entry #endif /* CONFIG_APUS */ @@ -447,7 +444,7 @@ SystemCall: STD_EXCEPTION(0xd00, SingleStep, SingleStepException) STD_EXCEPTION(0xe00, Trap_0e, UnknownException) - STD_EXCEPTION(0xf00, Trap_0f, UnknownException) + STD_EXCEPTION(0xf20, AltiVec, AltiVecUnavailable) /* * Handle TLB miss for instruction on 603/603e. @@ -806,6 +803,59 @@ KernelFP: 86: .string "floating point used in kernel (task=%p, pc=%x)\n" .align 4 +/* + * Take away the altivec regs. + * + * For now, ignore the vrsave regs and save them all + * -- Cort + */ + .globl giveup_altivec +giveup_altivec: +#ifdef CONFIG_ALTIVEC + /* check for altivec */ + mfspr r4,PVR + srwi r4,r4,16 + cmpi 0,r4,12 + bnelr + + /* save altivec regs */ + addi r4,r3,THREAD+THREAD_VRSAVE + mfspr r5,256 /* vrsave */ + stw r5,0(r4) + + /* get regs for the task */ + addi r4,r3,THREAD+PT_REGS + /* turn off the altivec bit in the tasks regs */ + lwz r5,_MSR(r4) + lis r6,MSR_VEC@h + andi. r5,r5,r6 + stw r5,_MSR(r4) +#endif /* CONFIG_ALTIVEC */ + blr + + .globl load_up_altivec +load_up_altivec: +#ifdef CONFIG_ALTIVEC + /* check for altivec */ + mfspr r4,PVR + srwi r4,r4,16 + cmpi 0,r4,12 + bnelr + + /* restore altivec regs */ + addi r4,r3,THREAD+THREAD_VRSAVE + lwz r5,0(r4) + mtspr 256,r5 /* vrsave */ + + /* get regs for the task */ + addi r4,r3,THREAD+PT_REGS + /* turn on the altivec bit in the tasks regs */ + lwz r5,_MSR(r4) + oris r5,r5,MSR_VEC@h + stw r5,_MSR(r4) +#endif /* CONFIG_ALTIVEC */ + blr + /* * giveup_fpu(tsk) * Disable FP for the task given as the argument, @@ -957,14 +1007,69 @@ fix_mem_constants: isync /* No speculative loading until now */ blr + +apus_interrupt_entry: + /* This is horrible, but there's no way around it. Enable the + * data cache so the IRQ hardware register can be accessed + * without cache intervention. Then disable interrupts and get + * the current emulated m68k IPL value. + */ + + mfmsr 20 + xori r20,r20,MSR_DR + sync + mtmsr r20 + sync - /* On APUS the first 0x4000 bytes of the kernel will be mapped - * at a different physical address than the rest. For this - * reason, the exception code cannot use relative branches to - * access the code below. - */ - . = 0x4000 -#endif + lis r4,APUS_IPL_EMU@h + + li r20,(IPLEMU_SETRESET|IPLEMU_DISABLEINT) + stb r20,APUS_IPL_EMU@l(r4) + eieio + + lbz r3,APUS_IPL_EMU@l(r4) + + li r2,IPLEMU_IPLMASK + rlwinm. r20,r3,32-3,29,31 + bne 2f + mr r20,r2 /* lvl7! Need to reset state machine. */ + b 3f +2: cmp 0,r20,r2 + beq 1f +3: eieio + stb r2,APUS_IPL_EMU@l(r4) + ori r20,r20,IPLEMU_SETRESET + eieio + stb r20,APUS_IPL_EMU@l(r4) +1: eieio + li r20,IPLEMU_DISABLEINT + stb r20,APUS_IPL_EMU@l(r4) + + /* At this point we could do some magic to avoid the overhead + * of calling the C interrupt handler in case of a spurious + * interrupt. Could not get a simple hack to work though. + */ + + mfmsr r20 + xori r20,r20,MSR_DR + sync + mtmsr r20 + sync + + stw r3,(_CCR+4)(r21); + + addi r3,r1,STACK_FRAME_OVERHEAD; + li r20,MSR_KERNEL; + bl transfer_to_handler; + .long do_IRQ; + .long ret_from_except + +/*********************************************************************** + * Please note that on APUS the exception handlers are located at the + * physical address 0xfff0000. For this reason, the exception handlers + * cannot use relative branches to access the code below. + ***********************************************************************/ +#endif /* CONFIG_APUS */ #ifdef CONFIG_SMP .globl __secondary_hold @@ -1165,6 +1270,19 @@ start_here: bl identify_machine bl MMU_init +#ifdef CONFIG_APUS + /* Copy exception code to exception vector base on APUS. */ + lis r4,KERNELBASE@h +#ifdef CONFIG_APUS_FAST_EXCEPT + lis r3,0xfff0 /* Copy to 0xfff00000 */ +#else + lis r3,0 /* Copy to 0x00000000 */ +#endif + li r5,0x4000 /* # bytes of memory to copy */ + li r6,0 + bl copy_and_flush /* copy the first 0x4000 bytes */ +#endif /* CONFIG_APUS */ + /* * Go back to running unmapped so we can load up new values * for SDR1 (hash table pointer) and the segment registers @@ -1283,3 +1401,4 @@ clear_bats: mtspr IBAT3L,r20 blr + diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index d851569d5c1b..4427e801f7d8 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -67,14 +67,6 @@ void disable_irq(unsigned int irq_nr); volatile unsigned char *chrp_int_ack_special; -#ifdef CONFIG_APUS -/* Rename a few functions. Requires the CONFIG_APUS protection. */ -#define request_irq nop_ppc_request_irq -#define free_irq nop_ppc_free_irq -#define get_irq_list nop_get_irq_list -#define VEC_SPUR (24) -#endif - #define MAXCOUNT 10000000 #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) @@ -94,8 +86,9 @@ atomic_t ppc_n_lost_interrupts; * this needs to be removed. * -- Cort */ -static char cache_bitmask = 0; -static struct irqaction malloc_cache[8]; +#define IRQ_KMALLOC_ENTRIES 8 +static int cache_bitmask = 0; +static struct irqaction malloc_cache[IRQ_KMALLOC_ENTRIES]; extern int mem_init_done; void *irq_kmalloc(size_t size, int pri) @@ -103,7 +96,7 @@ void *irq_kmalloc(size_t size, int pri) unsigned int i; if ( mem_init_done ) return kmalloc(size,pri); - for ( i = 0; i <= 3 ; i++ ) + for ( i = 0; i < IRQ_KMALLOC_ENTRIES ; i++ ) if ( ! ( cache_bitmask & (1<> 8) & 0xff, addr & 0xff)) @@ -67,6 +68,7 @@ unsigned char nvram_read_byte(int addr) while (!req.complete) pmu_poll(); return req.reply[1]; +#endif case 1: return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]; case 2: @@ -82,6 +84,7 @@ void nvram_write_byte(unsigned char val, int addr) struct adb_request req; switch (nvram_naddrs) { +#ifdef CONFIG_ADB_PMU case -1: if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM, (addr >> 8) & 0xff, addr & 0xff, val)) @@ -89,6 +92,7 @@ void nvram_write_byte(unsigned char val, int addr) while (!req.complete) pmu_poll(); break; +#endif case 1: nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val; break; diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 399b99052ba9..4bd37196ed43 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -209,8 +209,10 @@ EXPORT_SYMBOL(adb_request); EXPORT_SYMBOL(adb_register); EXPORT_SYMBOL(cuda_request); EXPORT_SYMBOL(cuda_poll); +#ifdef CONFIG_ADB_PMU EXPORT_SYMBOL(pmu_request); EXPORT_SYMBOL(pmu_poll); +#endif /* CONFIG_ADB_PMU */ #endif /* CONFIG_ADB */ #ifdef CONFIG_PMAC_PBOOK EXPORT_SYMBOL(pmu_register_sleep_notifier); diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index ed3b39bc18ad..6907fc9c26ba 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -45,6 +45,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs); extern unsigned long _get_SP(void); struct task_struct *last_task_used_math = NULL; +struct task_struct *last_task_used_altivec = NULL; static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; @@ -60,6 +61,7 @@ struct task_struct *current_set[NR_CPUS] = {&init_task, }; #undef SHOW_TASK_SWITCHES 1 #undef CHECK_STACK 1 +#if defined(CHECK_STACK) unsigned long kernel_stack_top(struct task_struct *tsk) { @@ -72,28 +74,6 @@ task_top(struct task_struct *tsk) return ((unsigned long)tsk) + sizeof(struct task_struct); } -int -dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs) -{ - if (regs->msr & MSR_FP) - giveup_fpu(current); - memcpy(fpregs, ¤t->thread.fpr[0], sizeof(*fpregs)); - return 1; -} - -void -enable_kernel_fp(void) -{ -#ifdef __SMP__ - if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) - giveup_fpu(current); - else - giveup_fpu(NULL); /* just enables FP for kernel */ -#else - giveup_fpu(last_task_used_math); -#endif /* __SMP__ */ -} - /* check to make sure the kernel stack is healthy */ int check_stack(struct task_struct *tsk) { @@ -156,6 +136,29 @@ int check_stack(struct task_struct *tsk) } return(ret); } +#endif /* defined(CHECK_STACK) */ + +int +dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs) +{ + if (regs->msr & MSR_FP) + giveup_fpu(current); + memcpy(fpregs, ¤t->thread.fpr[0], sizeof(*fpregs)); + return 1; +} + +void +enable_kernel_fp(void) +{ +#ifdef __SMP__ + if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) + giveup_fpu(current); + else + giveup_fpu(NULL); /* just enables FP for kernel */ +#else + giveup_fpu(last_task_used_math); +#endif /* __SMP__ */ +} void _switch_to(struct task_struct *prev, struct task_struct *new, @@ -187,8 +190,20 @@ _switch_to(struct task_struct *prev, struct task_struct *new, * every switch, just a save. * -- Cort */ - if (prev->thread.regs && (prev->thread.regs->msr & MSR_FP)) + if ( prev->thread.regs && (prev->thread.regs->msr & MSR_FP) ) giveup_fpu(prev); + /* + * If the previous thread 1) has some altivec regs it wants saved + * (has bits in vrsave set) and 2) used altivec in the last quantum + * (thus changing altivec regs) then save them. + * + * On SMP we always save/restore altivec regs just to avoid the + * complexity of changing processors. + * -- Cort + */ + if ( (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) && + prev->thread.vrsave ) + giveup_altivec(prev); if ( (new->last_processor != NO_PROC_ID) && (new->last_processor != new->processor) && new->mm ) flush_tlb_mm(new->mm); @@ -215,7 +230,8 @@ void show_regs(struct pt_regs * regs) printk("TASK = %p[%d] '%s' ", current, current->pid, current->comm); printk("Last syscall: %ld ", current->thread.last_syscall); - printk("\nlast math %p", last_task_used_math); + printk("\nlast math %p last altivec %p", last_task_used_math, + last_task_used_altivec); #ifdef __SMP__ printk(" CPU: %d last CPU: %d", current->processor,current->last_processor); @@ -245,12 +261,16 @@ void exit_thread(void) { if (last_task_used_math == current) last_task_used_math = NULL; + if (last_task_used_altivec == current) + last_task_used_altivec = NULL; } void flush_thread(void) { if (last_task_used_math == current) last_task_used_math = NULL; + if (last_task_used_altivec == current) + last_task_used_altivec = NULL; } void @@ -307,11 +327,18 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, */ if (regs->msr & MSR_FP) giveup_fpu(current); - memcpy(&p->thread.fpr, ¤t->thread.fpr, sizeof(p->thread.fpr)); p->thread.fpscr = current->thread.fpscr; childregs->msr &= ~MSR_FP; + if (regs->msr & MSR_VEC) + giveup_altivec(current); + if ( p->thread.vrsave ) + memcpy(&p->thread.vrf, ¤t->thread.vrf, sizeof(p->thread.vrf)); + p->thread.vscr = current->thread.vscr; + p->thread.vrsave = current->thread.vrsave; + childregs->msr &= ~MSR_VEC; + #ifdef __SMP__ p->last_processor = NO_PROC_ID; #endif /* __SMP__ */ @@ -369,6 +396,8 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) shove_aux_table(sp); if (last_task_used_math == current) last_task_used_math = 0; + if (last_task_used_altivec == current) + last_task_used_altivec = 0; current->thread.fpscr = 0; } diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 8863a9940ced..ce9a230ac419 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -245,6 +245,9 @@ int get_cpuinfo(char *buffer) case 10: len += sprintf(len+buffer, "604ev5 (MachV)\n"); break; + case 12: + len += sprintf(len+buffer, "7400 (G4)\n"); + break; case 50: len += sprintf(len+buffer, "821\n"); case 80: diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 99a9c2bce097..92e9ffc27d0b 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -128,6 +128,42 @@ MachineCheckException(struct pt_regs *regs) _exception(SIGSEGV, regs); } +void +AltiVecUnavailable(struct pt_regs *regs) +{ + /* + * This should be changed so we don't take a trap if coming + * back when last_task_used_altivec == current. We should also + * allow the kernel to use the altivec regs on UP to store tasks + * regs during switch + * -- Cort + */ + if ( regs->msr & MSR_VEC ) + { + show_regs(regs); + panic("AltiVec trap with Altivec enabled!\n"); + } + + if ( !user_mode(regs) ) + { + show_regs(regs); + panic("Kernel Used Altivec with MSR_VEC off!\n"); + } +#ifdef __SMP__ + printk("User Mode altivec trap should not happen in SMP!\n"); +#else + if ( last_task_used_altivec != current ) + { + if ( last_task_used_altivec ) + giveup_altivec(current); + load_up_altivec(current); + last_task_used_altivec = current; + } + /* enable altivec for the task on return */ + regs->msr |= MSR_VEC; +#endif +} + void UnknownException(struct pt_regs *regs) { diff --git a/arch/ppc/lib/checksum.S b/arch/ppc/lib/checksum.S index 66a2e3aae6e3..5eb60537c266 100644 --- a/arch/ppc/lib/checksum.S +++ b/arch/ppc/lib/checksum.S @@ -24,6 +24,8 @@ * len is in words and is always >= 5. */ _GLOBAL(ip_fast_csum) + cmpi 0,r4,0 + beq 10f lwz r0,0(r3) lwzu r5,4(r3) addi r4,r4,-2 @@ -38,6 +40,8 @@ _GLOBAL(ip_fast_csum) not r3,r3 srwi r3,r3,16 blr +10: li r3,0 + blr /* * Compute checksum of TCP or UDP pseudo-header: diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 34a32fe8c4df..f3efef24ac43 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -1381,7 +1381,7 @@ unsigned long __init *gemini_find_end_of_memory(void) set_phys_avail(); return ret; } -#endif /* defined(CONFIG_GEMINI) || defined(CONFIG_ALL_PPC) */ +#endif /* defined(CONFIG_GEMINI) */ #ifdef CONFIG_APUS #define HARDWARE_MAPPED_SIZE (512*1024) diff --git a/arch/sh/config.in b/arch/sh/config.in index 516dc37484ef..6471e7aa8c0a 100644 --- a/arch/sh/config.in +++ b/arch/sh/config.in @@ -11,9 +11,22 @@ endmenu mainmenu_option next_comment comment 'Processor type and features' -choice 'Processor family' \ - "SH-3 CONFIG_CPU_SH3 \ - SH-4 CONFIG_CPU_SH4" SH-3 +choice 'Processor type' \ + "SH7708 CONFIG_CPU_SUBTYPE_SH7708 \ + SH7709 CONFIG_CPU_SUBTYPE_SH7709 \ + SH7750 CONFIG_CPU_SUBTYPE_SH7750" SH7708 +if [ "$CONFIG_CPU_SUBTYPE_SH7708" = "y" ]; then + define_bool CONFIG_CPU_SH3 y + define_bool CONFIG_CPU_SH4 n +fi +if [ "$CONFIG_CPU_SUBTYPE_SH7709" = "y" ]; then + define_bool CONFIG_CPU_SH3 y + define_bool CONFIG_CPU_SH4 n +fi +if [ "$CONFIG_CPU_SUBTYPE_SH7750" = "y" ]; then + define_bool CONFIG_CPU_SH3 n + define_bool CONFIG_CPU_SH4 y +fi bool 'Little Endian' CONFIG_LITTLE_ENDIAN hex 'Physical memory start address' CONFIG_MEMORY_START 08000000 bool 'Use SH CPU internal real time clock' CONFIG_SH_CPU_RTC @@ -35,6 +48,12 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL +if [ "$CONFIG_PROC_FS" = "y" ]; then + choice 'Kernel core (/proc/kcore) format' \ + "ELF CONFIG_KCORE_ELF \ + A.OUT CONFIG_KCORE_AOUT" ELF +fi + tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC endmenu @@ -61,6 +80,10 @@ endmenu if [ "$CONFIG_NET" = "y" ]; then source net/Config.in + mainmenu_option next_comment + comment 'Network device drivers' + source drivers/net/Config.in + endmenu fi mainmenu_option next_comment diff --git a/arch/sh/defconfig b/arch/sh/defconfig index dcf006a15e07..6a65ad411776 100644 --- a/arch/sh/defconfig +++ b/arch/sh/defconfig @@ -10,10 +10,14 @@ # # Processor type and features # -# CONFIG_CPU_SH3 is not set -CONFIG_CPU_SH4=y +CONFIG_CPU_SUBTYPE_SH7708=y +# CONFIG_CPU_SUBTYPE_SH7709 is not set +# CONFIG_CPU_SUBTYPE_SH7750 is not set +CONFIG_CPU_SH3=y +# CONFIG_CPU_SH4 is not set CONFIG_LITTLE_ENDIAN=y -CONFIG_MEMORY_START=08000000 +CONFIG_MEMORY_START=0c000000 +CONFIG_SH_CPU_RTC=y # # Loadable module support @@ -27,6 +31,8 @@ CONFIG_MEMORY_START=08000000 # CONFIG_SYSVIPC is not set # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_SYSCTL is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set @@ -35,8 +41,8 @@ CONFIG_BINFMT_ELF=y # # CONFIG_SERIAL is not set CONFIG_SERIAL_CONSOLE=y -# CONFIG_SH_SCI_SERIAL is not set -CONFIG_SH_SCIF_SERIAL=y +CONFIG_SH_SCI_SERIAL=y +# CONFIG_SH_SCIF_SERIAL is not set # # Floppy, IDE, and other block devices @@ -59,9 +65,6 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_UDF_FS is not set diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S index a49c2476cb60..a3e5a918c2e6 100644 --- a/arch/sh/kernel/entry.S +++ b/arch/sh/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.16 1999/10/21 14:00:27 gniibe Exp $ +/* $Id: entry.S,v 1.19 1999/10/31 13:19:35 gniibe Exp gniibe $ * * linux/arch/sh/entry.S * @@ -61,7 +61,11 @@ ENOSYS = 38 #if defined(__sh3__) TRA = 0xffffffd0 EXPEVT = 0xffffffd4 +#ifdef CONFIG_CPU_SUBTYPE_SH7709 +INTEVT = 0xa4000000 ! INTEVTE2(0xa4000000) +#else INTEVT = 0xffffffd8 +#endif MMU_TEA = 0xfffffffc ! TLB Exception Address Register #elif defined(__SH4__) TRA = 0xff000020 @@ -251,6 +255,11 @@ system_call: mov.l 1f,r2 mov.l @r2,r8 ! + ! DEBUG DEBUG + ! mov.l led,r1 + ! mov r0,r2 + ! mov.b r2,@r1 + ! #ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB mov #0x20,r1 extu.b r1,r1 @@ -320,6 +329,7 @@ system_call: 3: .long SYMBOL_NAME(syscall_trace) 2: .long 0xefffffff ! BL=0 1: .long TRA +led: .long 0xa8000000 ! For my board -- gN .section .fixup,"ax" fixup_syscall_argerr: @@ -571,6 +581,37 @@ ENTRY(interrupt_table) .long SYMBOL_NAME(do_IRQ) ! rovi .long SYMBOL_NAME(do_IRQ) .long SYMBOL_NAME(do_IRQ) +#if defined(CONFIG_CPU_SUBTYPE_SH7709) + .long SYMBOL_NAME(do_IRQ) ! 32 IRQ irq0 + .long SYMBOL_NAME(do_IRQ) ! 33 irq1 + .long SYMBOL_NAME(do_IRQ) ! 34 irq2 + .long SYMBOL_NAME(do_IRQ) ! 35 irq3 + .long SYMBOL_NAME(do_IRQ) ! 36 irq4 + .long SYMBOL_NAME(do_IRQ) ! 37 irq5 + .long SYMBOL_NAME(do_IRQ) ! 38 + .long SYMBOL_NAME(do_IRQ) ! 39 + .long SYMBOL_NAME(do_IRQ) ! 40 PINT pint0-7 + .long SYMBOL_NAME(do_IRQ) ! 41 pint8-15 + .long SYMBOL_NAME(do_IRQ) ! 42 + .long SYMBOL_NAME(do_IRQ) ! 43 + .long SYMBOL_NAME(do_IRQ) ! 44 + .long SYMBOL_NAME(do_IRQ) ! 45 + .long SYMBOL_NAME(do_IRQ) ! 46 + .long SYMBOL_NAME(do_IRQ) ! 47 + .long SYMBOL_NAME(do_IRQ) ! 48 DMAC dei0 + .long SYMBOL_NAME(do_IRQ) ! 49 dei1 + .long SYMBOL_NAME(do_IRQ) ! 50 dei2 + .long SYMBOL_NAME(do_IRQ) ! 51 dei3 + .long SYMBOL_NAME(do_IRQ) ! 52 IrDA eri1 + .long SYMBOL_NAME(do_IRQ) ! 53 rxi1 + .long SYMBOL_NAME(do_IRQ) ! 54 bri1 + .long SYMBOL_NAME(do_IRQ) ! 55 txi1 + .long SYMBOL_NAME(do_IRQ) ! 56 SCIF eri2 + .long SYMBOL_NAME(do_IRQ) ! 57 rxi2 + .long SYMBOL_NAME(do_IRQ) ! 58 bri2 + .long SYMBOL_NAME(do_IRQ) ! 59 txi2 + .long SYMBOL_NAME(do_IRQ) ! 60 ADC adi +#elif defined(__SH4__) .long SYMBOL_NAME(do_IRQ) ! Hitachi UDI .long SYMBOL_NAME(do_IRQ) ! GPIO .long SYMBOL_NAME(do_IRQ) ! DMAC dmte0 @@ -589,6 +630,7 @@ ENTRY(interrupt_table) .long error .long error ! fpu .long error ! fpu +#endif ENTRY(sys_call_table) .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/ @@ -608,7 +650,7 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_mknod) .long SYMBOL_NAME(sys_chmod) /* 15 */ .long SYMBOL_NAME(sys_lchown) - .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ .long SYMBOL_NAME(sys_stat) .long SYMBOL_NAME(sys_lseek) .long SYMBOL_NAME(sys_getpid) /* 20 */ @@ -622,8 +664,8 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_fstat) .long SYMBOL_NAME(sys_pause) .long SYMBOL_NAME(sys_utime) /* 30 */ - .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */ - .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */ .long SYMBOL_NAME(sys_access) .long SYMBOL_NAME(sys_nice) .long SYMBOL_NAME(sys_ni_syscall) /* 35 */ /* old ftime syscall holder */ @@ -635,7 +677,7 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_dup) .long SYMBOL_NAME(sys_pipe) .long SYMBOL_NAME(sys_times) - .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */ .long SYMBOL_NAME(sys_brk) /* 45 */ .long SYMBOL_NAME(sys_setgid) .long SYMBOL_NAME(sys_getgid) @@ -644,12 +686,12 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_getegid) /* 50 */ .long SYMBOL_NAME(sys_acct) .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */ - .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */ .long SYMBOL_NAME(sys_ioctl) .long SYMBOL_NAME(sys_fcntl) /* 55 */ - .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */ .long SYMBOL_NAME(sys_setpgid) - .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */ .long SYMBOL_NAME(sys_ni_syscall) /* sys_olduname */ .long SYMBOL_NAME(sys_umask) /* 60 */ .long SYMBOL_NAME(sys_chroot) @@ -689,7 +731,7 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_fchown) /* 95 */ .long SYMBOL_NAME(sys_getpriority) .long SYMBOL_NAME(sys_setpriority) - .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ .long SYMBOL_NAME(sys_statfs) .long SYMBOL_NAME(sys_fstatfs) /* 100 */ .long SYMBOL_NAME(sys_ni_syscall) /* ioperm */ diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S index eda9e347d1c2..f6378927ee9f 100644 --- a/arch/sh/kernel/head.S +++ b/arch/sh/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.6 1999/10/05 12:34:16 gniibe Exp $ +/* $Id: head.S,v 1.7 1999/10/27 09:41:42 gniibe Exp gniibe $ * * arch/sh/kernel/head.S * @@ -18,9 +18,8 @@ ENTRY(empty_zero_page) .long 0 /* RAMDISK_FLAGS */ .long 0x0200 /* ORIG_ROOT_DEV */ .long 1 /* LOADER_TYPE */ - .long 0x88400000 /* INITRD_START */ - .long 0x00400000 /* INITRD_SIZE */ - .long 0x89000000 /* MEMORY_END */ + .long 0x00360000 /* INITRD_START */ + .long 0x000a0000 /* INITRD_SIZE */ .long 0 .text diff --git a/arch/sh/kernel/irq_onchip.c b/arch/sh/kernel/irq_onchip.c index d743c947116a..f03456bfad19 100644 --- a/arch/sh/kernel/irq_onchip.c +++ b/arch/sh/kernel/irq_onchip.c @@ -1,8 +1,8 @@ -/* $Id: irq_onchip.c,v 1.4 1999/10/19 12:22:05 gniibe Exp $ +/* $Id: irq_onchip.c,v 1.5 1999/10/28 02:18:33 gniibe Exp $ * * linux/arch/sh/kernel/irq_onchip.c * - * Copyright (C) 1999 Niibe Yutaka + * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi * * Interrupt handling for on-chip supporting modules (TMU, RTC, etc.). * @@ -135,6 +135,109 @@ static void end_onChip_irq(unsigned int irq) enable_onChip_irq(irq); } + +#ifdef CONFIG_CPU_SUBTYPE_SH7709 +/* + * SH7707/SH7709/SH7709A/SH7729 Extended on-chip I/O + */ + +#define INTC_IRR0 0xa4000004UL +#define INTC_IPRC 0xa4000016UL + +#define IRQ0_IRQ 32 +#define IRQ1_IRQ 33 +#define IRQ2_IRQ 34 +#define IRQ3_IRQ 35 +#define IRQ4_IRQ 36 +#define IRQ5_IRQ 37 + +#define IRQ0_IRP_OFFSET 32 +#define IRQ1_IRP_OFFSET 36 +#define IRQ2_IRP_OFFSET 40 +#define IRQ3_IRP_OFFSET 44 +#define IRQ4_IRP_OFFSET 48 +#define IRQ5_IRP_OFFSET 52 + +#define IRQ0_PRIORITY 1 +#define IRQ1_PRIORITY 1 +#define IRQ2_PRIORITY 1 +#define IRQ3_PRIORITY 1 +#define IRQ4_PRIORITY 1 +#define IRQ5_PRIORITY 1 + +static void enable_onChip2_irq(unsigned int irq); +void disable_onChip2_irq(unsigned int irq); + +/* shutdown is same as "disable" */ +#define shutdown_onChip2_irq disable_onChip2_irq + +static void mask_and_ack_onChip2(unsigned int); +static void end_onChip2_irq(unsigned int irq); + +static unsigned int startup_onChip2_irq(unsigned int irq) +{ + enable_onChip2_irq(irq); + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type onChip2_irq_type = { + "SH7709 Extended On-Chip Supporting Module", + startup_onChip2_irq, + shutdown_onChip2_irq, + enable_onChip2_irq, + disable_onChip2_irq, + mask_and_ack_onChip2, + end_onChip2_irq +}; + +void disable_onChip2_irq(unsigned int irq) +{ + unsigned long val, flags; + /* Set priority in IPR to 0 */ + int offset = ipr_data[irq-TIMER_IRQ].offset - 32; + unsigned long intc_ipr_address = INTC_IPRC + (offset/16*INTC_SIZE); + unsigned short mask = 0xffff ^ (0xf << (offset%16)); + + save_and_cli(flags); + val = ctrl_inw(intc_ipr_address); + val &= mask; + ctrl_outw(val, intc_ipr_address); + restore_flags(flags); +} + +static void enable_onChip2_irq(unsigned int irq) +{ + unsigned long val, flags; + /* Set priority in IPR back to original value */ + int offset = ipr_data[irq-TIMER_IRQ].offset - 32; + int priority = ipr_data[irq-TIMER_IRQ].priority; + unsigned long intc_ipr_address = INTC_IPRC + (offset/16*INTC_SIZE); + unsigned short value = (priority << (offset%16)); + + save_and_cli(flags); + val = ctrl_inw(intc_ipr_address); + val |= value; + ctrl_outw(val, intc_ipr_address); + restore_flags(flags); +} + +static void mask_and_ack_onChip2(unsigned int irq) +{ + disable_onChip2_irq(irq); + if (IRQ0_IRQ <= irq && irq <= IRQ5_IRQ) { + /* Clear external interrupt request */ + int a = ctrl_inb(INTC_IRR0); + a &= ~(1 << (irq - IRQ0_IRQ)); + ctrl_outb(a, INTC_IRR0); + } +} + +static void end_onChip2_irq(unsigned int irq) +{ + enable_onChip2_irq(irq); +} +#endif /* CONFIG_CPU_SUBTYPE_SH7709 */ + void __init init_IRQ(void) { int i; @@ -142,4 +245,25 @@ void __init init_IRQ(void) for (i = TIMER_IRQ; i < NR_IRQS; i++) { irq_desc[i].handler = &onChip_irq_type; } + +#ifdef CONFIG_CPU_SUBTYPE_SH7709 + for (i = IRQ0_IRQ; i < NR_IRQS; i++) { + irq_desc[i].handler = &onChip2_irq_type; + } + + /* + * Enable external irq(INTC IRQ mode). + * You should set corresponding bits of PFC to "00" + * to enable these interrupts. + */ + set_ipr_data(IRQ0_IRQ, IRQ0_IRP_OFFSET, IRQ0_PRIORITY); + set_ipr_data(IRQ1_IRQ, IRQ1_IRP_OFFSET, IRQ1_PRIORITY); + set_ipr_data(IRQ2_IRQ, IRQ2_IRP_OFFSET, IRQ2_PRIORITY); + set_ipr_data(IRQ3_IRQ, IRQ3_IRP_OFFSET, IRQ3_PRIORITY); + set_ipr_data(IRQ4_IRQ, IRQ4_IRP_OFFSET, IRQ4_PRIORITY); + set_ipr_data(IRQ5_IRQ, IRQ5_IRP_OFFSET, IRQ5_PRIORITY); + + ctrl_inb(INTC_IRR0); + ctrl_outb(0, INTC_IRR0); +#endif /* CONFIG_CPU_SUBTYPE_SH7709 */ } diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 9d90c0133181..5d2a5696ca94 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.7 1999/09/23 00:05:41 gniibe Exp $ +/* $Id: process.c,v 1.8 1999/10/31 13:19:16 gniibe Exp $ * * linux/arch/sh/kernel/process.c * @@ -249,8 +249,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, p->thread.sp = (unsigned long) childregs; p->thread.pc = (unsigned long) ret_from_fork; - if (p->mm) - p->mm->context = NO_CONTEXT; return 0; } diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 7e6990823c66..f97e66585f1a 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.7 1999/10/23 01:34:50 gniibe Exp $ +/* $Id: setup.c,v 1.7 1999/10/23 01:34:50 gniibe Exp gniibe $ * * linux/arch/sh/kernel/setup.c * @@ -135,9 +135,9 @@ static inline void parse_mem_cmdline (char ** cmdline_p) memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; - memory_start = (unsigned long)__va(0)+__MEMORY_START; + memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START; /* Default is 4Mbyte. */ - memory_end = (unsigned long)__va(0x00400000)+__MEMORY_START; + memory_end = (unsigned long)PAGE_OFFSET+0x00400000+__MEMORY_START; for (;;) { /* @@ -214,7 +214,7 @@ void __init setup_arch(char **cmdline_p) /* * Initialize the boot-time allocator (with low memory only): */ - bootmap_size = init_bootmem(start_pfn, max_low_pfn); + bootmap_size = init_bootmem(start_pfn, max_low_pfn, __MEMORY_START); /* * FIXME: what about high memory? @@ -259,16 +259,18 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_BLK_DEV_INITRD if (LOADER_TYPE) { - initrd_start = INITRD_START ? INITRD_START : 0; - initrd_end = initrd_start+INITRD_SIZE; - if (initrd_end > memory_end) { + if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { + reserve_bootmem(INITRD_START, INITRD_SIZE); + initrd_start = + INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0; + initrd_end = initrd_start+INITRD_SIZE; + } else { printk("initrd extends beyond end of memory " "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_end,memory_end); + INITRD_START + INITRD_SIZE, + max_low_pfn << PAGE_SHIFT); initrd_start = 0; - } else - reserve_bootmem(__pa(initrd_start)-__MEMORY_START, - INITRD_SIZE); + } } #endif diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index a485f10a388c..8f480f764ee3 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c @@ -44,9 +44,8 @@ asmlinkage int sys_pipe(unsigned long * fildes) } asmlinkage unsigned long -sys_mmap(int fd, unsigned long addr, - unsigned long len, unsigned long prot, - unsigned long flags, unsigned long off) +sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, + unsigned long flags, int fd, unsigned long off) { int error = -EFAULT; struct file *file = NULL; diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index 7824f1a836a0..49a765f83bac 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.3 1999/10/17 10:30:15 gniibe Exp $ +/* $Id: time.c,v 1.7 1999/11/06 02:00:37 gniibe Exp $ * * linux/arch/sh/kernel/time.c * @@ -43,7 +43,10 @@ #define TMU0_TCNT 0xfffffe98 /* Long access */ #define TMU0_TCR 0xfffffe9c /* Word access */ -#define INTERVAL 37500 /* (1000000*CLOCK_MHZ/HZ/2) ??? */ +#define INTERVAL 37500 /* (1000000*CLOCK_MHZ/HZ/2) ??? for CqREEK */ +#if 0 /* Takeshi's board */ +#define INTERVAL 83333 +#endif /* SH-3 RTC */ #define R64CNT 0xfffffec0 @@ -195,6 +198,13 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg { do_timer(regs); +#ifdef TAKESHI + { + unsigned long what_is_this=0xa4000124; + + ctrl_outb(ctrl_inb(what_is_this)+1,what_is_this); + } +#endif #if 0 if (!user_mode(regs)) sh_do_profile(regs->pc); diff --git a/arch/sh/lib/checksum.S b/arch/sh/lib/checksum.S index 8eb4c05ef89d..3471084b9e2a 100644 --- a/arch/sh/lib/checksum.S +++ b/arch/sh/lib/checksum.S @@ -1,4 +1,4 @@ -/* $Id: checksum.S,v 1.1 1999/09/18 16:56:53 gniibe Exp $ +/* $Id: checksum.S,v 1.2 1999/10/29 13:06:55 gniibe Exp $ * * INET An implementation of the TCP/IP protocol suite for the LINUX * operating system. INET is implemented using the BSD Socket @@ -192,7 +192,7 @@ DST( mov.w r0,@r5 ) mov #-5,r0 shld r0,r6 tst r6,r6 - bf/s 2f + bt/s 2f clrt SRC(1: mov.l @r4+,r0 ) SRC( mov.l @r4+,r1 ) diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 595e413457a6..7f3610a3b22b 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.3 1999/09/21 23:09:53 gniibe Exp $ +/* $Id: fault.c,v 1.5 1999/10/31 13:17:31 gniibe Exp $ * * linux/arch/sh/mm/fault.c * Copyright (C) 1999 Niibe Yutaka @@ -81,6 +81,34 @@ bad_area: return 0; } +static void handle_vmalloc_fault(struct task_struct *tsk, unsigned long address) +{ + pgd_t *dir; + pmd_t *pmd; + pte_t *pte; + pte_t entry; + + dir = pgd_offset_k(address); + pmd = pmd_offset(dir, address); + if (pmd_none(*pmd)) { + printk(KERN_ERR "vmalloced area %08lx bad\n", address); + return; + } + if (pmd_bad(*pmd)) { + pmd_ERROR(*pmd); + pmd_clear(pmd); + return; + } + pte = pte_offset(pmd, address); + entry = *pte; + if (pte_none(entry) || !pte_present(entry) || !pte_write(entry)) { + printk(KERN_ERR "vmalloced area %08lx bad\n", address); + return; + } + + update_mmu_cache(NULL, address, entry); +} + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -98,6 +126,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, tsk = current; mm = tsk->mm; + if (address >= VMALLOC_START && address < VMALLOC_END) { + handle_vmalloc_fault(tsk, address); + return; + } + /* * If we're in an interrupt or have no user * context, we must not take the fault.. @@ -222,23 +255,13 @@ void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) { unsigned long flags; - unsigned long asid; unsigned long pteval; - asid = get_asid(); - - address &= PAGE_MASK; -#if 0/*defined(__SH4__)*//* SH-4 has separate I/D caches: XXX really needed? */ - if ((vma->vm_flags & VM_EXEC) != 0) -/* && - ((pte_val(pte) & (_PAGE_PRESENT | _PAGE_DIRTY)) == - (_PAGE_PRESENT | _PAGE_DIRTY))) */ - flush_icache_range(address,address+PAGE_SIZE); -#endif save_and_cli(flags); - /* Set PTEH register */ - ctrl_outl((address|asid), MMU_PTEH); - + /* + * We don't need to set PTEH register. + * It's automatically set by the hardware. + */ pteval = pte_val(pte); pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ pteval |= _PAGE_FLAGS_HARDWARE_DEFAULT; /* add default flags */ @@ -246,18 +269,31 @@ void update_mmu_cache(struct vm_area_struct * vma, ctrl_outl(pteval, MMU_PTEL); /* Load the TLB */ - asm volatile ("ldtlb" : /* no output */ : /* no input */ - : "memory"); + asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); restore_flags(flags); } -static __inline__ void __flush_tlb_page(unsigned long asid, unsigned long page) +static void __flush_tlb_page(struct mm_struct *mm, unsigned long page) { - unsigned long addr, data; + unsigned long addr, data, asid; + unsigned long saved_asid = MMU_NO_ASID; + + if (mm->context == NO_CONTEXT) + return; + + asid = mm->context & MMU_CONTEXT_ASID_MASK; + if (mm != current->mm) { + saved_asid = get_asid(); + /* + * We need to set ASID of the target entry to flush, + * because TLB is indexed by (ASID and PAGE). + */ + set_asid(asid); + } #if defined(__sh3__) - addr = MMU_TLB_ADDRESS_ARRAY | (page & 0x1F000) | MMU_PAGE_ASSOC_BIT; - data = page | asid; /* VALID bit is off */ + addr = MMU_TLB_ADDRESS_ARRAY |(page & 0x1F000)| MMU_PAGE_ASSOC_BIT; + data = (page & 0xfffe0000) | asid; /* VALID bit is off */ ctrl_outl(data, addr); #elif defined(__SH4__) int i; @@ -276,19 +312,18 @@ static __inline__ void __flush_tlb_page(unsigned long asid, unsigned long page) } } #endif + if (saved_asid != MMU_NO_ASID) + set_asid(saved_asid); } void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { - unsigned long asid; - - if (vma->vm_mm->context != NO_CONTEXT) { - unsigned long flags; + unsigned long flags; + if (vma->vm_mm) { page &= PAGE_MASK; - asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK; save_and_cli(flags); - __flush_tlb_page (asid, page); + __flush_tlb_page(vma->vm_mm, page); restore_flags(flags); } } @@ -303,18 +338,15 @@ void flush_tlb_range(struct mm_struct *mm, unsigned long start, save_and_cli(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */ - get_new_mmu_context(mm); + mm->context = NO_CONTEXT; if (mm == current->mm) - set_asid(mm->context & MMU_CONTEXT_ASID_MASK); + activate_context(mm); } else { - unsigned long asid; - - asid = mm->context & MMU_CONTEXT_ASID_MASK; start &= PAGE_MASK; end += (PAGE_SIZE - 1); end &= PAGE_MASK; while (start < end) { - __flush_tlb_page (asid, start); + __flush_tlb_page(mm, start); start += PAGE_SIZE; } } @@ -325,14 +357,14 @@ void flush_tlb_range(struct mm_struct *mm, unsigned long start, void flush_tlb_mm(struct mm_struct *mm) { /* Invalidate all TLB of this process. */ - /* Instead of flush TLBs, we get new MMU context. */ + /* Instead of invalidating each TLB, we get new MMU context. */ if (mm->context != NO_CONTEXT) { unsigned long flags; save_and_cli(flags); - get_new_mmu_context(mm); + mm->context = NO_CONTEXT; if (mm == current->mm) - set_asid(mm->context & MMU_CONTEXT_ASID_MASK); + activate_context(mm); restore_flags(flags); } } diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 0be75e4a31d1..83e2f3e9ea14 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.4 1999/10/23 01:37:02 gniibe Exp $ +/* $Id: init.c,v 1.4 1999/10/23 01:37:02 gniibe Exp gniibe $ * * linux/arch/sh/mm/init.c * @@ -193,13 +193,14 @@ pgd_t swapper_pg_dir[1024]; */ void __init paging_init(void) { + int i; pgd_t * pg_dir; /* We don't need kernel mapping as hardware support that. */ pg_dir = swapper_pg_dir; - /* Unmap the original low memory mappings to detect NULL reference */ - pgd_val(pg_dir[0]) = 0; + for (i=0; i < USER_PTRS_PER_PGD*2; i++) + pgd_val(pg_dir[i]) = 0; /* Enable MMU */ ctrl_outl(MMU_CONTROL_INIT, MMUCR); diff --git a/arch/sparc/config.in b/arch/sparc/config.in index b9eec6ee2f2f..81fc41f5d8fe 100644 --- a/arch/sparc/config.in +++ b/arch/sparc/config.in @@ -63,6 +63,11 @@ bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL +if [ "$CONFIG_PROC_FS" = "y" ]; then + choice 'Kernel core (/proc/kcore) format' \ + "ELF CONFIG_KCORE_ELF \ + A.OUT CONFIG_KCORE_AOUT" ELF +fi tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index ba3db5e7f5b9..98d1431a53c1 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -78,6 +78,8 @@ CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in index e6c0b5e5ae06..86e9425975ba 100644 --- a/arch/sparc64/config.in +++ b/arch/sparc64/config.in @@ -47,6 +47,11 @@ bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL +if [ "$CONFIG_PROC_FS" = "y" ]; then + choice 'Kernel core (/proc/kcore) format' \ + "ELF CONFIG_KCORE_ELF \ + A.OUT CONFIG_KCORE_AOUT" ELF +fi bool 'Kernel support for Linux/Sparc 32bit binary compatibility' CONFIG_SPARC32_COMPAT if [ "$CONFIG_SPARC32_COMPAT" != "n" ]; then tristate ' Kernel support for 32-bit ELF binaries' CONFIG_BINFMT_ELF32 diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 10d9ccd811b0..59ab0b543e41 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -88,6 +88,8 @@ CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set CONFIG_SPARC32_COMPAT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_ELF32=y diff --git a/drivers/block/hpt34x.c b/drivers/block/hpt34x.c index 816b4b805902..adc3d41564ee 100644 --- a/drivers/block/hpt34x.c +++ b/drivers/block/hpt34x.c @@ -299,8 +299,7 @@ int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; - drive->timeout = WAIT_CMD; - ide_set_handler(drive, &ide_dma_intr); /* issue cmd to drive */ + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */ OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); return 0; case ide_dma_end: /* returns 1 on error, 0 otherwise */ diff --git a/drivers/block/icside.c b/drivers/block/icside.c index 5d007fce3c52..b8378145760a 100644 --- a/drivers/block/icside.c +++ b/drivers/block/icside.c @@ -381,8 +381,7 @@ icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive) if (drive->media != ide_disk) return 0; - drive->timeout = WAIT_CMD; - ide_set_handler(drive, &ide_dma_intr); + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index fbcab6ddb57c..e3cce8eb4984 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -659,6 +659,21 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, return 1; } +static int cdrom_timer_expiry(ide_drive_t *drive) +{ + struct request *rq = HWGROUP(drive)->rq; + struct packet_command *pc = (struct packet_command *) rq->buffer; + unsigned long wait = 0; + + printk("in expiry\n"); + /* blank and format can take an extremly long time to + * complete, if the IMMED bit was not set. + */ + if (pc->c[0] == GPCMD_BLANK || pc->c[0] == GPCMD_FORMAT_UNIT) + wait = 60*60*HZ; + + return wait; +} /* Set up the device registers for transferring a packet command on DEV, expecting to later transfer XFERLEN bytes. HANDLER is the routine @@ -692,7 +707,7 @@ static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen, (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { - ide_set_handler (drive, handler); + ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ } else { OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ @@ -702,7 +717,6 @@ static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen, return 0; } - /* Send a packet command to DRIVE described by CMD_BUF and CMD_LEN. The device registers must have already been prepared by cdrom_start_packet_command. @@ -712,11 +726,6 @@ static int cdrom_transfer_packet_command (ide_drive_t *drive, unsigned char *cmd_buf, int cmd_len, ide_handler_t *handler) { - /* don't timeout for blank and format commands. they may take - * a _very_ long time. */ - if (cmd_buf[0] == GPCMD_BLANK || cmd_buf[0] == GPCMD_FORMAT_UNIT) - drive->timeout = 0; - if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { /* Here we should have been called after receiving an interrupt from the device. DRQ should how be set. */ @@ -732,7 +741,7 @@ static int cdrom_transfer_packet_command (ide_drive_t *drive, } /* Arm the interrupt handler. */ - ide_set_handler (drive, handler); + ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry); /* Send the command to the device. */ atapi_output_bytes (drive, cmd_buf, cmd_len); @@ -957,7 +966,7 @@ static void cdrom_read_intr (ide_drive_t *drive) /* Done moving data! Wait for another interrupt. */ - ide_set_handler(drive, &cdrom_read_intr); + ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL); } /* @@ -1195,9 +1204,6 @@ static void cdrom_pc_intr (ide_drive_t *drive) struct request *rq = HWGROUP(drive)->rq; struct packet_command *pc = (struct packet_command *)rq->buffer; - /* restore timeout after blank or format command */ - drive->timeout = WAIT_CMD; - /* Check for errors. */ if (cdrom_decode_status (drive, 0, &stat)) return; @@ -1283,7 +1289,7 @@ static void cdrom_pc_intr (ide_drive_t *drive) } /* Now we wait for another interrupt. */ - ide_set_handler (drive, &cdrom_pc_intr); + ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry); } @@ -2398,7 +2404,6 @@ int ide_cdrom_setup (ide_drive_t *drive) drive->special.all = 0; drive->ready_stat = 0; - drive->timeout = WAIT_CMD; CDROM_STATE_FLAGS (drive)->media_changed = 1; CDROM_STATE_FLAGS (drive)->toc_valid = 0; @@ -2431,10 +2436,14 @@ int ide_cdrom_setup (ide_drive_t *drive) /* limit transfer size per interrupt. */ CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0; if (drive->id != NULL) { + /* a testament to the nice quality of Samsung drives... */ if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430")) CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1; else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432")) CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1; + /* the 3231 model does not support the SET_CD_SPEED command */ + else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-3231")) + cdi->mask |= CDC_SELECT_SPEED; } #if ! STANDARD_ATAPI diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c index 8fa7745b4d56..924451f5a262 100644 --- a/drivers/block/ide-disk.c +++ b/drivers/block/ide-disk.c @@ -175,7 +175,7 @@ read_next: if (i > 0) { if (msect) goto read_next; - ide_set_handler (drive, &read_intr); + ide_set_handler (drive, &read_intr, WAIT_CMD, NULL); } } @@ -206,7 +206,7 @@ static void write_intr (ide_drive_t *drive) ide_end_request(1, hwgroup); if (i > 0) { idedisk_output_data (drive, rq->buffer, SECTOR_WORDS); - ide_set_handler (drive, &write_intr); + ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); } goto out; } @@ -271,7 +271,7 @@ static void multwrite_intr (ide_drive_t *drive) if (stat & DRQ_STAT) { if (rq->nr_sectors) { ide_multwrite(drive, drive->mult_count); - ide_set_handler (drive, &multwrite_intr); + ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL); goto out; } } else { @@ -385,7 +385,7 @@ static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long bl if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive))) return; #endif /* CONFIG_BLK_DEV_IDEDMA */ - ide_set_handler(drive, &read_intr); + ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG); return; } @@ -404,10 +404,10 @@ static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long bl __cli(); /* local CPU only */ if (drive->mult_count) { HWGROUP(drive)->wrq = *rq; /* scratchpad */ - ide_set_handler (drive, &multwrite_intr); + ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL); ide_multwrite(drive, drive->mult_count); } else { - ide_set_handler (drive, &write_intr); + ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); idedisk_output_data(drive, rq->buffer, SECTOR_WORDS); } return; @@ -506,7 +506,6 @@ static void idedisk_pre_reset (ide_drive_t *drive) drive->special.all = 0; drive->special.b.set_geometry = 1; drive->special.b.recalibrate = 1; - drive->timeout = WAIT_CMD; if (OK_TO_RESET_CONTROLLER) drive->mult_count = 0; if (!drive->keep_settings) diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c index 338d51c9a951..7712b6cd658b 100644 --- a/drivers/block/ide-dma.c +++ b/drivers/block/ide-dma.c @@ -420,8 +420,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; - drive->timeout = WAIT_CMD; - ide_set_handler(drive, &ide_dma_intr);/* issue cmd to drive */ + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);/* issue cmd to drive */ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); case ide_dma_begin: /* Note that this is done *after* the cmd has diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c index 3db1c1515644..4609e77d92bc 100644 --- a/drivers/block/ide-floppy.c +++ b/drivers/block/ide-floppy.c @@ -916,7 +916,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive) if (temp > pc->buffer_size) { printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n"); idefloppy_discard_data (drive,bcount.all); - ide_set_handler (drive,&idefloppy_pc_intr); + ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL); return; } #if IDEFLOPPY_DEBUG_LOG @@ -938,7 +938,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive) pc->actually_transferred+=bcount.all; /* Update the current position */ pc->current_position+=bcount.all; - ide_set_handler (drive,&idefloppy_pc_intr); /* And set the interrupt handler again */ + ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */ } static void idefloppy_transfer_pc (ide_drive_t *drive) @@ -956,7 +956,7 @@ static void idefloppy_transfer_pc (ide_drive_t *drive) ide_do_reset (drive); return; } - ide_set_handler (drive, &idefloppy_pc_intr); /* Set the interrupt routine */ + ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* Set the interrupt routine */ atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */ } @@ -1025,7 +1025,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc) #endif /* CONFIG_BLK_DEV_IDEDMA */ if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) { - ide_set_handler (drive, &idefloppy_transfer_pc); + ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD, NULL); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ } else { OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); @@ -1519,7 +1519,6 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy) *((unsigned short *) &gcw) = drive->id->config; drive->driver_data = floppy; drive->ready_stat = 0; - drive->timeout = IDEFLOPPY_WAIT_CMD; memset (floppy, 0, sizeof (idefloppy_floppy_t)); floppy->drive = drive; floppy->pc = floppy->pc_stack; diff --git a/drivers/block/ide-pmac.c b/drivers/block/ide-pmac.c index c3e800249b02..e1eadcaa206f 100644 --- a/drivers/block/ide-pmac.c +++ b/drivers/block/ide-pmac.c @@ -363,8 +363,7 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; - drive->timeout = WAIT_CMD; - ide_set_handler(drive, &ide_dma_intr); + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA, IDE_COMMAND_REG); case ide_dma_begin: diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c index bbf222338bd6..5ea3230dcaf8 100644 --- a/drivers/block/ide-tape.c +++ b/drivers/block/ide-tape.c @@ -1833,7 +1833,7 @@ static void idetape_pc_intr (ide_drive_t *drive) if (temp > pc->buffer_size) { printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n"); idetape_discard_data (drive,bcount.all); - ide_set_handler (drive,&idetape_pc_intr); + ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL); return; } #if IDETAPE_DEBUG_LOG @@ -1855,7 +1855,7 @@ static void idetape_pc_intr (ide_drive_t *drive) pc->actually_transferred+=bcount.all; /* Update the current position */ pc->current_position+=bcount.all; - ide_set_handler (drive,&idetape_pc_intr); /* And set the interrupt handler again */ + ide_set_handler (drive,&idetape_pc_intr,IDETAPE_WAIT_CMD,NULL); /* And set the interrupt handler again */ } /* @@ -1928,7 +1928,7 @@ static void idetape_transfer_pc(ide_drive_t *drive) ide_do_reset (drive); return; } - ide_set_handler(drive, &idetape_pc_intr); /* Set the interrupt routine */ + ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* Set the interrupt routine */ atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */ } @@ -1995,7 +1995,7 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) } #endif /* CONFIG_BLK_DEV_IDEDMA */ if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { - ide_set_handler(drive, &idetape_transfer_pc); + ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL); OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); } else { OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); @@ -3579,7 +3579,6 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) spin_lock_init(&tape->spinlock); drive->driver_data = tape; drive->ready_stat = 0; /* An ATAPI device ignores DRDY */ - drive->timeout = IDETAPE_WAIT_CMD; #ifdef CONFIG_BLK_DEV_IDEPCI /* * These two ide-pci host adapters appear to need this disabled. diff --git a/drivers/block/ide.c b/drivers/block/ide.c index f0c9d58da05f..82f9a330370e 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -497,18 +497,6 @@ void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup) spin_unlock_irqrestore(&io_request_lock, flags); } -/* - * The below two are helpers used when modifying the drive timeout. - */ -static inline unsigned long set_timeout(ide_drive_t *drive, unsigned long timeout) -{ - unsigned long foo = drive->timeout; - drive->timeout = timeout; - return foo; -} - -#define restore_timeout(drive, old) (drive->timeout = old) - /* * This should get invoked any time we exit the driver to * wait for an interrupt response from a drive. handler() points @@ -516,7 +504,8 @@ static inline unsigned long set_timeout(ide_drive_t *drive, unsigned long timeou * timer is started to prevent us from waiting forever in case * something goes wrong (see the ide_timer_expiry() handler later on). */ -void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler) +void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, + unsigned int timeout, ide_expiry_t *expiry) { unsigned long flags; ide_hwgroup_t *hwgroup = HWGROUP(drive); @@ -528,12 +517,10 @@ void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler) drive->name, hwgroup->handler, handler); } #endif - hwgroup->handler = handler; - /* 0 means don't timeout */ - if (drive->timeout && !timer_pending(&hwgroup->timer)) { - hwgroup->timer.expires = jiffies + drive->timeout; - add_timer(&(hwgroup->timer)); - } + hwgroup->handler = handler; + hwgroup->expiry = expiry; + hwgroup->timer.expires = jiffies + timeout; + add_timer(&(hwgroup->timer)); spin_unlock_irqrestore(&hwgroup->spinlock, flags); } @@ -580,7 +567,6 @@ static void do_reset1 (ide_drive_t *, int); /* needed below */ static void atapi_reset_pollfunc (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); - unsigned long old_timeout; byte stat; SELECT_DRIVE(HWIF(drive),drive); @@ -590,9 +576,7 @@ static void atapi_reset_pollfunc (ide_drive_t *drive) printk("%s: ATAPI reset complete\n", drive->name); } else { if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { - old_timeout = set_timeout(drive, HZ / 20); - ide_set_handler (drive, &atapi_reset_pollfunc); - restore_timeout(drive, old_timeout); + ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL); return; /* continue polling */ } hwgroup->poll_timeout = 0; /* end of polling */ @@ -613,14 +597,11 @@ static void reset_pollfunc (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); ide_hwif_t *hwif = HWIF(drive); - unsigned long old_timeout; byte tmp; if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) { if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { - old_timeout = set_timeout(drive, HZ / 20); - ide_set_handler (drive, &reset_pollfunc); - restore_timeout(drive, old_timeout); + ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL); return; /* continue polling */ } printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp); @@ -688,7 +669,6 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) unsigned long flags; ide_hwif_t *hwif = HWIF(drive); ide_hwgroup_t *hwgroup = HWGROUP(drive); - unsigned long old_timeout; __save_flags(flags); /* local CPU only */ __cli(); /* local CPU only */ @@ -700,9 +680,7 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) udelay (20); OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - old_timeout = set_timeout(drive, HZ / 20); - ide_set_handler (drive, &atapi_reset_pollfunc); - restore_timeout(drive, old_timeout); + ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL); __restore_flags (flags); /* local CPU only */ return; } @@ -732,9 +710,7 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi) OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */ udelay(10); /* more than enough time */ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - old_timeout = set_timeout(drive, HZ / 20); - ide_set_handler (drive, &reset_pollfunc); - restore_timeout(drive, old_timeout); + ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL); /* * Some weird controller like resetting themselves to a strange @@ -934,7 +910,7 @@ void ide_error (ide_drive_t *drive, const char *msg, byte stat) */ void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) { - ide_set_handler (drive, handler); + ide_set_handler (drive, handler, WAIT_CMD, NULL); if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ OUT_BYTE(nsect,IDE_NSECTOR_REG); @@ -1425,7 +1401,9 @@ void ide_timer_expiry (unsigned long data) ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; ide_drive_t *drive; ide_handler_t *handler; + ide_expiry_t *expiry; unsigned long flags; + unsigned long wait; spin_lock_irqsave(&hwgroup->spinlock, flags); drive = hwgroup->drive; @@ -1434,9 +1412,22 @@ void ide_timer_expiry (unsigned long data) do_hwgroup_request(hwgroup); return; } + hwgroup->busy = 1; /* should already be "1" */ + + if ((expiry = hwgroup->expiry) != NULL) { + /* continue */ + if ((wait = expiry(drive)) != 0) { + /* reset timer */ + hwgroup->timer.expires = jiffies + wait; + add_timer(&(hwgroup->timer)); + spin_unlock_irqrestore(&hwgroup->spinlock, flags); + return; + } + } + hwgroup->handler = NULL; - /* polling in progress or just don't timeout */ + if (hwgroup->poll_timeout != 0) { spin_unlock_irqrestore(&hwgroup->spinlock, flags); handler(drive); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index d83f2b66a606..cace2226cd5f 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -151,12 +151,12 @@ static void figure_loop_size(struct loop_device *lo) int size; if (S_ISREG(lo->lo_dentry->d_inode->i_mode)) - size = (lo->lo_dentry->d_inode->i_size - lo->lo_offset) / BLOCK_SIZE; + size = (lo->lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS; else { kdev_t lodev = lo->lo_device; if (blk_size[MAJOR(lodev)]) size = blk_size[MAJOR(lodev)][MINOR(lodev)] - - lo->lo_offset / BLOCK_SIZE; + (lo->lo_offset >> BLOCK_SIZE_BITS); else size = MAX_DISK_SIZE; } diff --git a/drivers/block/pdc4030.c b/drivers/block/pdc4030.c index 080d353a572a..bf5465695c8d 100644 --- a/drivers/block/pdc4030.c +++ b/drivers/block/pdc4030.c @@ -162,7 +162,6 @@ int __init setup_pdc4030 (ide_hwif_t *hwif) if (!hwif) return 0; drive = &hwif->drives[0]; - drive->timeout = HZ/100; hwif2 = &ide_hwifs[hwif->index+1]; if (hwif->chipset == ide_pdc4030) /* we've already been found ! */ return 1; @@ -309,9 +308,6 @@ static void promise_read_intr (ide_drive_t *drive) unsigned int sectors_left, sectors_avail, nsect; struct request *rq; - /* reset timeout */ - drive->timeout = HZ/100; - if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { ide_error(drive, "promise_read_intr", stat); return; @@ -366,8 +362,7 @@ read_next: if (stat & DRQ_STAT) goto read_again; if (stat & BUSY_STAT) { - drive->timeout = WAIT_CMD; - ide_set_handler (drive, &promise_read_intr); + ide_set_handler (drive, &promise_read_intr, WAIT_CMD, NULL); #ifdef DEBUG_READ printk(KERN_DEBUG "%s: promise_read: waiting for" "interrupt\n", drive->name); @@ -396,7 +391,7 @@ static void promise_complete_pollfunc(ide_drive_t *drive) if (GET_STAT() & BUSY_STAT) { if (time_before(jiffies, hwgroup->poll_timeout)) { - ide_set_handler(drive, &promise_complete_pollfunc); + ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL); return; /* continue polling... */ } hwgroup->poll_timeout = 0; @@ -425,7 +420,7 @@ static void promise_write_pollfunc (ide_drive_t *drive) if (IN_BYTE(IDE_NSECTOR_REG) != 0) { if (time_before(jiffies, hwgroup->poll_timeout)) { - ide_set_handler (drive, &promise_write_pollfunc); + ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL); return; /* continue polling... */ } hwgroup->poll_timeout = 0; @@ -439,7 +434,7 @@ static void promise_write_pollfunc (ide_drive_t *drive) */ ide_multwrite(drive, 4); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler(drive, &promise_complete_pollfunc); + ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL); #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n", drive->name, GET_STAT()); @@ -472,7 +467,7 @@ static void promise_write (ide_drive_t *drive) if (rq->nr_sectors > 4) { ide_multwrite(drive, rq->nr_sectors - 4); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler (drive, &promise_write_pollfunc); + ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL); } else { /* * There are 4 or fewer sectors to transfer, do them all in one go @@ -480,7 +475,7 @@ static void promise_write (ide_drive_t *drive) */ ide_multwrite(drive, rq->nr_sectors); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - ide_set_handler(drive, &promise_complete_pollfunc); + ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL); #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, " "status = %02x\n", drive->name, GET_STAT()); @@ -523,8 +518,7 @@ void do_pdc4030_io (ide_drive_t *drive, struct request *rq) printk(KERN_DEBUG "%s: read: waiting for " "interrupt\n", drive->name); #endif - drive->timeout = WAIT_CMD; - ide_set_handler(drive, &promise_read_intr); + ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL); return; } udelay(1); diff --git a/drivers/block/trm290.c b/drivers/block/trm290.c index 5c7c8fd3c70e..1308c7bd74f3 100644 --- a/drivers/block/trm290.c +++ b/drivers/block/trm290.c @@ -192,8 +192,7 @@ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive) outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */ if (drive->media != ide_disk) return 0; - drive->timeout = WAIT_CMD; - ide_set_handler(drive, &ide_dma_intr); + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); return 0; case ide_dma_begin: diff --git a/drivers/char/README.computone b/drivers/char/README.computone index 51c3666b6748..d12a4ac29844 100644 --- a/drivers/char/README.computone +++ b/drivers/char/README.computone @@ -47,7 +47,7 @@ d) Run "make config" or "make menuconfig" or "make xconfig" e) Set address on ISA cards then: edit /usr/src/linux/drivers/char/ip2/ip2.h if needed or - edit /etc/conf.modules (or /etc/modules.conf) if needed (module). + edit /etc/modules.conf if needed (module). or both to match this setting. f) Run "make dep" g) Run "make modules" diff --git a/drivers/char/ip2/ip2.h b/drivers/char/ip2/ip2.h index 7236744b0245..4fc99c55c79e 100644 --- a/drivers/char/ip2/ip2.h +++ b/drivers/char/ip2/ip2.h @@ -70,8 +70,7 @@ * console warning. * When the driver is loaded as a module these setting can be overridden on the - * modprobe command line or on an option line in /etc/conf.modules - * or /etc/modules.conf depending on your distrubution. + * modprobe command line or on an option line in /etc/modules.conf. * If the driver is built-in the configuration must be * set here for ISA cards and address set to 1 and 2 for PCI and EISA. * @@ -92,8 +91,8 @@ /* this structure is zeroed out because the suggested method is to configure * the driver as a module, set up the parameters with an options line in - * /etc/modules.conf or /etc/conf.modules and load with modprobe, kerneld or - * kmod, the kernel module loader + * /etc/modules.conf and load with modprobe, kerneld or kmod, the kernel + * module loader */ static ip2config_t ip2config = { diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 041858997e11..6d2b5ed835b5 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -25,7 +25,7 @@ * You can find the original tools for this direct from Multitech * ftp://ftp.multitech.com/ISI-Cards/ * - * Having installed the cards the module options (/etc/conf.modules) + * Having installed the cards the module options (/etc/modules.conf) * * options isicom io=card1,card2,card3,card4 irq=card1,card2,card3,card4 * diff --git a/drivers/char/joystick/joy-amiga.c b/drivers/char/joystick/joy-amiga.c index 520f262a4f06..9180250402e7 100644 --- a/drivers/char/joystick/joy-amiga.c +++ b/drivers/char/joystick/joy-amiga.c @@ -25,7 +25,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: + * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ @@ -39,7 +39,7 @@ static struct js_port* js_am_port __initdata = NULL; -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); MODULE_PARM(js_am, "1-2i"); static int js_am[]={0,0}; diff --git a/drivers/char/joystick/joy-analog.c b/drivers/char/joystick/joy-analog.c index fdf04b212e24..7c1c9719d6a2 100644 --- a/drivers/char/joystick/joy-analog.c +++ b/drivers/char/joystick/joy-analog.c @@ -25,7 +25,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: + * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ @@ -43,7 +43,7 @@ static int js_an_port_list[] __initdata = {0x201, 0}; static struct js_port* js_an_port __initdata = NULL; -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); MODULE_PARM(js_an, "2-24i"); static int js_an[]={-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0}; diff --git a/drivers/char/joystick/joy-analog.h b/drivers/char/joystick/joy-analog.h index 06c0079a4a0d..84479fcd132a 100644 --- a/drivers/char/joystick/joy-analog.h +++ b/drivers/char/joystick/joy-analog.h @@ -26,7 +26,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: + * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ @@ -238,7 +238,7 @@ static int __init js_an_probe_devs(struct js_an_info *info, int exist, int mask0 break; default: printk(KERN_WARNING "joy-analog: Unknown joystick device detected " - "(data=%#x), contact \n", exist); + "(data=%#x), contact \n", exist); return -1; } } diff --git a/drivers/char/joystick/joy-assasin.c b/drivers/char/joystick/joy-assasin.c index 64d16d7b0071..731c6e56af41 100644 --- a/drivers/char/joystick/joy-assasin.c +++ b/drivers/char/joystick/joy-assasin.c @@ -25,7 +25,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: + * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ @@ -49,7 +49,7 @@ #define JS_AS_MODE_OEM 3 /* Panther OEM version */ #define JS_AS_MODE_PXL 4 /* Panther XL */ -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); MODULE_PARM(js_as, "2-24i"); static int js_as[]={-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0}; @@ -319,7 +319,7 @@ static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct j info = port->info; } else { printk(KERN_WARNING "joy-assasin: unknown joystick device detected " - "(io=%#x, id=%d), contact \n", io, data[0]); + "(io=%#x, id=%d), contact \n", io, data[0]); return port; } diff --git a/drivers/char/joystick/joy-gravis.c b/drivers/char/joystick/joy-gravis.c index 9185d3113d72..7416527e49c9 100644 --- a/drivers/char/joystick/joy-gravis.c +++ b/drivers/char/joystick/joy-gravis.c @@ -25,7 +25,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: + * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ diff --git a/drivers/char/joystick/joy-lightning.c b/drivers/char/joystick/joy-lightning.c index fc36c3d50c84..3b337fd9fcde 100644 --- a/drivers/char/joystick/joy-lightning.c +++ b/drivers/char/joystick/joy-lightning.c @@ -26,7 +26,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: + * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ @@ -52,7 +52,7 @@ static struct js_port* __initdata js_l4_port = NULL; -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); MODULE_PARM(js_l4, "2-24i"); static int js_l4[]={-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0}; diff --git a/drivers/char/joystick/joy-logitech.c b/drivers/char/joystick/joy-logitech.c index 2dcafbfeb43c..064ecade4bff 100644 --- a/drivers/char/joystick/joy-logitech.c +++ b/drivers/char/joystick/joy-logitech.c @@ -25,7 +25,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: + * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ @@ -318,7 +318,7 @@ static struct js_port __init *js_lt_probe(int io, struct js_port *port) return port; default: printk(KERN_WARNING "joy-logitech: unknown joystick device detected " - "(io=%#x, count=%d, data=0x%08x%08x), contact \n", + "(io=%#x, count=%d, data=0x%08x%08x), contact \n", io, i, (int)(data >> 32), (int)(data & 0xffffffff)); return port; } diff --git a/drivers/char/joystick/joy-sidewinder.c b/drivers/char/joystick/joy-sidewinder.c index 3fb0d8cef481..d097471bc5be 100644 --- a/drivers/char/joystick/joy-sidewinder.c +++ b/drivers/char/joystick/joy-sidewinder.c @@ -25,7 +25,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: + * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ @@ -422,7 +422,7 @@ static struct js_port __init *js_sw_probe(int io, struct js_port *port) return port; default: printk(KERN_WARNING "joy-sidewinder: unknown joystick device detected " - "(io=%#x, count=%d, data=0x%08x%08x), contact \n", + "(io=%#x, count=%d, data=0x%08x%08x), contact \n", io, i, (int)(data >> 32), (int)(data & 0xffffffff)); return port; } diff --git a/drivers/char/joystick/joy-thrustmaster.c b/drivers/char/joystick/joy-thrustmaster.c index 3ea71416dbb6..1e79b32810f8 100644 --- a/drivers/char/joystick/joy-thrustmaster.c +++ b/drivers/char/joystick/joy-thrustmaster.c @@ -25,7 +25,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: + * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ @@ -278,7 +278,7 @@ static struct js_port __init *js_tm_probe(int io, struct js_port *port) if (info.mode >= JS_TM_MODE_MAX || !names[info.mode]) { printk(KERN_WARNING "joy-thrustmaster: unknown device detected " - "(io=%#x, id=%d), contact \n", + "(io=%#x, id=%d), contact \n", io, info.mode); return port; } diff --git a/drivers/char/joystick/joy-turbografx.c b/drivers/char/joystick/joy-turbografx.c index fdf1aa43300f..6b30efe852b4 100644 --- a/drivers/char/joystick/joy-turbografx.c +++ b/drivers/char/joystick/joy-turbografx.c @@ -26,7 +26,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: + * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ @@ -41,7 +41,7 @@ #include -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); MODULE_PARM(js_tg, "2-8i"); MODULE_PARM(js_tg_2, "2-8i"); MODULE_PARM(js_tg_3, "2-8i"); diff --git a/drivers/char/joystick/joystick.c b/drivers/char/joystick/joystick.c index 941f1795de69..6c2abda1f6e9 100644 --- a/drivers/char/joystick/joystick.c +++ b/drivers/char/joystick/joystick.c @@ -26,7 +26,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: + * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ @@ -90,7 +90,7 @@ js_delta_func js_delta_a; * Module info. */ -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); MODULE_SUPPORTED_DEVICE("js"); /* diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index c2a7a850931f..6fece94702ea 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -30,7 +30,7 @@ extern int console_loglevel; extern struct vfsmount *vfsmntlist; /* Machine specific power off function */ -extern void (*sysrq_power_off)(void) = NULL; +void (*sysrq_power_off)(void) = NULL; /* Send a signal to all user processes */ diff --git a/drivers/net/arcnet.c b/drivers/net/arcnet.c index 906d3fab7cd1..62d8acd5b374 100644 --- a/drivers/net/arcnet.c +++ b/drivers/net/arcnet.c @@ -61,7 +61,7 @@ - Added support for promiscuous mode. v2.60 ALPHA (96/11/23) - - Added patch from Vojtech Pavlik + - Added patch from Vojtech Pavlik and Martin Mares to make the driver work with the new Linux 2.1.x memory management. I modified their patch quite a bit though; bugs are my fault. More changes should @@ -89,7 +89,7 @@ v2.50 (96/02/24) - Massively improved autoprobe routines; they now work even as a - module. Thanks to Vojtech Pavlik + module. Thanks to Vojtech Pavlik for his ideas and help in this area. - Changed printk's around quite a lot. diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index d356e39af514..e5dc04b79b31 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1,58 +1,29 @@ -/*****************************************************************************/ -/* sis900.c: A SiS 900 PCI Fast Ethernet driver for Linux. */ -/* */ -/* Silicon Integrated System Corporation */ -/* Revision: 1.05 Aug 7 1999 */ -/* */ -/*****************************************************************************/ - -/* - Modified from the driver which is originally written by Donald Becker. - - This software may be used and distributed according to the terms - of the GNU Public License (GPL), incorporated herein by reference. - Drivers based on this skeleton fall under the GPL and must retain - the authorship (implicit copyright) notice. - - The author may be reached as becker@tidalwave.net, or - Donald Becker - 312 Severn Ave. #W302 - Annapolis MD 21403 - - Support and updates [to the original skeleton] available at - http://www.tidalwave.net/~becker/pci-skeleton.html +/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. + Silicon Integrated System Corporation + Revision: 1.05 Aug 7 1999 + + Modified from the driver which is originally written by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License (GPL), incorporated herein by reference. + Drivers based on this skeleton fall under the GPL and must retain + the authorship (implicit copyright) notice. + + References: + SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support, + preliminary Rev. 1.0 Jan. 14, 1998 + SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support, + preliminary Rev. 1.0 Nov. 10, 1998 + SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution, + preliminary Rev. 1.0 Jan. 18, 1998 + http://www.sis.com.tw/support/databook.htm + + Rev 1.06 Nov. 4 1999 Ollie Lho (ollie@sis.com.tw) Second release + Rev 1.05.05 Oct. 29 1999 Ollie Lho (ollie@sis.com.tw) Single buffer Tx/Rx + Chin-Shan Li (lcs@sis.com.tw) Added AMD Am79c901 HomePNA PHY support + Rev 1.05 Aug. 7 1999 Jim Huang (cmhuang@sis.com.tw) Initial release */ -static const char *version = -"sis900.c:v1.05 8/07/99\n"; - -static int max_interrupt_work = 20; -#define sis900_debug debug -static int sis900_debug = 0; - -static int multicast_filter_limit = 128; - -#define MAX_UNITS 8 /* More are supported, limit only on options */ -static int speeds[MAX_UNITS] = {100, 100, 100, 100, 100, 100, 100, 100}; -static int full_duplex[MAX_UNITS] = {1, 1, 1, 1, 1, 1, 1, 1}; - -#define TX_BUF_SIZE 1536 -#define RX_BUF_SIZE 1536 - -#define TX_DMA_BURST 0 -#define RX_DMA_BURST 0 -#define TX_FIFO_THRESH 16 -#define TxDRNT_100 (1536>>5) -#define TxDRNT_10 16 -#define RxDRNT_100 8 -#define RxDRNT_10 8 -#define TRUE 1 -#define FALSE 0 - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (4*HZ) - #include #include #include @@ -65,1845 +36,1244 @@ static int full_duplex[MAX_UNITS] = {1, 1, 1, 1, 1, 1, 1, 1}; #include #include #include + #include #include #include /* Processor type for cache alignment. */ #include #include - -#define RUN_AT(x) (jiffies + (x)) - #include -#if LINUX_VERSION_CODE < 0x20123 -#define test_and_set_bit(val, addr) set_bit(val, addr) -#endif -#if LINUX_VERSION_CODE <= 0x20139 -#define net_device_stats enet_statistics -#else -#define NETSTATS_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS) -/* Grrrr, the PCI code changed, but did not consider CardBus... */ -#include -#define PCI_SUPPORT_VER1 -#else -#define PCI_SUPPORT_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20159 -#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE); -#else -#define dev_free_skb(skb) dev_kfree_skb(skb); -#endif - -/* The I/O extent. */ -#define SIS900_TOTAL_SIZE 0x100 +#include "sis900.h" -/* This table drives the PCI probe routines. It's mostly boilerplate in all - of the drivers, and will likely be provided by some future kernel. - Note the matching code -- the first table entry matchs all 56** cards but - second only the 1234 card. -*/ +static const char *version = +"sis900.c: v1.06 11/04/99\n"; -enum pci_flags_bit { - PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, -}; +static int max_interrupt_work = 20; +#define sis900_debug debug +static int sis900_debug = 0; -struct pci_id_info { - const char *name; - u16 vendor_id, device_id, device_id_mask, flags; - int io_size; - struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev, - long ioaddr, int irq, int chip_idx, int fnd_cnt); -}; +static int multicast_filter_limit = 128; -static struct net_device * sis900_probe1(int pci_bus, int pci_devfn, - struct net_device *dev, long ioaddr, - int irq, int chp_idx, int fnd_cnt); +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*HZ) -static struct pci_id_info pci_tbl[] = -{{ "SiS 900 PCI Fast Ethernet", - 0x1039, 0x0900, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x100, sis900_probe1}, - { "SiS 7016 PCI Fast Ethernet", - 0x1039, 0x7016, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x100, sis900_probe1}, - {0,}, /* 0 terminated list. */ +struct mac_chip_info { + const char *name; + u16 vendor_id, device_id, flags; + int io_size; + struct net_device *(*probe) (struct mac_chip_info *mac, struct pci_dev * pci_dev, + struct net_device * net_dev); +}; +static struct net_device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev, + struct net_device * net_dev); + +static struct mac_chip_info mac_chip_table[] = { + { "SiS 900 PCI Fast Ethernet", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900, + PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe}, + { "SiS 7016 PCI Fast Ethernet",PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016, + PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe}, + {0,}, /* 0 terminated list. */ }; -/* The capability table matches the chip table above. */ -enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04}; -static int sis_cap_tbl[] = { - HAS_MII_XCVR|HAS_CHIP_XCVR|HAS_LNK_CHNG, - HAS_MII_XCVR|HAS_CHIP_XCVR|HAS_LNK_CHNG, +static void sis900_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex); +static void amd79c901_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex); + +static struct mii_chip_info { + const char * name; + u16 phy_id0; + u16 phy_id1; + void (*read_mode) (struct net_device *net_dev, int phy_addr, int *speed, int *duplex); +} mii_chip_table[] = { + {"SiS 900 Internal MII PHY", 0x001d, 0x8000, sis900_read_mode}, + {"SiS 7014 Physical Layer Solution", 0x0016, 0xf830,sis900_read_mode}, + {"AMD 79C901 10BASE-T PHY", 0x0000, 0x35b9, amd79c901_read_mode}, + {"AMD 79C901 HomePNA PHY", 0x0000, 0x35c8, amd79c901_read_mode}, + {0,}, }; -/* The rest of these values should never change. */ -#define NUM_TX_DESC 16 /* Number of Tx descriptor registers. */ -#define NUM_RX_DESC 8 /* Number of Rx descriptor registers. */ - -/* Symbolic offsets to registers. */ -enum SIS900_registers { - cr=0x0, //Command Register - cfg=0x4, //Configuration Register - mear=0x8, //EEPROM Access Register - ptscr=0xc, //PCI Test Control Register - isr=0x10, //Interrupt Status Register - imr=0x14, //Interrupt Mask Register - ier=0x18, //Interrupt Enable Register - epar=0x18, //Enhanced PHY Access Register - txdp=0x20, //Transmit Descriptor Pointer Register - txcfg=0x24, //Transmit Configuration Register - rxdp=0x30, //Receive Descriptor Pointer Register - rxcfg=0x34, //Receive Configuration Register - flctrl=0x38, //Flow Control Register - rxlen=0x3c, //Receive Packet Length Register - rfcr=0x48, //Receive Filter Control Register - rfdr=0x4C, //Receive Filter Data Register - pmctrl=0xB0, //Power Management Control Register - pmer=0xB4 //Power Management Wake-up Event Register +struct mii_phy { + struct mii_phy * next; + struct mii_chip_info * chip_info; + int phy_addr; + u16 status; }; -#define RESET 0x00000100 -#define SWI 0x00000080 -#define RxRESET 0x00000020 -#define TxRESET 0x00000010 -#define RxDIS 0x00000008 -#define RxENA 0x00000004 -#define TxDIS 0x00000002 -#define TxENA 0x00000001 - -#define BISE 0x80000000 -#define EUPHCOM 0x00000100 -#define REQALG 0x00000080 -#define SB 0x00000040 -#define POW 0x00000020 -#define EXD 0x00000010 -#define PESEL 0x00000008 -#define LPM 0x00000004 -#define BEM 0x00000001 - -/* Interrupt register bits, using my own meaningful names. */ -#define WKEVT 0x10000000 -#define TxPAUSEEND 0x08000000 -#define TxPAUSE 0x04000000 -#define TxRCMP 0x02000000 -#define RxRCMP 0x01000000 -#define DPERR 0x00800000 -#define SSERR 0x00400000 -#define RMABT 0x00200000 -#define RTABT 0x00100000 -#define RxSOVR 0x00010000 -#define HIBERR 0x00008000 -#define SWINT 0x00001000 -#define MIBINT 0x00000800 -#define TxURN 0x00000400 -#define TxIDLE 0x00000200 -#define TxERR 0x00000100 -#define TxDESC 0x00000080 -#define TxOK 0x00000040 -#define RxORN 0x00000020 -#define RxIDLE 0x00000010 -#define RxEARLY 0x00000008 -#define RxERR 0x00000004 -#define RxDESC 0x00000002 -#define RxOK 0x00000001 - -#define IE 0x00000001 - -#define TxCSI 0x80000000 -#define TxHBI 0x40000000 -#define TxMLB 0x20000000 -#define TxATP 0x10000000 -#define TxIFG 0x0C000000 -#define TxMXF 0x03800000 -#define TxMXF_shift 0x23 -#define TxMXDMA 0x00700000 -#define TxMXDMA_shift 20 -#define TxRTCNT 0x000F0000 -#define TxRTCNT_shift 16 -#define TxFILLT 0x00007F00 -#define TxFILLT_shift 8 -#define TxDRNT 0x0000007F - -#define RxAEP 0x80000000 -#define RxARP 0x40000000 -#define RxATP 0x10000000 -#define RxAJAB 0x08000000 -#define RxMXF 0x03800000 -#define RxMXF_shift 23 -#define RxMXDMA 0x00700000 -#define RxMXDMA_shift 20 -#define RxDRNT 0x0000007F - -#define RFEN 0x80000000 -#define RFAAB 0x40000000 -#define RFAAM 0x20000000 -#define RFAAP 0x10000000 -#define RFPromiscuous (RFAAB|RFAAM|RFAAP) -#define RFAA_shift 28 -#define RFEP 0x00070000 -#define RFEP_shift 16 - -#define RFDAT 0x0000FFFF - -#define OWN 0x80000000 -#define MORE 0x40000000 -#define INTR 0x20000000 -#define OK 0x08000000 -#define DSIZE 0x00000FFF - -#define SUPCRC 0x10000000 -#define ABORT 0x04000000 -#define UNDERRUN 0x02000000 -#define NOCARRIER 0x01000000 -#define DEFERD 0x00800000 -#define EXCDEFER 0x00400000 -#define OWCOLL 0x00200000 -#define EXCCOLL 0x00100000 -#define COLCNT 0x000F0000 - -#define INCCRC 0x10000000 -// ABORT 0x04000000 -#define OVERRUN 0x02000000 -#define DEST 0x01800000 -#define BCAST 0x01800000 -#define MCAST 0x01000000 -#define UNIMATCH 0x00800000 -#define TOOLONG 0x00400000 -#define RUNT 0x00200000 -#define RXISERR 0x00100000 -#define CRCERR 0x00080000 -#define FAERR 0x00040000 -#define LOOPBK 0x00020000 -#define RXCOL 0x00010000 - -#define EuphLiteEEMACAddr 0x08 -#define EuphLiteEEVendorID 0x02 -#define EuphLiteEEDeviceID 0x03 -#define EuphLiteEECardTypeRev 0x0b -#define EuphLiteEEPlexusRev 0x0c -#define EuphLiteEEChecksum 0x0f - -#define RXSTS_shift 18 -#define OWN 0x80000000 -#define MORE 0x40000000 -#define INTR 0x20000000 -#define OK 0x08000000 -#define DSIZE 0x00000FFF -/* MII register offsets */ -#define MII_CONTROL 0x0000 -#define MII_STATUS 0x0001 -#define MII_PHY_ID0 0x0002 -#define MII_PHY_ID1 0x0003 -#define MII_ANAR 0x0004 -#define MII_ANLPAR 0x0005 -#define MII_ANER 0x0006 -/* MII Control register bit definitions. */ -#define MIICNTL_FDX 0x0100 -#define MIICNTL_RST_AUTO 0x0200 -#define MIICNTL_ISOLATE 0x0400 -#define MIICNTL_PWRDWN 0x0800 -#define MIICNTL_AUTO 0x1000 -#define MIICNTL_SPEED 0x2000 -#define MIICNTL_LPBK 0x4000 -#define MIICNTL_RESET 0x8000 -/* MII Status register bit significance. */ -#define MIISTAT_EXT 0x0001 -#define MIISTAT_JAB 0x0002 -#define MIISTAT_LINK 0x0004 -#define MIISTAT_CAN_AUTO 0x0008 -#define MIISTAT_FAULT 0x0010 -#define MIISTAT_AUTO_DONE 0x0020 -#define MIISTAT_CAN_T 0x0800 -#define MIISTAT_CAN_T_FDX 0x1000 -#define MIISTAT_CAN_TX 0x2000 -#define MIISTAT_CAN_TX_FDX 0x4000 -#define MIISTAT_CAN_T4 0x8000 -/* MII NWAY Register Bits ... -** valid for the ANAR (Auto-Negotiation Advertisement) and -** ANLPAR (Auto-Negotiation Link Partner) registers */ -#define MII_NWAY_NODE_SEL 0x001f -#define MII_NWAY_CSMA_CD 0x0001 -#define MII_NWAY_T 0x0020 -#define MII_NWAY_T_FDX 0x0040 -#define MII_NWAY_TX 0x0080 -#define MII_NWAY_TX_FDX 0x0100 -#define MII_NWAY_T4 0x0200 -#define MII_NWAY_RF 0x2000 -#define MII_NWAY_ACK 0x4000 -#define MII_NWAY_NP 0x8000 - -/* MII Auto-Negotiation Expansion Register Bits */ -#define MII_ANER_PDF 0x0010 -#define MII_ANER_LP_NP_ABLE 0x0008 -#define MII_ANER_NP_ABLE 0x0004 -#define MII_ANER_RX_PAGE 0x0002 -#define MII_ANER_LP_AN_ABLE 0x0001 -#define HALF_DUPLEX 1 -#define FDX_CAPABLE_DUPLEX_UNKNOWN 2 -#define FDX_CAPABLE_HALF_SELECTED 3 -#define FDX_CAPABLE_FULL_SELECTED 4 -#define HW_SPEED_UNCONFIG 0 -#define HW_SPEED_10_MBPS 10 -#define HW_SPEED_100_MBPS 100 -#define HW_SPEED_DEFAULT (HW_SPEED_10_MBPS) - -#define ACCEPT_ALL_PHYS 0x01 -#define ACCEPT_ALL_MCASTS 0x02 -#define ACCEPT_ALL_BCASTS 0x04 -#define ACCEPT_ALL_ERRORS 0x08 -#define ACCEPT_CAM_QUALIFIED 0x10 -#define MAC_LOOPBACK 0x20 -//#define FDX_CAPABLE_FULL_SELECTED 4 -#define CRC_SIZE 4 -#define MAC_HEADER_SIZE 14 - -typedef struct _EuphLiteDesc { - u32 llink; - unsigned char* buf; - u32 physAddr; - /* Hardware sees the physical address of descriptor */ - u32 plink; - u32 cmdsts; - u32 bufPhys; -} EuphLiteDesc; +typedef struct _BufferDesc { + u32 link; + u32 cmdsts; + u32 bufptr; +} BufferDesc; struct sis900_private { - char devname[8]; /* Used only for kernel debugging. */ - const char *product_name; - struct net_device *next_module; - int chip_id; - int chip_revision; - unsigned char pci_bus, pci_devfn; -#if LINUX_VERSION_CODE > 0x20139 - struct net_device_stats stats; -#else - struct enet_statistics stats; -#endif - struct timer_list timer; /* Media selection timer. */ - unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ - unsigned int cur_tx, dirty_tx, tx_flag; - - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff* tx_skbuff[NUM_TX_DESC]; - EuphLiteDesc tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ - EuphLiteDesc rx_buf[NUM_RX_DESC]; - unsigned char *rx_bufs; - unsigned char *tx_bufs; /* Tx bounce buffer region. */ - char phys[4]; /* MII device addresses. */ - int phy_idx; /* Support Max 4 PHY */ - u16 pmd_status; - unsigned int tx_full; /* The Tx queue is full. */ - int MediaSpeed; /* user force speed */ - int MediaDuplex; /* user force duplex */ - int full_duplex; /* Full/Half-duplex. */ - int speeds; /* 100/10 Mbps. */ - u16 LinkOn; - u16 LinkChange; + struct net_device *next_module; + struct net_device_stats stats; + struct pci_dev * pci_dev; + + struct mac_chip_info * mac; + struct mii_phy * mii; + unsigned int cur_phy; + + struct timer_list timer; /* Link status detection timer. */ + unsigned int cur_rx, dirty_rx; + unsigned int cur_tx, dirty_tx; + + /* The saved address of a sent/receive-in-place packet buffer */ + struct sk_buff *tx_skbuff[NUM_TX_DESC]; + struct sk_buff *rx_skbuff[NUM_RX_DESC]; + BufferDesc tx_ring[NUM_TX_DESC]; + BufferDesc rx_ring[NUM_RX_DESC]; + unsigned int tx_full; /* The Tx queue is full. */ + + int LinkOn; }; #ifdef MODULE #if LINUX_VERSION_CODE > 0x20115 MODULE_AUTHOR("Jim Huang "); MODULE_DESCRIPTION("SiS 900 PCI Fast Ethernet driver"); -MODULE_PARM(speeds, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(multicast_filter_limit, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(debug, "i"); #endif #endif -static int sis900_open(struct net_device *dev); +static int sis900_open(struct net_device *net_dev); +static int sis900_mii_probe (struct net_device * net_dev); +static void sis900_init_rxfilter (struct net_device * net_dev); static u16 read_eeprom(long ioaddr, int location); -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int val); +static u16 mdio_read(struct net_device *net_dev, int phy_id, int location); +static void mdio_write(struct net_device *net_dev, int phy_id, int location, int val); static void sis900_timer(unsigned long data); -static void sis900_tx_timeout(struct net_device *dev); -static void sis900_init_ring(struct net_device *dev); -static int sis900_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int sis900_rx(struct net_device *dev); +static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy); +static void sis900_tx_timeout(struct net_device *net_dev); +static void sis900_init_tx_ring(struct net_device *net_dev); +static void sis900_init_rx_ring(struct net_device *net_dev); +static int sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev); +static int sis900_rx(struct net_device *net_dev); +static void sis900_finish_xmit (struct net_device *net_dev); static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static int sis900_close(struct net_device *dev); -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static struct enet_statistics *sis900_get_stats(struct net_device *dev); -static void set_rx_mode(struct net_device *dev); -static void sis900_reset(struct net_device *dev); -static u16 elAutoNegotiate(struct net_device *dev, int phy_id, int *duplex, int *speed); -static void elSetCapability(struct net_device *dev, int phy_id, int duplex, int speed); -static u16 elPMDreadMode(struct net_device *dev, int phy_id, int *speed, int *duplex); -static u16 elMIIpollBit(struct net_device *dev, int phy_id, int location, u16 mask, u16 polarity, u16 *value); -static void elSetMediaType(struct net_device *dev, int speed, int duplex); +static int sis900_close(struct net_device *net_dev); +static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd); +static struct enet_statistics *sis900_get_stats(struct net_device *net_dev); +static u16 sis900_compute_hashtable_index(u8 *addr); +static void set_rx_mode(struct net_device *net_dev); +static void sis900_reset(struct net_device *net_dev); /* A list of all installed SiS900 devices, for removing the driver module. */ static struct net_device *root_sis900_dev = NULL; -/* Ideally we would detect all network cards in slot order. That would - be best done a central PCI probe dispatch, which wouldn't work - well when dynamically adding drivers. So instead we detect just the - SiS 900 cards in slot order. */ - -int sis900_probe(struct net_device *dev) +/* walk through every ethernet PCI devices to see if some of them are matched with our card list*/ +int sis900_probe (struct net_device * net_dev) { - int cards_found = 0; - int pci_index = 0; - unsigned char pci_bus, pci_device_fn; - - if ( ! pcibios_present()) - return -ENODEV; - - for (;pci_index < 0xff; pci_index++) { - u16 vendor, device, pci_command, new_command; - int chip_idx, irq; - long ioaddr; - - if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, - pci_index, - &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) { - break; - } - pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, - &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, - &device); - - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor == pci_tbl[chip_idx].vendor_id && - (device & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ - continue; - - { - struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->resource[0].start; - irq = pdev->irq; - } - - if ((pci_tbl[chip_idx].flags & PCI_USES_IO) && - check_region(ioaddr, pci_tbl[chip_idx].io_size)) - continue; - - /* Activate the card: fix for brain-damaged Win98 BIOSes. */ - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - new_command = pci_command | (pci_tbl[chip_idx].flags & 7); - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled the" - " device at %d/%d!" - "Updating PCI command %4.4x->%4.4x.\n", - pci_bus, pci_device_fn, - pci_command, new_command); - - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); - } - - dev = pci_tbl[chip_idx].probe1(pci_bus, - pci_device_fn, - dev, - ioaddr, - irq, - chip_idx, - cards_found); - - if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { - u8 pci_latency; - - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); - - if (pci_latency < 32) { - printk(KERN_NOTICE " PCI latency timer (CFLT) is " - "unreasonably low at %d. Setting to 64 clocks.\n", - pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, 64); - } - } - dev = 0; - cards_found++; - } - return cards_found ? 0 : -ENODEV; + int found = 0; + struct pci_dev * pci_dev = NULL; + + if (!pci_present()) + return -ENODEV; + + while ((pci_dev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_dev)) != NULL) { + /* pci_dev contains all ethernet devices */ + u32 pci_io_base; + struct mac_chip_info * mac; + + for (mac = mac_chip_table; mac->vendor_id; mac++) { + /* try to match our card list */ + if (pci_dev->vendor == mac->vendor_id && + pci_dev->device == mac->device_id) + break; + } + + if (mac->vendor_id == 0) + /* pci_dev does not match any of our cards */ + continue; + + /* now, pci_dev should be either 900 or 7016 */ + pci_io_base = pci_dev->resource[0].start; + if ((mac->flags & PCI_COMMAND_IO ) && + check_region(pci_io_base, mac->io_size)) + continue; + + /* setup various bits in PCI command register */ + pci_set_master(pci_dev); + + /* do the real low level jobs */ + net_dev = mac->probe(mac, pci_dev, net_dev); + + if (net_dev != NULL) { + found++; + } + net_dev = NULL; + } + return found ? 0 : -ENODEV; } -static struct net_device * sis900_probe1( int pci_bus, - int pci_devfn, - struct net_device *dev, - long ioaddr, - int irq, - int chip_idx, - int found_cnt) +static struct net_device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev, + struct net_device * net_dev) { - static int did_version = 0; /* Already printed version info. */ - struct sis900_private *tp; - u16 status; - int duplex = found_cnt < MAX_UNITS ? full_duplex[found_cnt] : 0 ; - int speed = found_cnt < MAX_UNITS ? speeds[found_cnt] : 0 ; - int phy=0, phy_idx=0, i; - - if (did_version++ == 0) - printk(KERN_INFO "%s", version); - - dev = init_etherdev(dev, 0); - - if(dev==NULL) - return NULL; - - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", - dev->name, pci_tbl[chip_idx].name, ioaddr, irq); - - if ((u16)read_eeprom(ioaddr, EuphLiteEEVendorID) != 0xffff) { - for (i = 0; i < 3; i++) - ((u16 *)(dev->dev_addr))[i] = - read_eeprom(ioaddr,i+EuphLiteEEMACAddr); - for (i = 0; i < 5; i++) - printk("%2.2x:", (u8)dev->dev_addr[i]); - printk("%2.2x.\n", dev->dev_addr[i]); - } else - printk(KERN_INFO "Error EEPROM read\n"); - - /* We do a request_region() to register /proc/ioports info. */ - request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); - - dev->base_addr = ioaddr; - dev->irq = irq; - - /* Some data structures must be quadword aligned. */ - tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA); - if(tp==NULL) - { - release_region(ioaddr, pci_tbl[chip_idx].io_size); - return NULL; - } - memset(tp, 0, sizeof(*tp)); - dev->priv = tp; - - tp->next_module = root_sis900_dev; - root_sis900_dev = dev; - - tp->chip_id = chip_idx; - tp->pci_bus = pci_bus; - tp->pci_devfn = pci_devfn; - - /* Find the connected MII xcvrs. - Doing this in open() would allow detecting external xcvrs later, but - takes too much time. */ - if (sis_cap_tbl[chip_idx] & HAS_MII_XCVR) { - for (phy = 0, phy_idx = 0; - phy < 32 && phy_idx < sizeof(tp->phys); phy++) - { - int mii_status ; - mii_status = mdio_read(dev, phy, MII_STATUS); - - if (mii_status != 0xffff && mii_status != 0x0000) { - tp->phy_idx = phy_idx; - tp->phys[phy_idx++] = phy; - tp->pmd_status=mdio_read(dev, phy, MII_STATUS); - printk(KERN_INFO "%s: MII transceiver found " - "at address %d.\n", - dev->name, phy); - break; - } - } - - if (phy_idx == 0) { - printk(KERN_INFO "%s: No MII transceivers found!\n", - dev->name); - tp->phys[0] = -1; - tp->pmd_status = 0; - } - } else { - tp->phys[0] = -1; - tp->pmd_status = 0; - } - - if ((tp->pmd_status > 0) && (phy_idx > 0)) { - if (sis900_debug > 1) { - printk(KERN_INFO "duplex=%d, speed=%d\n", - duplex, speed); - } - if (!duplex && !speed) { - // auto-config media type - // Set full capability - if (sis900_debug > 1) { - printk(KERN_INFO "Auto Config ...\n"); - } - elSetCapability(dev, tp->phys[tp->phy_idx], 1, 100); - tp->pmd_status=elAutoNegotiate(dev, - tp->phys[tp->phy_idx], - &tp->full_duplex, - &tp->speeds); - } else { - tp->MediaSpeed = speed; - tp->MediaDuplex = duplex; - elSetCapability(dev, tp->phys[tp->phy_idx], - duplex, speed); - elAutoNegotiate(dev, tp->phys[tp->phy_idx], - &tp->full_duplex, - &tp->speeds); - status = mdio_read(dev, phy, MII_ANLPAR); - if ( !(status & (MII_NWAY_T | MII_NWAY_T_FDX | - MII_NWAY_TX | MII_NWAY_TX_FDX ))) - { - u16 cmd=0; - cmd |= ( speed == 100 ? - MIICNTL_SPEED : 0 ); - cmd |= ( duplex ? MIICNTL_FDX : 0 ); - mdio_write(dev, phy, MII_CONTROL, cmd); - elSetMediaType(dev, speed==100 ? - HW_SPEED_100_MBPS : - HW_SPEED_10_MBPS, - duplex ? - FDX_CAPABLE_FULL_SELECTED: - FDX_CAPABLE_HALF_SELECTED); - elMIIpollBit(dev, phy, MII_STATUS, - MIISTAT_LINK, TRUE, &status); - } else { - status = mdio_read(dev, phy, MII_STATUS); - } - } + struct sis900_private *sis_priv; + long ioaddr = pci_dev->resource[0].start; + int irq = pci_dev->irq; + static int did_version = 0; + u16 signature; + int i; + + if (did_version++ == 0) + printk(KERN_INFO "%s", version); + + /* check to see if we have sane EEPROM */ + signature = (u16) read_eeprom(ioaddr, EEPROMSignature); + if (signature == 0xffff || signature == 0x0000) { + printk (KERN_INFO "%s: Error EERPOM read %x\n", + net_dev->name, signature); + return NULL; + } - if (tp->pmd_status & MIISTAT_LINK) - tp->LinkOn = TRUE; - else - tp->LinkOn = FALSE; + if ((net_dev = init_etherdev(net_dev, 0)) == NULL) + return NULL; - tp->LinkChange = FALSE; - - } - - if (sis900_debug > 1) { - if (tp->full_duplex == FDX_CAPABLE_FULL_SELECTED) { - printk(KERN_INFO "%s: Media type is Full Duplex.\n", - dev->name); - } else { - printk(KERN_INFO "%s: Media type is Half Duplex.\n", - dev->name); - } - if (tp->speeds == HW_SPEED_100_MBPS) { - printk(KERN_INFO "%s: Speed is 100mbps.\n", dev->name); - } else { - printk(KERN_INFO "%s: Speed is 10mbps.\n", dev->name); - } + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, mac->name, + ioaddr, irq); + + /* get MAC address from EEPROM */ + for (i = 0; i < 3; i++) + ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", (u8)net_dev->dev_addr[i]); + printk("%2.2x.\n", net_dev->dev_addr[i]); + + if ((net_dev->priv = kmalloc(sizeof(struct sis900_private), GFP_KERNEL)) == NULL) { + unregister_netdevice(net_dev); + return NULL; + } + + sis_priv = net_dev->priv; + memset(sis_priv, 0, sizeof(struct sis900_private)); + + /* We do a request_region() to register /proc/ioports info. */ + request_region(ioaddr, mac->io_size, net_dev->name); + net_dev->base_addr = ioaddr; + net_dev->irq = irq; + sis_priv->pci_dev = pci_dev; + sis_priv->mac = mac; + + /* probe for mii transciver */ + if (sis900_mii_probe(net_dev) == 0) { + unregister_netdev(net_dev); + kfree(sis_priv); + release_region(ioaddr, mac->io_size); + return NULL; } - /* The SiS900-specific entries in the device structure. */ - dev->open = &sis900_open; - dev->hard_start_xmit = &sis900_start_xmit; - dev->stop = &sis900_close; - dev->get_stats = &sis900_get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &mii_ioctl; + sis_priv->next_module = root_sis900_dev; + root_sis900_dev = net_dev; - return dev; + /* The SiS900-specific entries in the device structure. */ + net_dev->open = &sis900_open; + net_dev->hard_start_xmit = &sis900_start_xmit; + net_dev->stop = &sis900_close; + net_dev->get_stats = &sis900_get_stats; + net_dev->set_multicast_list = &set_rx_mode; + net_dev->do_ioctl = &mii_ioctl; + + return net_dev; } -/* Serial EEPROM section. */ +static int sis900_mii_probe (struct net_device * net_dev) +{ + struct sis900_private * sis_priv = (struct sis900_private *)net_dev->priv; + int phy_addr; + + sis_priv->mii = NULL; + + /* search for total of 32 possible mii phy addresses */ + for (phy_addr = 0; phy_addr < 32; phy_addr++) { + u16 mii_status; + u16 phy_id0, phy_id1; + int i; + + mii_status = mdio_read(net_dev, phy_addr, MII_STATUS); + if (mii_status == 0xffff || mii_status == 0x0000) + /* the mii is not accessable, try next one */ + continue; + + phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0); + phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1); + + /* search our mii table for the current mii */ + for (i = 0; mii_chip_table[i].phy_id1; i++) + if (phy_id0 == mii_chip_table[i].phy_id0) { + struct mii_phy * mii_phy; + + printk(KERN_INFO + "%s: %s transceiver found at address %d.\n", + net_dev->name, mii_chip_table[i].name, + phy_addr);; + if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) { + mii_phy->chip_info = mii_chip_table+i; + mii_phy->phy_addr = phy_addr; + mii_phy->status = mdio_read(net_dev, phy_addr, + MII_STATUS); + mii_phy->next = sis_priv->mii; + sis_priv->mii = mii_phy; + } + /* the current mii is on our mii_info_table, + try next address */ + break; + } + } + + if (sis_priv->mii == NULL) { + printk(KERN_INFO "%s: No MII transceivers found!\n", + net_dev->name); + return 0; + } + + /* arbitrary choose that last PHY and current PHY */ + sis_priv->cur_phy = sis_priv->mii->phy_addr; + printk(KERN_INFO "%s: Using %s as default\n", net_dev->name, + sis_priv->mii->chip_info->name); -/* EEPROM_Ctrl bits. */ -#define EECLK 0x00000004 /* EEPROM shift clock. */ -#define EECS 0x00000008 /* EEPROM chip select. */ -#define EEDO 0x00000002 /* EEPROM chip data out. */ -#define EEDI 0x00000001 /* EEPROM chip data in. */ + if (sis_priv->mii->status & MII_STAT_LINK) + sis_priv->LinkOn = TRUE; + else + sis_priv->LinkOn = FALSE; -/* Delay between EEPROM clock transitions. - No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. - */ + return 1; +} +/* Delay between EEPROM clock transitions. */ #define eeprom_delay() inl(ee_addr) -/* The EEPROM commands include the alway-set leading bit. */ -#define EEread 0x0180 -#define EEwrite 0x0140 -#define EEerase 0x01C0 -#define EEwriteEnable 0x0130 -#define EEwriteDisable 0x0100 -#define EEeraseAll 0x0120 -#define EEwriteAll 0x0110 -#define EEaddrMask 0x013F -#define EEcmdShift 16 - +/* Read Serial EEPROM through EEPROM Access Register, Note that location is + in word (16 bits) unit */ static u16 read_eeprom(long ioaddr, int location) { - int i; - u16 retval = 0; - long ee_addr = ioaddr + mear; - u32 read_cmd = location | EEread; - - outl(0, ee_addr); - eeprom_delay(); - outl(EECLK, ee_addr); - eeprom_delay(); - - /* Shift the read command bits out. */ - for (i = 8; i >= 0; i--) { - u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS; - outl(dataval, ee_addr); - eeprom_delay(); - outl(dataval | EECLK, ee_addr); - eeprom_delay(); - } - outb(EECS, ee_addr); - eeprom_delay(); - - for (i = 16; i > 0; i--) { - outl(EECS, ee_addr); - eeprom_delay(); - outl(EECS | EECLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0); - eeprom_delay(); - } - - /* Terminate the EEPROM access. */ - outl(0, ee_addr); - eeprom_delay(); - outl(EECLK, ee_addr); - return (retval); + int i; + u16 retval = 0; + long ee_addr = ioaddr + mear; + u32 read_cmd = location | EEread; + + outl(0, ee_addr); + eeprom_delay(); + outl(EECLK, ee_addr); + eeprom_delay(); + + /* Shift the read command (9) bits out. */ + for (i = 8; i >= 0; i--) { + u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS; + outl(dataval, ee_addr); + eeprom_delay(); + outl(dataval | EECLK, ee_addr); + eeprom_delay(); + } + outb(EECS, ee_addr); + eeprom_delay(); + + /* read the 16-bits data in */ + for (i = 16; i > 0; i--) { + outl(EECS, ee_addr); + eeprom_delay(); + outl(EECS | EECLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0); + eeprom_delay(); + } + + /* Terminate the EEPROM access. */ + outl(0, ee_addr); + eeprom_delay(); + outl(EECLK, ee_addr); + + return (retval); } -/* MII serial management: mostly bogus for now. */ /* Read and write the MII management registers using software-generated - serial MDIO protocol. - The maximum data clock rate is 2.5 Mhz. The minimum timing is usually - met by back-to-back PCI I/O cycles, but we insert a delay to avoid - "overclocking" issues. */ - + serial MDIO protocol. Note that the command bits and data bits are + send out seperately */ #define mdio_delay() inl(mdio_addr) -#define MIIread 0x6000 -#define MIIwrite 0x6002 -#define MIIpmdMask 0x0F80 -#define MIIpmdShift 7 -#define MIIregMask 0x007C -#define MIIregShift 2 -#define MIIturnaroundBits 2 -#define MIIcmdLen 16 -#define MIIcmdShift 16 -#define MIIreset 0xFFFFFFFF -#define MIIwrLen 32 - -#define MDC 0x00000040 -#define MDDIR 0x00000020 -#define MDIO 0x00000010 - static void mdio_idle(long mdio_addr) { - outl(MDIO | MDDIR, mdio_addr); - mdio_delay(); - outl(MDIO | MDDIR | MDC, mdio_addr); + outl(MDIO | MDDIR, mdio_addr); + mdio_delay(); + outl(MDIO | MDDIR | MDC, mdio_addr); } /* Syncronize the MII management interface by shifting 32 one bits out. */ static void mdio_reset(long mdio_addr) { - int i; - - for (i = 31; i >= 0; i--) { - outl(MDDIR | MDIO, mdio_addr); - mdio_delay(); - outl(MDDIR | MDIO | MDC, mdio_addr); - mdio_delay(); - } - return; + int i; + + for (i = 31; i >= 0; i--) { + outl(MDDIR | MDIO, mdio_addr); + mdio_delay(); + outl(MDDIR | MDIO | MDC, mdio_addr); + mdio_delay(); + } + return; } -static int mdio_read(struct net_device *dev, int phy_id, int location) +static u16 mdio_read(struct net_device *net_dev, int phy_id, int location) { - long mdio_addr = dev->base_addr + mear; - int mii_cmd = MIIread|(phy_id<= 0; i--) { - int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; - outl(dataval, mdio_addr); - outl(dataval | MDC, mdio_addr); - } - - /* Read the two transition, 16 data, and wire-idle bits. */ - for (i = 16; i > 0; i--) { - outl(0, mdio_addr); - //mdio_delay(); - retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0); - outl(MDC, mdio_addr); - mdio_delay(); - } - return retval; + long mdio_addr = net_dev->base_addr + mear; + int mii_cmd = MIIread|(phy_id<= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; + outl(dataval, mdio_addr); + mdio_delay(); + outl(dataval | MDC, mdio_addr); + mdio_delay(); + } + + /* Read the 16 data bits. */ + for (i = 16; i > 0; i--) { + outl(0, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0); + outl(MDC, mdio_addr); + mdio_delay(); + } + return retval; } -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +static void mdio_write(struct net_device *net_dev, int phy_id, int location, int value) { - long mdio_addr = dev->base_addr + mear; - int mii_cmd = MIIwrite|(phy_id<= 0; i--) { - int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; - outb(dataval, mdio_addr); - mdio_delay(); - outb(dataval | MDC, mdio_addr); - mdio_delay(); - } - mdio_delay(); - /* Clear out extra bits. */ - for (i = 2; i > 0; i--) { - outb(0, mdio_addr); - mdio_delay(); - outb(MDC, mdio_addr); - mdio_delay(); - } - return; + long mdio_addr = net_dev->base_addr + mear; + int mii_cmd = MIIwrite|(phy_id<= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; + outb(dataval, mdio_addr); + mdio_delay(); + outb(dataval | MDC, mdio_addr); + mdio_delay(); + } + mdio_delay(); + + /* Shift the value bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR; + outl(dataval, mdio_addr); + mdio_delay(); + outl(dataval | MDC, mdio_addr); + mdio_delay(); + } + mdio_delay(); + + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + outb(0, mdio_addr); + mdio_delay(); + outb(MDC, mdio_addr); + mdio_delay(); + } + return; } static int -sis900_open(struct net_device *dev) +sis900_open(struct net_device *net_dev) { - struct sis900_private *tp = (struct sis900_private *)dev->priv; - long ioaddr = dev->base_addr; - - if (sis900_debug > 0) - printk(KERN_INFO "%s sis900_open, IO Addr=%x, Irq=%x\n", - dev->name, (unsigned int)ioaddr, dev->irq); - - /* Soft reset the chip. */ - outl(0, ioaddr + imr); - outl(0, ioaddr + ier); - outl(0, ioaddr + rfcr); - outl(RESET | RxRESET | TxRESET, ioaddr + cr); - - if (request_irq(dev->irq, &sis900_interrupt, SA_SHIRQ, dev->name, dev)) - { - return -EAGAIN; - } - - MOD_INC_USE_COUNT; - - tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL); - tp->rx_bufs = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL); - if (tp->tx_bufs == NULL || tp->rx_bufs == NULL) { - if (tp->tx_bufs) - kfree(tp->tx_bufs); - if (tp->rx_bufs) - kfree(tp->rx_bufs); - if (!tp->tx_bufs) { - printk(KERN_ERR "%s: Can't allocate a %d byte TX Bufs.\n", - dev->name, TX_BUF_SIZE * NUM_TX_DESC); - } - if (!tp->rx_bufs) { - printk(KERN_ERR "%s: Can't allocate a %d byte RX Bufs.\n", - dev->name, RX_BUF_SIZE * NUM_RX_DESC); - } - return -ENOMEM; - } - - { - u32 rfcrSave; - u32 w; - u32 i; - - rfcrSave = inl(rfcr); - outl(rfcrSave & ~RFEN, rfcr); - for (i=0 ; i<3 ; i++) { - w = (u16)*((u16*)(dev->dev_addr)+i); - outl((((u32) i) << RFEP_shift), ioaddr + rfcr); - outl((u32)w, ioaddr + rfdr); - if (sis900_debug > 4) { - printk(KERN_INFO "Filter Addr[%d]=%x\n", - i, inl(ioaddr + rfdr)); - } - } - outl(rfcrSave, rfcr); - } - - sis900_init_ring(dev); - outl((u32)tp->tx_buf[0].physAddr, ioaddr + txdp); - outl((u32)tp->rx_buf[0].physAddr, ioaddr + rxdp); - - if (sis900_debug > 4) - printk(KERN_INFO "txdp:%8.8x\n", inl(ioaddr + txdp)); - - /* Check that the chip has finished the reset. */ - { - u32 status; - int j=0; - status = TxRCMP | RxRCMP; - while (status && (j++ < 30000)) { - status ^= (inl(isr) & status); - } - } - - outl(PESEL, ioaddr + cfg); - - /* Must enable Tx/Rx before setting transfer thresholds! */ - /* - * #define TX_DMA_BURST 0 - * #define RX_DMA_BURST 0 - * #define TX_FIFO_THRESH 16 - * #define TxDRNT_100 (1536>>5) - * #define TxDRNT_10 (1536>>5) - * #define RxDRNT_100 (1536>>5) - * #define RxDRNT_10 (1536>>5) - */ - outl((RX_DMA_BURST<<20) | (RxDRNT_10 << 1), ioaddr+rxcfg); - outl(TxATP | (TX_DMA_BURST << 20) | (TX_FIFO_THRESH<<8) | TxDRNT_10, - ioaddr + txcfg); - if (sis900_debug > 1) - { - if (tp->LinkOn) { - printk(KERN_INFO"%s: Media Type %s%s-duplex.\n", - dev->name, - tp->speeds==HW_SPEED_100_MBPS ? - "100mbps " : "10mbps ", - tp->full_duplex== FDX_CAPABLE_FULL_SELECTED ? - "full" : "half"); + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + long ioaddr = net_dev->base_addr; + + /* Soft reset the chip. */ + sis900_reset(net_dev); + + if (request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev)) { + return -EAGAIN; + } + + MOD_INC_USE_COUNT; + + sis900_init_rxfilter(net_dev); + + sis900_init_tx_ring(net_dev); + sis900_init_rx_ring(net_dev); + + set_rx_mode(net_dev); + + net_dev->tbusy = 0; + net_dev->interrupt = 0; + net_dev->start = 1; + + /* Enable all known interrupts by setting the interrupt mask. */ + outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr); + outl(RxENA, ioaddr + cr); + outl(IE, ioaddr + ier); + + sis900_check_mode(net_dev, sis_priv->mii); + + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer(&sis_priv->timer); + sis_priv->timer.expires = jiffies + HZ; + sis_priv->timer.data = (unsigned long)net_dev; + sis_priv->timer.function = &sis900_timer; + add_timer(&sis_priv->timer); + + return 0; +} + +/* set receive filter address to our MAC address */ +static void +sis900_init_rxfilter (struct net_device * net_dev) +{ + long ioaddr = net_dev->base_addr; + u32 rfcrSave; + u32 i; + + rfcrSave = inl(rfcr + ioaddr); + + /* disable packet filtering before setting filter */ + outl(rfcrSave & ~RFEN, rfcr); + + /* load MAC addr to filter data register */ + for (i = 0 ; i < 3 ; i++) { + u32 w; + + w = (u32) *((u16 *)(net_dev->dev_addr)+i); + outl((i << RFADDR_shift), ioaddr + rfcr); + outl(w, ioaddr + rfdr); + + if (sis900_debug > 2) { + printk(KERN_INFO "%s: Receive Filter Addrss[%d]=%x\n", + net_dev->name, i, inl(ioaddr + rfdr)); } - else printk(KERN_INFO"%s: Media Link Off\n", dev->name); } - set_rx_mode(dev); - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - - /* Enable all known interrupts by setting the interrupt mask. */ - outl((RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr); - outl(RxENA, ioaddr + cr); - outl(IE, ioaddr + ier); - - if (sis900_debug > 3) - printk(KERN_INFO "%s: sis900_open() ioaddr %#lx IRQ %d \n", - dev->name, ioaddr, dev->irq); - - /* Set the timer to switch to check for link beat and perhaps switch - to an alternate media type. */ - init_timer(&tp->timer); - tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ - tp->timer.data = (unsigned long)dev; - tp->timer.function = &sis900_timer; /* timer handler */ - add_timer(&tp->timer); - - return 0; + + /* enable packet filitering */ + outl(rfcrSave | RFEN, rfcr + ioaddr); +} + +/* Initialize the Tx ring. */ +static void +sis900_init_tx_ring(struct net_device *net_dev) +{ + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + long ioaddr = net_dev->base_addr; + int i; + + sis_priv->tx_full = 0; + sis_priv->dirty_tx = sis_priv->cur_tx = 0; + + for (i = 0; i < NUM_TX_DESC; i++) { + sis_priv->tx_skbuff[i] = NULL; + + sis_priv->tx_ring[i].link = (u32) virt_to_bus(&sis_priv->tx_ring[i+1]); + sis_priv->tx_ring[i].cmdsts = 0; + sis_priv->tx_ring[i].bufptr = 0; + } + sis_priv->tx_ring[i-1].link = (u32) virt_to_bus(&sis_priv->tx_ring[0]); + + /* load Transmit Descriptor Register */ + outl(virt_to_bus(&sis_priv->tx_ring[0]), ioaddr + txdp); + if (sis900_debug > 2) + printk(KERN_INFO "%s: TX descriptor register loaded with: %8.8x\n", + net_dev->name, inl(ioaddr + txdp)); } +/* Initialize the Rx descriptor ring, pre-allocate recevie buffers */ +static void +sis900_init_rx_ring(struct net_device *net_dev) +{ + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + long ioaddr = net_dev->base_addr; + int i; + + sis_priv->cur_rx = 0; + sis_priv->dirty_rx = 0; + + /* init RX descriptor */ + for (i = 0; i < NUM_RX_DESC; i++) { + sis_priv->rx_skbuff[i] = NULL; + + sis_priv->rx_ring[i].link = (u32) virt_to_bus(&sis_priv->rx_ring[i+1]); + sis_priv->rx_ring[i].cmdsts = 0; + sis_priv->rx_ring[i].bufptr = 0; + } + sis_priv->rx_ring[i-1].link = (u32) virt_to_bus(&sis_priv->rx_ring[0]); + + /* allocate sock buffers */ + for (i = 0; i < NUM_RX_DESC; i++) { + struct sk_buff *skb; + + if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) { + /* not enough memory for skbuff, this makes a "hole" + on the buffer ring, it is not clear how the + hardware will react to this kind of degenerated + buffer */ + break; + } + skb->dev = net_dev; + sis_priv->rx_skbuff[i] = skb; + sis_priv->rx_ring[i].cmdsts = RX_BUF_SIZE; + sis_priv->rx_ring[i].bufptr = virt_to_bus(skb->tail); + } + sis_priv->dirty_rx = (unsigned int) (i - NUM_RX_DESC); + + /* load Receive Descriptor Register */ + outl(virt_to_bus(&sis_priv->rx_ring[0]), ioaddr + rxdp); + if (sis900_debug > 2) + printk(KERN_INFO "%s: RX descriptor register loaded with: %8.8x\n", + net_dev->name, inl(ioaddr + rxdp)); +} +/* on each timer ticks we check two things, Link Status (ON/OFF) and + Link Mode (10/100/Full/Half) + */ static void sis900_timer(unsigned long data) { - struct net_device *dev = (struct net_device *)data; - struct sis900_private *tp = (struct sis900_private *)dev->priv; - int next_tick = 0; - u16 status; - - if (!tp->LinkOn) { - status = mdio_read(dev, tp->phys[tp->phy_idx], MII_STATUS); - if (status & MIISTAT_LINK) { - elPMDreadMode(dev, tp->phys[tp->phy_idx], - &tp->speeds, &tp->full_duplex); - tp->LinkOn = TRUE; - printk(KERN_INFO "%s: Media Link On %s%s-duplex ", - dev->name, - tp->speeds == HW_SPEED_100_MBPS ? - "100mbps " : "10mbps ", - tp->full_duplex==FDX_CAPABLE_FULL_SELECTED ? - "full" : "half"); + struct net_device *net_dev = (struct net_device *)data; + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct mii_phy *mii_phy = sis_priv->mii; + static int next_tick = 5*HZ; + u16 status; + + status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); + + /* current mii phy is failed to link, try another one */ + while (!(status & MII_STAT_LINK)) { + if (mii_phy->next == NULL) { + if (sis_priv->LinkOn) { + /* link stat change from ON to OFF */ + next_tick = HZ; + sis_priv->LinkOn = FALSE; + printk(KERN_INFO "%s: Media Link Off\n", + net_dev->name); + } + sis_priv->timer.expires = jiffies + next_tick; + add_timer(&sis_priv->timer); + return; } - } else { // previous link on - status = mdio_read(dev, tp->phys[tp->phy_idx], MII_STATUS); - if (!(status & MIISTAT_LINK)) { - tp->LinkOn = FALSE; - printk(KERN_INFO "%s: Media Link Off\n", dev->name); + mii_phy = mii_phy->next; + status = mdio_read(net_dev, mii_phy->phy_addr, MII_STATUS); + } + + if (!sis_priv->LinkOn) { + /* link stat change forn OFF to ON, read and report link mode */ + sis_priv->LinkOn = TRUE; + next_tick = 5*HZ; + /* change what cur_phy means */ + if (mii_phy->phy_addr != sis_priv->cur_phy) { + printk(KERN_INFO "%s: Changing transceiver to %s\n", net_dev->name, + mii_phy->chip_info->name); + status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL); + mdio_write(net_dev, sis_priv->cur_phy, + MII_CONTROL, status | MII_CNTL_ISOLATE); + status = mdio_read(net_dev, mii_phy->phy_addr, MII_CONTROL); + mdio_write(net_dev, mii_phy->phy_addr, + MII_CONTROL, status & ~MII_CNTL_ISOLATE); + sis_priv->cur_phy = mii_phy->phy_addr; } - } - next_tick = 2*HZ; + sis900_check_mode(net_dev, mii_phy); + } - if (next_tick) { - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); - } + sis_priv->timer.expires = jiffies + next_tick; + add_timer(&sis_priv->timer); } - -static void sis900_tx_timeout(struct net_device *dev) +static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy) { - struct sis900_private *tp = (struct sis900_private *)dev->priv; - long ioaddr = dev->base_addr; - int i; - - if (sis900_debug > 0) - printk(KERN_INFO "%s: Transmit timeout, status %2.2x %4.4x \n", - dev->name, inl(ioaddr + cr), inl(ioaddr + isr)); - - /* Disable interrupts by clearing the interrupt mask. */ - outl(0x0000, ioaddr + imr); - - /* Emit info to figure out what went wrong. */ - if (sis900_debug > 1) { - printk(KERN_INFO "%s:Tx queue start entry %d dirty entry %d.\n", - dev->name, tp->cur_tx, tp->dirty_tx); - for (i = 0; i < NUM_TX_DESC; i++) - printk(KERN_INFO "%s: Tx descriptor %d is %8.8x.%s\n", - dev->name, i, (unsigned int)&tp->tx_buf[i], - i == tp->dirty_tx % NUM_TX_DESC ? - " (queue head)" : ""); + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + long ioaddr = net_dev->base_addr; + int speed, duplex; + u32 tx_flags = 0, rx_flags = 0; + + mii_phy->chip_info->read_mode(net_dev, sis_priv->cur_phy, &speed, &duplex); + + tx_flags = TxATP | (TX_DMA_BURST << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); + rx_flags = RX_DMA_BURST << RxMXDMA_shift; + + if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS ) { + rx_flags |= (RxDRNT_10 << RxDRNT_shift); + tx_flags |= (TxDRNT_10 << TxDRNT_shift); + } + else { + rx_flags |= (RxDRNT_100 << RxDRNT_shift); + tx_flags |= (TxDRNT_100 << TxDRNT_shift); + } + + if (duplex == FDX_CAPABLE_FULL_SELECTED) { + tx_flags |= (TxCSI | TxHBI); + rx_flags |= RxATX; } - /* Soft reset the chip. */ - //outb(RESET, ioaddr + cr); - /* Check that the chip has finished the reset. */ - /* - for (i = 1000; i > 0; i--) - if ((inb(ioaddr + cr) & RESET) == 0) - break; - */ - - tp->cur_rx = 0; - /* Must enable Tx/Rx before setting transfer thresholds! */ - /* - set_rx_mode(dev); - */ - { /* Save the unsent Tx packets. */ - struct sk_buff *saved_skb[NUM_TX_DESC], *skb; - int j; - for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) - saved_skb[j]=tp->tx_skbuff[tp->dirty_tx % NUM_TX_DESC]; - tp->dirty_tx = tp->cur_tx = 0; - - for (i = 0; i < j; i++) { - skb = tp->tx_skbuff[i] = saved_skb[i]; - /* Always alignment */ - memcpy((unsigned char*)(tp->tx_buf[i].buf), - skb->data, skb->len); - tp->tx_buf[i].cmdsts = OWN | skb->len; - /* Note: the chip doesn't have auto-pad! */ - /* - outl(tp->tx_flag|(skb->len>=ETH_ZLEN?skb->len:ETH_ZLEN), - ioaddr + TxStatus0 + i*4); - */ - } - outl(TxENA, ioaddr + cr); - tp->cur_tx = i; - while (i < NUM_TX_DESC) - tp->tx_skbuff[i++] = 0; - if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ - dev->tbusy = 0; - tp->tx_full = 0; - } else { - tp->tx_full = 1; - } - } - - dev->trans_start = jiffies; - tp->stats.tx_errors++; - /* Enable all known interrupts by setting the interrupt mask. */ - outl((RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr); - return; + outl (tx_flags, ioaddr + txcfg); + outl (rx_flags, ioaddr + rxcfg); +} +static void sis900_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex) +{ + int i = 0; + u32 status; + + /* STSOUT register is Latched on Transition, read operation updates it */ + while (i++ < 2) + status = mdio_read(net_dev, phy_addr, MII_STSOUT); + + if (status & MII_STSOUT_SPD) + *speed = HW_SPEED_100_MBPS; + else + *speed = HW_SPEED_10_MBPS; + + if (status & MII_STSOUT_DPLX) + *duplex = FDX_CAPABLE_FULL_SELECTED; + else + *duplex = FDX_CAPABLE_HALF_SELECTED; + + if (status & MII_STSOUT_LINK_FAIL) + printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); + else + printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", + net_dev->name, + *speed == HW_SPEED_100_MBPS ? + "100mbps" : "10mbps", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); +} +static void amd79c901_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex) +{ + int i; + u16 status; + + for (i = 0; i < 2; i++) + status = mdio_read(net_dev, phy_addr, MII_STATUS); + + if (status & MII_STAT_CAN_AUTO) { + /* 10BASE-T PHY */ + for (i = 0; i < 2; i++) + status = mdio_read(net_dev, phy_addr, MII_STATUS_SUMMARY); + if (status & MII_STSSUM_SPD) + *speed = HW_SPEED_100_MBPS; + else + *speed = HW_SPEED_10_MBPS; + if (status & MII_STSSUM_DPLX) + *duplex = FDX_CAPABLE_FULL_SELECTED; + else + *duplex = FDX_CAPABLE_HALF_SELECTED; + + if (status & MII_STSSUM_LINK) + printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", + net_dev->name, + *speed == HW_SPEED_100_MBPS ? + "100mbps" : "10mbps", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); + else + printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); + + } + else { + /* HomePNA */ + *speed = HW_SPEED_HOME; + *duplex = FDX_CAPABLE_HALF_SELECTED; + if (status & MII_STAT_LINK) + printk(KERN_INFO "%s: Media Link On 1mbps half-duplex \n", + net_dev->name); + else + printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); + } } +static void sis900_tx_timeout(struct net_device *net_dev) +{ + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + long ioaddr = net_dev->base_addr; + printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n", + net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr)); + + /* Disable interrupts by clearing the interrupt mask. */ + outl(0x0000, ioaddr + imr); -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void -sis900_init_ring(struct net_device *dev) -{ - struct sis900_private *tp = (struct sis900_private *)dev->priv; - int i; - - tp->tx_full = 0; - tp->cur_rx = 0; - tp->dirty_tx = tp->cur_tx = 0; - - /* Tx Buffer */ - for (i = 0; i < NUM_TX_DESC; i++) { - tp->tx_skbuff[i] = 0; - tp->tx_buf[i].buf = &tp->tx_bufs[i*TX_BUF_SIZE]; - tp->tx_buf[i].bufPhys = - virt_to_bus(&tp->tx_bufs[i*TX_BUF_SIZE]); - } - - /* Tx Descriptor */ - for (i = 0; i< NUM_TX_DESC; i++) { - tp->tx_buf[i].llink = (u32) - &(tp->tx_buf[((i+1) < NUM_TX_DESC) ? (i+1) : 0]); - tp->tx_buf[i].plink = (u32) - virt_to_bus(&(tp->tx_buf[((i+1) < NUM_TX_DESC) ? - (i+1) : 0].plink)); - tp->tx_buf[i].physAddr= - virt_to_bus(&(tp->tx_buf[i].plink)); - tp->tx_buf[i].cmdsts=0; - } - - /* Rx Buffer */ - for (i = 0; i < NUM_RX_DESC; i++) { - tp->rx_buf[i].buf = &tp->rx_bufs[i*RX_BUF_SIZE]; - tp->rx_buf[i].bufPhys = - virt_to_bus(&tp->rx_bufs[i*RX_BUF_SIZE]); - } - - /* Rx Descriptor */ - for (i = 0; i< NUM_RX_DESC; i++) { - tp->rx_buf[i].llink = (u32) - &(tp->rx_buf[((i+1) < NUM_RX_DESC) ? (i+1) : 0]); - tp->rx_buf[i].plink = (u32) - virt_to_bus(&(tp->rx_buf[((i+1) < NUM_RX_DESC) ? - (i+1) : 0].plink)); - tp->rx_buf[i].physAddr= - virt_to_bus(&(tp->rx_buf[i].plink)); - tp->rx_buf[i].cmdsts=RX_BUF_SIZE; - } + sis_priv->cur_rx = 0; + net_dev->trans_start = jiffies; + sis_priv->stats.tx_errors++; + + /* FIXME: Should we restart the transmission thread here ?? */ + + /* Enable all known interrupts by setting the interrupt mask. */ + outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxOK), ioaddr + imr); + return; } static int -sis900_start_xmit(struct sk_buff *skb, struct net_device *dev) +sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) { - struct sis900_private *tp = (struct sis900_private *)dev->priv; - long ioaddr = dev->base_addr; - int entry; - - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start < TX_TIMEOUT) - return 1; - sis900_tx_timeout(dev); - return 1; - } - - /* Calculate the next Tx descriptor entry. ????? */ - entry = tp->cur_tx % NUM_TX_DESC; - - tp->tx_skbuff[entry] = skb; - - if (sis900_debug > 5) { - int i; - printk(KERN_INFO "%s: SKB Tx Frame contents:(len=%d)", - dev->name,skb->len); - - for (i = 0; i < skb->len; i++) { - printk("%2.2x ", - (u8)skb->data[i]); - } - printk(".\n"); - } - - memcpy(tp->tx_buf[entry].buf, - skb->data, skb->len); - - tp->tx_buf[entry].cmdsts=(OWN | skb->len); - - //tp->tx_buf[entry].plink = 0; - outl(TxENA, ioaddr + cr); - if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ - clear_bit(0, (void*)&dev->tbusy); - } else { - tp->tx_full = 1; - } - - /* Note: the chip doesn't have auto-pad! */ - - dev->trans_start = jiffies; - if (sis900_debug > 4) - printk(KERN_INFO "%s: Queued Tx packet at " - "%p size %d to slot %d.\n", - dev->name, skb->data, (int)skb->len, entry); - - return 0; + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + long ioaddr = net_dev->base_addr; + unsigned int entry; + + /* test tbusy to see if we have timeout situation then set it */ + if (test_and_set_bit(0, (void*)&net_dev->tbusy) != 0) { + if (jiffies - net_dev->trans_start > TX_TIMEOUT) + sis900_tx_timeout(net_dev); + return 1; + } + + /* Calculate the next Tx descriptor entry. */ + entry = sis_priv->cur_tx % NUM_TX_DESC; + sis_priv->tx_skbuff[entry] = skb; + + /* set the transmit buffer descriptor and enable Transmit State Machine */ + sis_priv->tx_ring[entry].bufptr = virt_to_bus(skb->data); + sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len); + outl(TxENA, ioaddr + cr); + + if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) { + /* Typical path, clear tbusy to indicate more + transmission is possible */ + clear_bit(0, (void*)&net_dev->tbusy); + } else { + /* no more transmit descriptor avaiable, tbusy remain set */ + sis_priv->tx_full = 1; + } + + net_dev->trans_start = jiffies; + + if (sis900_debug > 3) + printk(KERN_INFO "%s: Queued Tx packet at %p size %d " + "to slot %d.\n", + net_dev->name, skb->data, (int)skb->len, entry); + + return 0; } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *)dev_instance; - struct sis900_private *tp = (struct sis900_private *)dev->priv; - int boguscnt = max_interrupt_work; - int status; - long ioaddr = dev->base_addr; + struct net_device *net_dev = (struct net_device *)dev_instance; + int boguscnt = max_interrupt_work; + long ioaddr = net_dev->base_addr; + u32 status; #if defined(__i386__) - /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ - if (test_and_set_bit(0, (void*)&dev->interrupt)) { - printk(KERN_INFO "%s: SMP simultaneous entry of " - "an interrupt handler.\n", dev->name); - dev->interrupt = 0; /* Avoid halting machine. */ - return; - } + /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ + if (test_and_set_bit(0, (void*)&net_dev->interrupt)) { + printk(KERN_INFO "%s: SMP simultaneous entry of " + "an interrupt handler.\n", net_dev->name); + net_dev->interrupt = 0; /* Avoid halting machine. */ + return; + } #else - if (dev->interrupt) { - printk(KERN_INFO "%s: Re-entering the " - "interrupt handler.\n", dev->name); - return; - } - dev->interrupt = 1; -#endif - - do { - status = inl(ioaddr + isr); - /* Acknowledge all of the current interrupt sources ASAP. */ - outl(status, ioaddr + isr); // ????? - - if (sis900_debug > 4) - printk(KERN_INFO "%s: interrupt status=%#4.4x " - "new intstat=%#4.4x.\n", - dev->name, status, inl(ioaddr + isr)); - - if ((status & (TxURN|TxERR|TxOK | RxORN|RxERR|RxOK)) == 0) { - break; - } - - if (status & (RxOK|RxORN|RxERR)) /* Rx interrupt */ - sis900_rx(dev); - - if (status & (TxOK | TxERR)) { - unsigned int dirty_tx; - - if (sis900_debug > 5) { - printk(KERN_INFO "TxOK:tp->cur_tx:%d," - "tp->dirty_tx:%x\n", - tp->cur_tx, tp->dirty_tx); - } - for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; - dirty_tx++) - { - int i; - int entry = dirty_tx % NUM_TX_DESC; - int txstatus = tp->tx_buf[entry].cmdsts; - - if (sis900_debug > 4) { - printk(KERN_INFO "%s: Tx Frame contents:" - "(len=%d)", - dev->name, (txstatus & DSIZE)); - - for (i = 0; i < (txstatus & DSIZE) ; - i++) { - printk("%2.2x ", - (u8)(tp->tx_buf[entry].buf[i])); - } - printk(".\n"); - } - if ( ! (txstatus & (OK | UNDERRUN))) - { - if (sis900_debug > 1) - printk(KERN_INFO "Tx NOT (OK," - "UnderRun)\n"); - break; /* It still hasn't been Txed */ - } - - /* Note: TxCarrierLost is always asserted - at 100mbps. */ - if (txstatus & (OWCOLL | ABORT)) { - /* There was an major error, log it. */ - if (sis900_debug > 1) - printk(KERN_INFO "Tx Out of " - " Window,Abort\n"); -#ifndef final_version - if (sis900_debug > 1) - printk(KERN_INFO "%s: Transmit " - "error, Tx status %8.8x.\n", - dev->name, txstatus); -#endif - tp->stats.tx_errors++; - if (txstatus & ABORT) { - tp->stats.tx_aborted_errors++; - } - if (txstatus & NOCARRIER) - tp->stats.tx_carrier_errors++; - if (txstatus & OWCOLL) - tp->stats.tx_window_errors++; -#ifdef ETHER_STATS - if ((txstatus & COLCNT)==COLCNT) - tp->stats.collisions16++; -#endif - } else { -#ifdef ETHER_STATS - /* No count for tp->stats.tx_deferred */ -#endif - if (txstatus & UNDERRUN) { - if (sis900_debug > 2) - printk(KERN_INFO "Tx UnderRun\n"); - } - tp->stats.collisions += - (txstatus >> 16) & 0xF; -#if LINUX_VERSION_CODE > 0x20119 - tp->stats.tx_bytes += txstatus & DSIZE; -#endif - if (sis900_debug > 2) - printk(KERN_INFO "Tx Transmit OK\n"); - tp->stats.tx_packets++; - } - - /* Free the original skb. */ - if (sis900_debug > 2) - printk(KERN_INFO "Free original skb\n"); - dev_free_skb(tp->tx_skbuff[entry]); - tp->tx_skbuff[entry] = 0; - } // for dirty - -#ifndef final_version - if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { - printk(KERN_INFO"%s: Out-of-sync dirty pointer," - " %d vs. %d, full=%d.\n", - dev->name, dirty_tx, - tp->cur_tx, tp->tx_full); - dirty_tx += NUM_TX_DESC; - } + if (net_dev->interrupt) { + printk(KERN_INFO "%s: Re-entering the interrupt handler.\n", + net_dev->name); + return; + } + net_dev->interrupt = 1; #endif - if (tp->tx_full && dirty_tx > tp->cur_tx-NUM_TX_DESC) { - /* The ring is no longer full, clear tbusy. */ - if (sis900_debug > 3) - printk(KERN_INFO "Tx Ring NO LONGER Full\n"); - tp->tx_full = 0; - dev->tbusy = 0; - mark_bh(NET_BH); - } - - tp->dirty_tx = dirty_tx; - if (sis900_debug > 2) - printk(KERN_INFO "TxOK,tp->cur_tx:%d,tp->dirty:%d\n", - tp->cur_tx, tp->dirty_tx); - } // if (TxOK | TxERR) - - /* Check uncommon events with one test. */ - if (status & (RxORN | TxERR | RxERR)) { - if (sis900_debug > 2) - printk(KERN_INFO "%s: Abnormal interrupt," - "status %8.8x.\n", dev->name, status); - - if (status == 0xffffffff) - break; - if (status & (RxORN | RxERR)) - tp->stats.rx_errors++; - - - if (status & RxORN) { - tp->stats.rx_over_errors++; - } - } - if (--boguscnt < 0) { - printk(KERN_INFO "%s: Too much work at interrupt, " - "IntrStatus=0x%4.4x.\n", - dev->name, status); - break; - } - } while (1); - - if (sis900_debug > 3) - printk(KERN_INFO "%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, inl(ioaddr + isr)); - + do { + status = inl(ioaddr + isr); + + if (sis900_debug > 3) + printk(KERN_INFO "%s: entering interrupt, " + "original status = %#8.8x, " + "new status = %#8.8x.\n", + net_dev->name, status, inl(ioaddr + isr)); + + if ((status & (HIBERR|TxURN|TxERR|TxOK|RxORN|RxERR|RxOK)) == 0) + /* nothing intresting happened */ + break; + + /* why dow't we break after Tx/Rx case ?? keyword: full-duplex */ + if (status & (RxORN | RxERR | RxOK)) + /* Rx interrupt */ + sis900_rx(net_dev); + + if (status & (TxURN | TxERR | TxOK)) + /* Tx interrupt */ + sis900_finish_xmit(net_dev); + + /* something strange happened !!! */ + if (status & HIBERR) { + printk(KERN_INFO "%s: Abnormal interrupt," + "status %#8.8x.\n", net_dev->name, status); + break; + } + if (--boguscnt < 0) { + printk(KERN_INFO "%s: Too much work at interrupt, " + "interrupt status = %#8.8x.\n", + net_dev->name, status); + break; + } + } while (1); + + if (sis900_debug > 3) + printk(KERN_INFO "%s: exiting interrupt, " + "interrupt status = 0x%#8.8x.\n", + net_dev->name, inl(ioaddr + isr)); + #if defined(__i386__) - clear_bit(0, (void*)&dev->interrupt); + clear_bit(0, (void*)&net_dev->interrupt); #else - dev->interrupt = 0; + net_dev->interrupt = 0; #endif - return; + return; } -/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the - field alignments and semantics. */ -static int sis900_rx(struct net_device *dev) +/* Process receive interrupt events, put buffer to higher layer and refill buffer pool + Note: This fucntion is called by interrupt handler, don't do "too much" work here */ +static int sis900_rx(struct net_device *net_dev) { - struct sis900_private *tp = (struct sis900_private *)dev->priv; - long ioaddr = dev->base_addr; - u16 cur_rx = tp->cur_rx % NUM_RX_DESC; - int rx_status=tp->rx_buf[cur_rx].cmdsts; - - if (sis900_debug > 4) - printk(KERN_INFO "%s: sis900_rx, current %4.4x," - " rx status=%8.8x\n", - dev->name, cur_rx, - rx_status); - - while (rx_status & OWN) { - int rx_size = rx_status & DSIZE; - rx_size -= CRC_SIZE; - - if (sis900_debug > 4) { - int i; - printk(KERN_INFO "%s: sis900_rx, rx status %8.8x," - " size %4.4x, cur %4.4x.\n", - dev->name, rx_status, rx_size, cur_rx); - printk(KERN_INFO "%s: Rx Frame contents:", dev->name); - - for (i = 0; i < rx_size; i++) { - printk("%2.2x ", - (u8)(tp->rx_buf[cur_rx].buf[i])); - } - - printk(".\n"); - } - if (rx_status & TOOLONG) { - if (sis900_debug > 1) - printk(KERN_INFO "%s: Oversized Ethernet frame," - " status %4.4x!\n", - dev->name, rx_status); - tp->stats.rx_length_errors++; - } else if (rx_status & (RXISERR | RUNT | CRCERR | FAERR)) { - if (sis900_debug > 1) - printk(KERN_INFO"%s: Ethernet frame had errors," - " status %4.4x.\n", - dev->name, rx_status); - tp->stats.rx_errors++; - if (rx_status & (RXISERR | FAERR)) - tp->stats.rx_frame_errors++; - if (rx_status & (RUNT | TOOLONG)) - tp->stats.rx_length_errors++; - if (rx_status & CRCERR) tp->stats.rx_crc_errors++; - } else { - /* Malloc up new buffer, compatible with net-2e. */ - /* Omit the four octet CRC from the length. */ - struct sk_buff *skb; - - skb = dev_alloc_skb(rx_size + 2); - if (skb == NULL) { - printk(KERN_INFO "%s: Memory squeeze," - "deferring packet.\n", - dev->name); - /* We should check that some rx space is free. - If not, - free one and mark stats->rx_dropped++. */ - tp->stats.rx_dropped++; - tp->rx_buf[cur_rx].cmdsts = RX_BUF_SIZE; - break; - } - skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte align the IP fields. */ - if (rx_size+CRC_SIZE > RX_BUF_SIZE) { - /* - int semi_count = RX_BUF_LEN - ring_offset - 4; - memcpy(skb_put(skb, semi_count), - &rx_bufs[ring_offset + 4], semi_count); - memcpy(skb_put(skb, rx_size-semi_count), - rx_bufs, rx_size - semi_count); - if (sis900_debug > 4) { - int i; - printk(KERN_DEBUG"%s: Frame wrap @%d", - dev->name, semi_count); - for (i = 0; i < 16; i++) - printk(" %2.2x", rx_bufs[i]); - printk(".\n"); - memset(rx_bufs, 0xcc, 16); - } - */ - } else { -#if 0 /* USE_IP_COPYSUM */ - eth_copy_and_sum(skb, - tp->rx_buf[cur_rx].buf, rx_size, 0); - skb_put(skb, rx_size); -#else - memcpy(skb_put(skb, rx_size), - tp->rx_buf[cur_rx].buf, rx_size); -#endif - } - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); -#if LINUX_VERSION_CODE > 0x20119 - tp->stats.rx_bytes += rx_size; -#endif - tp->stats.rx_packets++; - } - tp->rx_buf[cur_rx].cmdsts = RX_BUF_SIZE; - - cur_rx = ((cur_rx+1) % NUM_RX_DESC); - rx_status = tp->rx_buf[cur_rx].cmdsts; - } // while - if (sis900_debug > 4) - printk(KERN_INFO "%s: Done sis900_rx(), current %4.4x " - "Cmd %2.2x.\n", - dev->name, cur_rx, - inb(ioaddr + cr)); - tp->cur_rx = cur_rx; - return 0; + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + long ioaddr = net_dev->base_addr; + unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; + u32 rx_status = sis_priv->rx_ring[entry].cmdsts; + + if (sis900_debug > 3) + printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d " + "status:0x%8.8x\n", + sis_priv->cur_rx, sis_priv->dirty_rx,rx_status); + + while (rx_status & OWN) { + unsigned int rx_size; + + rx_size = (rx_status & DSIZE) - CRC_SIZE; + + if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) { + /* corrupted packet received */ + if (sis900_debug > 3) + printk(KERN_INFO "%s: Corrupted packet " + "received, buffer status = 0x%8.8x.\n", + net_dev->name, rx_status); + sis_priv->stats.rx_errors++; + if (rx_status & OVERRUN) + sis_priv->stats.rx_over_errors++; + if (rx_status & (TOOLONG|RUNT)) + sis_priv->stats.rx_length_errors++; + if (rx_status & (RXISERR | FAERR)) + sis_priv->stats.rx_frame_errors++; + if (rx_status & CRCERR) + sis_priv->stats.rx_crc_errors++; + /* reset buffer descriptor state */ + sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; + } else { + struct sk_buff * skb; + + if (sis_priv->rx_skbuff[entry] == NULL) { + printk(KERN_INFO "%s: NULL pointer " + "encountered in Rx ring, skipping\n", + net_dev->name); + break; + } + skb = sis_priv->rx_skbuff[entry]; + sis_priv->rx_skbuff[entry] = NULL; + /* reset buffer descriptor state */ + sis_priv->rx_ring[entry].cmdsts = 0; + sis_priv->rx_ring[entry].bufptr = 0; + + skb_put(skb, rx_size); + skb->protocol = eth_type_trans(skb, net_dev); + netif_rx(skb); + + if ((rx_status & BCAST) == MCAST) + sis_priv->stats.multicast++; + net_dev->last_rx = jiffies; + sis_priv->stats.rx_bytes += rx_size; + sis_priv->stats.rx_packets++; + } + sis_priv->cur_rx++; + entry = sis_priv->cur_rx % NUM_RX_DESC; + rx_status = sis_priv->rx_ring[entry].cmdsts; + } // while + + /* refill the Rx buffer, what if the rate of refilling is slower than + consuming ?? */ + for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) { + struct sk_buff *skb; + + entry = sis_priv->dirty_rx % NUM_RX_DESC; + + if (sis_priv->rx_skbuff[entry] == NULL) { + if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) { + /* not enough memory for skbuff, this makes a "hole" + on the buffer ring, it is not clear how the + hardware will react to this kind of degenerated + buffer */ + printk(KERN_INFO "%s: Memory squeeze," + "deferring packet.\n", + net_dev->name); + sis_priv->stats.rx_dropped++; + break; + } + skb->dev = net_dev; + sis_priv->rx_skbuff[entry] = skb; + sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; + sis_priv->rx_ring[entry].bufptr = virt_to_bus(skb->tail); + } + } + /* re-enable the potentially idle receive state matchine */ + outl(RxENA , ioaddr + cr ); + + return 0; } -static int -sis900_close(struct net_device *dev) +/* finish up transmission of packets, check for error condition and free skbuff etc. + Note: This fucntion is called by interrupt handler, don't do "too much" work here */ +static void sis900_finish_xmit (struct net_device *net_dev) { - long ioaddr = dev->base_addr; - struct sis900_private *tp = (struct sis900_private *)dev->priv; - int i; - - dev->start = 0; - dev->tbusy = 1; + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + + for (; sis_priv->dirty_tx < sis_priv->cur_tx; sis_priv->dirty_tx++) { + unsigned int entry; + u32 tx_status; + + entry = sis_priv->dirty_tx % NUM_TX_DESC; + tx_status = sis_priv->tx_ring[entry].cmdsts; + + if (tx_status & OWN) { + /* The packet is not transmited yet (owned by hardware) ! */ + break; + } + + if (tx_status & (ABORT | UNDERRUN | OWCOLL)) { + /* packet unsuccessfully transmited */ + if (sis900_debug > 3) + printk(KERN_INFO "%s: Transmit " + "error, Tx status %8.8x.\n", + net_dev->name, tx_status); + sis_priv->stats.tx_errors++; + if (tx_status & UNDERRUN) + sis_priv->stats.tx_fifo_errors++; + if (tx_status & ABORT) + sis_priv->stats.tx_aborted_errors++; + if (tx_status & NOCARRIER) + sis_priv->stats.tx_carrier_errors++; + if (tx_status & OWCOLL) + sis_priv->stats.tx_window_errors++; + } else { + /* packet successfully transmited */ + if (sis900_debug > 3) + printk(KERN_INFO "Tx Transmit OK\n"); + sis_priv->stats.collisions += (tx_status & COLCNT) >> 16; + sis_priv->stats.tx_bytes += tx_status & DSIZE; + sis_priv->stats.tx_packets++; + } + /* Free the original skb. */ + dev_kfree_skb(sis_priv->tx_skbuff[entry]); + sis_priv->tx_skbuff[entry] = NULL; + sis_priv->tx_ring[entry].bufptr = 0; + sis_priv->tx_ring[entry].cmdsts = 0; + } + + if (sis_priv->tx_full && net_dev->tbusy && + sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) { + /* The ring is no longer full, clear tbusy, tx_full and schedule + more transmission by marking NET_BH */ + sis_priv->tx_full = 0; + clear_bit(0, (void *)&net_dev->tbusy); + mark_bh(NET_BH); + } +} - if (sis900_debug > 1) - printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n", - dev->name, inl(ioaddr + isr)); +static int +sis900_close(struct net_device *net_dev) +{ + long ioaddr = net_dev->base_addr; + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + int i; + + net_dev->start = 0; + net_dev->tbusy = 1; - /* Disable interrupts by clearing the interrupt mask. */ - outl(0x0000, ioaddr + imr); + /* Disable interrupts by clearing the interrupt mask. */ + outl(0x0000, ioaddr + imr); + outl(0x0000, ioaddr + ier); - /* Stop the chip's Tx and Rx DMA processes. */ - outl(0x00, ioaddr + cr); + /* Stop the chip's Tx and Rx Status Machine */ + outl(RxDIS | TxDIS, ioaddr + cr); - del_timer(&tp->timer); + del_timer(&sis_priv->timer); - free_irq(dev->irq, dev); + free_irq(net_dev->irq, net_dev); - for (i = 0; i < NUM_TX_DESC; i++) { - if (tp->tx_skbuff[i]) - dev_free_skb(tp->tx_skbuff[i]); - tp->tx_skbuff[i] = 0; - } - kfree(tp->rx_bufs); - kfree(tp->tx_bufs); + /* Free Tx and RX skbuff */ + for (i = 0; i < NUM_RX_DESC; i++) { + if (sis_priv->rx_skbuff[i] != NULL) + dev_kfree_skb(sis_priv->rx_skbuff[i]); + sis_priv->rx_skbuff[i] = 0; + } + for (i = 0; i < NUM_TX_DESC; i++) { + if (sis_priv->tx_skbuff[i] != NULL) + dev_kfree_skb(sis_priv->tx_skbuff[i]); + sis_priv->tx_skbuff[i] = 0; + } - /* Green! Put the chip in low-power mode. */ + /* Green! Put the chip in low-power mode. */ - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; - return 0; + return 0; } -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) { - struct sis900_private *tp = (struct sis900_private *)dev->priv; - u16 *data = (u16 *)&rq->ifr_data; - - switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = tp->phys[tp->phy_idx]; - /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); - return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) - return -EPERM; - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); - return 0; - default: - return -EOPNOTSUPP; - } + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = sis_priv->mii->phy_addr; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(net_dev, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!suser()) + return -EPERM; + mdio_write(net_dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } } static struct enet_statistics * -sis900_get_stats(struct net_device *dev) -{ - struct sis900_private *tp = (struct sis900_private *)dev->priv; - - return &tp->stats; -} - -/* Set or clear the multicast filter for this adaptor. - This routine is not state sensitive and need not be SMP locked. */ - -static u16 elComputeHashTableIndex(u8 *addr) +sis900_get_stats(struct net_device *net_dev) { -#define POLYNOMIAL 0x04C11DB6L - u32 crc = 0xffffffff, msb; - int i, j; - u8 byte; - - for( i=0; i<6; i++ ) { - byte = *addr++; - for( j=0; j<8; j++ ) { - msb = crc >> 31; - crc <<= 1; - if( msb ^ ( byte & 1 )) { - crc ^= POLYNOMIAL; - crc |= 1; - } - byte >>= 1; - } - } - // 7 bit crc for 128 bit hash table - return( (int)(crc >> 25) ); -} + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; -static u16 elMIIpollBit(struct net_device *dev, - int phy_id, - int location, - u16 mask, - u16 polarity, - u16 *value) -{ - u32 i; - i=0; - while (1) { - *value = mdio_read(dev, phy_id, location); - if (polarity) { - if (mask & *value) return(TRUE); - } else { - if (mask & ~(*value)) return(TRUE); - } - if (++i == 1200) break; - } - return(FALSE); + return &sis_priv->stats; } -static u16 elPMDreadMode(struct net_device *dev, - int phy_id, - int *speed, - int *duplex) +/* SiS 900 uses the most sigificant 7 bits to index a 128 bits multicast hash table, which makes + this function a little bit different from other drivers */ +static u16 sis900_compute_hashtable_index(u8 *addr) { - u16 status, OurCap; - - *speed = HW_SPEED_10_MBPS; - *duplex = FDX_CAPABLE_HALF_SELECTED; - - status = mdio_read(dev, phy_id, MII_ANLPAR); - OurCap = mdio_read(dev, phy_id, MII_ANAR); - if (sis900_debug > 1) { - printk(KERN_INFO "Link Part Status %4X\n", status); - printk(KERN_INFO "Our Status %4X\n", OurCap); - printk(KERN_INFO "Status Reg %4X\n", - mdio_read(dev, phy_id, MII_STATUS)); - } - status &= OurCap; - if ( !( status & - (MII_NWAY_T|MII_NWAY_T_FDX | MII_NWAY_TX | MII_NWAY_TX_FDX ))) { - if (sis900_debug > 1) { - printk(KERN_INFO "The other end NOT support NWAY...\n"); - } - while (( status = mdio_read(dev, phy_id, 18)) & 0x4000) ; - while (( status = mdio_read(dev, phy_id, 18)) & 0x0020) ; - if (status & 0x80) - *speed = HW_SPEED_100_MBPS; - if (status & 0x40) - *duplex = FDX_CAPABLE_FULL_SELECTED; - if (sis900_debug > 3) { - printk(KERN_INFO"%s: Setting %s%s-duplex.\n", - dev->name, - *speed == HW_SPEED_100_MBPS ? - "100mbps " : "10mbps ", - *duplex == FDX_CAPABLE_FULL_SELECTED ? - "full" : "half"); - } - } else { - if (sis900_debug > 1) { - printk(KERN_INFO "The other end support NWAY...\n"); +/* what is the correct value of the POLYNOMIAL ?? + Donald Becker use 0x04C11DB7U */ +#define POLYNOMIAL 0x04C11DB6L + u32 crc = 0xffffffff, msb; + int i, j; + u8 byte; + + for (i = 0; i < 6; i++) { + byte = *addr++; + for (j = 0; j < 8; j++) { + msb = crc >> 31; + crc <<= 1; + if (msb ^ (byte & 1)) { + crc ^= POLYNOMIAL; + crc |= 1; + } + byte >>= 1; } - - if (status & (MII_NWAY_TX_FDX | MII_NWAY_T_FDX)) { - *duplex = FDX_CAPABLE_FULL_SELECTED; - } - if (status & (MII_NWAY_TX_FDX | MII_NWAY_TX)) { - *speed = HW_SPEED_100_MBPS; - } - if (sis900_debug > 3) { - printk(KERN_INFO"%s: Setting %s%s-duplex based on" - " auto-negotiated partner ability.\n", - dev->name, - *speed == HW_SPEED_100_MBPS ? - "100mbps " : "10mbps ", - *duplex == FDX_CAPABLE_FULL_SELECTED ? - "full" : "half"); - } - } - return (status); -} - -static u16 elAutoNegotiate(struct net_device *dev, int phy_id, int *duplex, int *speed) -{ - u16 status, retnVal; - - if (sis900_debug > 1) { - printk(KERN_INFO "AutoNegotiate...\n"); - } - mdio_write(dev, phy_id, MII_CONTROL, 0); - mdio_write(dev, phy_id, MII_CONTROL, MIICNTL_AUTO | MIICNTL_RST_AUTO); - retnVal = elMIIpollBit(dev, phy_id, MII_CONTROL, MIICNTL_RST_AUTO, - FALSE,&status); - if (!retnVal) { - printk(KERN_INFO "Not wait for Reset Complete\n"); - } - retnVal = elMIIpollBit(dev, phy_id, MII_STATUS, MIISTAT_AUTO_DONE, - TRUE, &status); - if (!retnVal) { - printk(KERN_INFO "Not wait for AutoNego Complete\n"); } - retnVal = elMIIpollBit(dev, phy_id, MII_STATUS, MIISTAT_LINK, - TRUE, &status); - if (!retnVal) { - printk(KERN_INFO "Not wait for Link Complete\n"); - } - if (status & MIISTAT_LINK) { - elPMDreadMode(dev, phy_id, speed, duplex); - elSetMediaType(dev, *speed, *duplex); - } - return(status); + /* leave 7 most siginifant bits */ + return ((int)(crc >> 25)); } -static void elSetCapability(struct net_device *dev, int phy_id, - int duplex, int speed) +static void set_rx_mode(struct net_device *net_dev) { - u16 cap = ( MII_NWAY_T | MII_NWAY_T_FDX | - MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_CSMA_CD ); - - if (speed != 100) { - cap &= ~( MII_NWAY_TX | MII_NWAY_TX_FDX ); - if (sis900_debug > 1) { - printk(KERN_INFO "UNSET 100Mbps\n"); - } + long ioaddr = net_dev->base_addr; + u16 mc_filter[8]; /* 128 bits multicast hash table */ + int i; + u32 rx_mode; + + if (net_dev->flags & IFF_PROMISC) { + /* Accept any kinds of packets */ + rx_mode = RFPromiscuous; + for (i = 0; i < 8; i++) + mc_filter[i] = 0xffff; + } else if ((net_dev->mc_count > multicast_filter_limit) || + (net_dev->flags & IFF_ALLMULTI)) { + /* too many multicast addresses or accept all multicast packet */ + rx_mode = RFAAB | RFAAM; + for (i = 0; i < 8; i++) + mc_filter[i] = 0xffff; + } else { + /* Accept Broadcast packet, destination address matchs our MAC address, + use Receive Filter to reject unwanted MCAST packet */ + struct dev_mc_list *mclist; + rx_mode = RFAAB; + for (i = 0; i < 8; i++) + mc_filter[i]=0; + for (i = 0, mclist = net_dev->mc_list; mclist && i < net_dev->mc_count; + i++, mclist = mclist->next) + set_bit(sis900_compute_hashtable_index(mclist->dmi_addr), + mc_filter); } - if (!duplex) { - cap &= ~( MII_NWAY_T_FDX | MII_NWAY_TX_FDX ); - if (sis900_debug > 1) { - printk(KERN_INFO "UNSET full-duplex\n"); - } + /* update Multicast Hash Table in Receive Filter */ + for (i = 0; i < 8; i++) { + /* why plus 0x04 ??, I don't know, UNDOCUMENT FEATURE ?? */ + outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr); + outl(mc_filter[i], ioaddr + rfdr); } - mdio_write(dev, phy_id, MII_ANAR, cap); -} - -static void elSetMediaType(struct net_device *dev, int speed, int duplex) -{ - long ioaddr = dev->base_addr; - u32 txCfgOn = 0, txCfgOff = TxDRNT; - u32 rxCfgOn = 0, rxCfgOff = 0; - - if (speed == HW_SPEED_100_MBPS) { - txCfgOn |= (TxDRNT_100 | TxHBI); - } else { - txCfgOn |= TxDRNT_10; - } - - if (duplex == FDX_CAPABLE_FULL_SELECTED) { - txCfgOn |= (TxCSI | TxHBI); - rxCfgOn |= RxATP; - } else { - txCfgOff |= (TxCSI | TxHBI); - rxCfgOff |= RxATP; - } - outl( (inl(ioaddr + txcfg) & ~txCfgOff) | txCfgOn, ioaddr + txcfg); - outl( (inl(ioaddr + rxcfg) & ~rxCfgOff) | rxCfgOn, ioaddr + rxcfg); -} - -static void set_rx_mode(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - u16 mc_filter[8]; - int i; - int rx_mode; - u32 rxCfgOn = 0, rxCfgOff = 0; - u32 txCfgOn = 0, txCfgOff = 0; - - if (sis900_debug > 3) - printk(KERN_INFO "%s: set_rx_mode (%4.4x) done--" - "RxCfg %8.8x.\n", - dev->name, dev->flags, inl(ioaddr + rxcfg)); - - /* Note: do not reorder, GCC is clever about common statements. */ - if (dev->flags & IFF_PROMISC) { - printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name); - rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS | - ACCEPT_CAM_QUALIFIED | ACCEPT_ALL_PHYS; - for (i=0 ; i<8 ; i++) - mc_filter[i]=0xffff; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { - rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS | - ACCEPT_CAM_QUALIFIED; - for (i=0 ; i<8 ; i++) - mc_filter[i]=0xffff; - } else { - struct dev_mc_list *mclist; - rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS | - ACCEPT_CAM_QUALIFIED; - for (i=0 ; i<8 ; i++) - mc_filter[i]=0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) - set_bit(elComputeHashTableIndex(mclist->dmi_addr), - mc_filter); - } - - for (i=0 ; i<8 ; i++) { - outl((u32)(0x00000004+i) << 16, ioaddr + rfcr); - outl(mc_filter[i], ioaddr + rfdr); - } - /* We can safely update without stopping the chip. */ - //rx_mode = ACCEPT_CAM_QUALIFIED | ACCEPT_ALL_BCASTS | ACCEPT_ALL_PHYS; - //rx_mode = ACCEPT_CAM_QUALIFIED | ACCEPT_ALL_BCASTS; - outl(RFEN | ((rx_mode & (ACCEPT_ALL_MCASTS | ACCEPT_ALL_BCASTS | - ACCEPT_ALL_PHYS)) << RFAA_shift), ioaddr + rfcr); - - if (rx_mode & ACCEPT_ALL_ERRORS) { - rxCfgOn = RxAEP | RxARP | RxAJAB; - } else { - rxCfgOff = RxAEP | RxARP | RxAJAB; - } - if (rx_mode & MAC_LOOPBACK) { - rxCfgOn |= RxATP; - txCfgOn |= TxMLB; - } else { - if (!(( (struct sis900_private *)(dev->priv) )->full_duplex)) - rxCfgOff |= RxATP; - txCfgOff |= TxMLB; - } - - if (sis900_debug > 2) { - printk(KERN_INFO "Before Set TxCfg=%8.8x\n",inl(ioaddr+txcfg)); - printk(KERN_INFO "Before Set RxCfg=%8.8x\n",inl(ioaddr+rxcfg)); - } - - outl((inl(ioaddr + rxcfg) | rxCfgOn) & ~rxCfgOff, ioaddr + rxcfg); - outl((inl(ioaddr + txcfg) | txCfgOn) & ~txCfgOff, ioaddr + txcfg); - - if (sis900_debug > 2) { - printk(KERN_INFO "After Set TxCfg=%8.8x\n",inl(ioaddr+txcfg)); - printk(KERN_INFO "After Set RxCfg=%8.8x\n",inl(ioaddr+rxcfg)); - printk(KERN_INFO "Receive Filter Register:%8.8x\n", - inl(ioaddr + rfcr)); - } - return; + outl(RFEN | rx_mode, ioaddr + rfcr); + + /* sis900 is capatable of looping back packet at MAC level for debugging purpose */ + if (net_dev->flags & IFF_LOOPBACK) { + u32 cr_saved; + /* We must disable Tx/Rx before setting loopback mode */ + cr_saved = inl(ioaddr + cr); + outl(cr_saved | TxDIS | RxDIS, ioaddr + cr); + /* enable loopback */ + outl(inl(ioaddr + txcfg) | TxMLB, ioaddr + txcfg); + outl(inl(ioaddr + rxcfg) | RxATX, ioaddr + rxcfg); + /* restore cr */ + outl(cr_saved, ioaddr + cr); + } + + return; } -static void sis900_reset(struct net_device *dev) +static void sis900_reset(struct net_device *net_dev) { - long ioaddr = dev->base_addr; + long ioaddr = net_dev->base_addr; + int i = 0; + u32 status = TxRCMP | RxRCMP; - outl(0, ioaddr + ier); - outl(0, ioaddr + imr); - outl(0, ioaddr + rfcr); + outl(0, ioaddr + ier); + outl(0, ioaddr + imr); + outl(0, ioaddr + rfcr); - outl(RxRESET | TxRESET | RESET, ioaddr + cr); - outl(PESEL, ioaddr + cfg); + outl(RxRESET | TxRESET | RESET, ioaddr + cr); + + /* Check that the chip has finished the reset. */ + while (status && (i++ < 1000)) { + status ^= (inl(isr + ioaddr) & status); + } - set_rx_mode(dev); + outl(PESEL, ioaddr + cfg); } #ifdef MODULE int init_module(void) { - return sis900_probe(0); + return sis900_probe(NULL); } void cleanup_module(void) { - struct net_device *next_dev; - - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_sis900_dev) { - struct sis900_private *tp = - (struct sis900_private *)root_sis900_dev->priv; - next_dev = tp->next_module; - unregister_netdev(root_sis900_dev); - release_region(root_sis900_dev->base_addr, - pci_tbl[tp->chip_id].io_size); - kfree(tp); - kfree(root_sis900_dev); - root_sis900_dev = next_dev; - } + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_sis900_dev) { + struct sis900_private *sis_priv = + (struct sis900_private *)root_sis900_dev->priv; + struct net_device *next_dev = sis_priv->next_module; + + unregister_netdev(root_sis900_dev); + release_region(root_sis900_dev->base_addr, + sis_priv->mac->io_size); + kfree(sis_priv); + kfree(root_sis900_dev); + + root_sis900_dev = next_dev; + } } #endif /* MODULE */ -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sis900.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sis900.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/sis900.h b/drivers/net/sis900.h new file mode 100644 index 000000000000..3d3af5f9acb5 --- /dev/null +++ b/drivers/net/sis900.h @@ -0,0 +1,248 @@ +/* sis900.h Definitions for SiS ethernet controllers including 7014/7016 and 900 + * Copyright 1999 Silicon Integrated System Corporation + * References: + * SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support, + * preliminary Rev. 1.0 Jan. 14, 1998 + * SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support, + * preliminary Rev. 1.0 Nov. 10, 1998 + * SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution, + * preliminary Rev. 1.0 Jan. 18, 1998 + * http://www.sis.com.tw/support/databook.htm + */ + +/* MAC operationl registers of SiS 7016 and SiS 900 ehternet controller */ +/* The I/O extent, SiS 900 needs 256 bytes of io address */ +#define SIS900_TOTAL_SIZE 0x100 + +/* Symbolic offsets to registers. */ +enum sis900_registers { + cr=0x0, //Command Register + cfg=0x4, //Configuration Register + mear=0x8, //EEPROM Access Register + ptscr=0xc, //PCI Test Control Register + isr=0x10, //Interrupt Status Register + imr=0x14, //Interrupt Mask Register + ier=0x18, //Interrupt Enable Register + epar=0x18, //Enhanced PHY Access Register + txdp=0x20, //Transmit Descriptor Pointer Register + txcfg=0x24, //Transmit Configuration Register + rxdp=0x30, //Receive Descriptor Pointer Register + rxcfg=0x34, //Receive Configuration Register + flctrl=0x38, //Flow Control Register + rxlen=0x3c, //Receive Packet Length Register + rfcr=0x48, //Receive Filter Control Register + rfdr=0x4C, //Receive Filter Data Register + pmctrl=0xB0, //Power Management Control Register + pmer=0xB4 //Power Management Wake-up Event Register +}; + +/* Symbolic names for bits in various registers */ +enum sis900_command_register_bits { + RESET = 0x00000100, SWI = 0x00000080, RxRESET = 0x00000020, + TxRESET = 0x00000010, RxDIS = 0x00000008, RxENA = 0x00000004, + TxDIS = 0x00000002, TxENA = 0x00000001 +}; + +enum sis900_configuration_register_bits { + DESCRFMT = 0x00000100 /* 7016 specific */, REQALG = 0x00000080, + SB = 0x00000040, POW = 0x00000020, EXD = 0x00000010, + PESEL = 0x00000008, LPM = 0x00000004, BEM = 0x00000001 +}; + +enum sis900_eeprom_access_reigster_bits { + MDC = 0x00000040, MDDIR = 0x00000020, MDIO = 0x00000010, /* 7016 specific */ + EECS = 0x00000008, EECLK = 0x00000004, EEDO = 0x00000002, + EEDI = 0x00000001 +}; + +enum sis900_interrupt_register_bits { + WKEVT = 0x10000000, TxPAUSEEND = 0x08000000, TxPAUSE = 0x04000000, + TxRCMP = 0x02000000, RxRCMP = 0x01000000, DPERR = 0x00800000, + SSERR = 0x00400000, RMABT = 0x00200000, RTABT = 0x00100000, + RxSOVR = 0x00010000, HIBERR = 0x00008000, SWINT = 0x00001000, + MIBINT = 0x00000800, TxURN = 0x00000400, TxIDLE = 0x00000200, + TxERR = 0x00000100, TxDESC = 0x00000080, TxOK = 0x00000040, + RxORN = 0x00000020, RxIDLE = 0x00000010, RxEARLY = 0x00000008, + RxERR = 0x00000004, RxDESC = 0x00000002, RxOK = 0x00000001 +}; + +enum sis900_interrupt_enable_reigster_bits { + IE = 0x00000001 +}; + +/* maximum dma burst fro transmission and receive*/ +#define MAX_DMA_RANGE 7 /* actually 0 means MAXIMUM !! */ +#define TxMXDMA_shift 20 +#define RxMXDMA_shift 20 +#define TX_DMA_BURST 0 +#define RX_DMA_BURST 0 + +/* transmit FIFO threshholds */ +#define TX_FILL_THRESH 16 /* 1/4 FIFO size */ +#define TxFILLT_shift 8 +#define TxDRNT_shift 0 +#define TxDRNT_100 48 /* 3/4 FIFO size */ +#define TxDRNT_10 16 /* 1/2 FIFO size */ + +enum sis900_transmit_config_register_bits { + TxCSI = 0x80000000, TxHBI = 0x40000000, TxMLB = 0x20000000, + TxATP = 0x10000000, TxIFG = 0x0C000000, TxFILLT = 0x00003F00, + TxDRNT = 0x0000003F +}; + +/* recevie FIFO thresholds */ +#define RxDRNT_shift 1 +#define RxDRNT_100 24 /* 3/4 FIFO size */ +#define RxDRNT_10 16 /* 1/2 FIFO size */ + +enum sis900_reveive_config_register_bits { + RxAEP = 0x80000000, RxARP = 0x40000000, RxATX = 0x10000000, + RxAJAB = 0x08000000, RxDRNT = 0x0000007F +}; + +#define RFAA_shift 28 +#define RFADDR_shift 16 + +enum sis900_receive_filter_control_register_bits { + RFEN = 0x80000000, RFAAB = 0x40000000, RFAAM = 0x20000000, + RFAAP = 0x10000000, RFPromiscuous = (RFAAB|RFAAM|RFAAP) +}; + +enum sis900_reveive_filter_data_mask { + RFDAT = 0x0000FFFF +}; + +/* EEPROM Addresses */ +enum sis900_eeprom_address { + EEPROMSignature = 0x00, EEPROMVendorID = 0x02, EEPROMDeviceID = 0x03, + EEPROMMACAddr = 0x08, EEPROMChecksum = 0x0b +}; + +/* The EEPROM commands include the alway-set leading bit. Refer to NM93Cxx datasheet */ +enum sis900_eeprom_command { + EEread = 0x0180, EEwrite = 0x0140, EEerase = 0x01C0, + EEwriteEnable = 0x0130, EEwriteDisable = 0x0100, + EEeraseAll = 0x0120, EEwriteAll = 0x0110, + EEaddrMask = 0x013F, EEcmdShift = 16 +}; + +/* Manamgement Data I/O (mdio) frame */ +#define MIIread 0x6000 +#define MIIwrite 0x5002 +#define MIIpmdShift 7 +#define MIIregShift 2 +#define MIIcmdLen 16 +#define MIIcmdShift 16 + +/* Buffer Descriptor Status*/ +enum sis900_buffer_status { + OWN = 0x80000000, MORE = 0x40000000, INTR = 0x20000000, + SUPCRC = 0x10000000, INCCRC = 0x10000000, + OK = 0x08000000, DSIZE = 0x00000FFF +}; +/* Status for TX Buffers */ +enum sis900_tx_buffer_status { + ABORT = 0x04000000, UNDERRUN = 0x02000000, NOCARRIER = 0x01000000, + DEFERD = 0x00800000, EXCDEFER = 0x00400000, OWCOLL = 0x00200000, + EXCCOLL = 0x00100000, COLCNT = 0x000F0000 +}; + +enum sis900_rx_bufer_status { + OVERRUN = 0x02000000, DEST = 0x00800000, BCAST = 0x01800000, + MCAST = 0x01000000, UNIMATCH = 0x00800000, TOOLONG = 0x00400000, + RUNT = 0x00200000, RXISERR = 0x00100000, CRCERR = 0x00080000, + FAERR = 0x00040000, LOOPBK = 0x00020000, RXCOL = 0x00010000 +}; + +/* MII register offsets */ +enum mii_registers { + MII_CONTROL = 0x0000, MII_STATUS = 0x0001, MII_PHY_ID0 = 0x0002, + MII_PHY_ID1 = 0x0003, MII_ANADV = 0x0004, MII_ANLPAR = 0x0005, + MII_ANEXT = 0x0006 +}; + +/* mii registers specific to SiS 900 */ +enum sis_mii_registers { + MII_CONFIG1 = 0x0010, MII_CONFIG2 = 0x0011, MII_STSOUT = 0x0012, + MII_MASK = 0x0013 +}; + +/* mii registers specific to AMD 79C901 */ +enum amd_mii_registers { + MII_STATUS_SUMMARY = 0x0018 +}; + +/* MII Control register bit definitions. */ +enum mii_control_register_bits { + MII_CNTL_FDX = 0x0100, MII_CNTL_RST_AUTO = 0x0200, + MII_CNTL_ISOLATE = 0x0400, MII_CNTL_PWRDWN = 0x0800, + MII_CNTL_AUTO = 0x1000, MII_CNTL_SPEED = 0x2000, + MII_CNTL_LPBK = 0x4000, MII_CNTL_RESET = 0x8000 +}; + +/* MII Status register bit */ +enum mii_status_register_bits { + MII_STAT_EXT = 0x0001, MII_STAT_JAB = 0x0002, + MII_STAT_LINK = 0x0004, MII_STAT_CAN_AUTO = 0x0008, + MII_STAT_FAULT = 0x0010, MII_STAT_AUTO_DONE = 0x0020, + MII_STAT_CAN_T = 0x0800, MII_STAT_CAN_T_FDX = 0x1000, + MII_STAT_CAN_TX = 0x2000, MII_STAT_CAN_TX_FDX = 0x4000, + MII_STAT_CAN_T4 = 0x8000 +}; + +#define MII_ID1_OUI_LO 0xFC00 /* low bits of OUI mask */ +#define MII_ID1_MODEL 0x03F0 /* model number */ +#define MII_ID1_REV 0x000F /* model number */ + +/* MII NWAY Register Bits ... + valid for the ANAR (Auto-Negotiation Advertisement) and + ANLPAR (Auto-Negotiation Link Partner) registers */ +enum mii_nway_register_bits { + MII_NWAY_NODE_SEL = 0x001f, MII_NWAY_CSMA_CD = 0x0001, + MII_NWAY_T = 0x0020, MII_NWAY_T_FDX = 0x0040, + MII_NWAY_TX = 0x0080, MII_NWAY_TX_FDX = 0x0100, + MII_NWAY_T4 = 0x0200, MII_NWAY_PAUSE = 0x0400, + MII_NWAY_RF = 0x2000, MII_NWAY_ACK = 0x4000, + MII_NWAY_NP = 0x8000 +}; + +enum mii_stsout_register_bits { + MII_STSOUT_LINK_FAIL = 0x4000, + MII_STSOUT_SPD = 0x0080, MII_STSOUT_DPLX = 0x0040 +}; + +enum mii_stssum_register_bits { + MII_STSSUM_LINK = 0x0008, MII_STSSUM_DPLX = 0x0004, + MII_STSSUM_AUTO = 0x0002, MII_STSSUM_SPD = 0x0001 +}; + +#define FDX_CAPABLE_DUPLEX_UNKNOWN 0 +#define FDX_CAPABLE_HALF_SELECTED 1 +#define FDX_CAPABLE_FULL_SELECTED 2 + +#define HW_SPEED_UNCONFIG 0 +#define HW_SPEED_HOME 1 +#define HW_SPEED_10_MBPS 10 +#define HW_SPEED_100_MBPS 100 +#define HW_SPEED_DEFAULT (HW_SPEED_100_MBPS) + +#define CRC_SIZE 4 +#define MAC_HEADER_SIZE 14 + +#define TX_BUF_SIZE 1536 +#define RX_BUF_SIZE 1536 + +#define NUM_TX_DESC 16 /* Number of Tx descriptor registers. */ +#define NUM_RX_DESC 16 /* Number of Rx descriptor registers. */ + +#define TRUE 1 +#define FALSE 0 + +/* PCI stuff, should be move to pic.h */ +#define PCI_DEVICE_ID_SI_900 0x900 +#define PCI_DEVICE_ID_SI_7016 0x7016 + +/* ioctl for accessing MII transveiver */ +#define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Get the PHY in use. */ +#define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read a PHY register. */ +#define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write a PHY register */ diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 7c127fd18a8b..5a3288b9b8bd 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -137,7 +137,7 @@ struct parport *parport_enumerate(void) request_module ("parport_lowlevel"); if (portlist) /* The user has a parport_lowlevel alias in - * conf.modules. Warn them that it won't work + * modules.conf. Warn them that it won't work * for long. */ printk (KERN_WARNING "parport: 'parport_lowlevel' is deprecated; " diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 78328d5ee5b3..5ed076b513fe 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -299,6 +299,11 @@ static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup) scsi->pc = NULL; } +static inline unsigned long get_timeout(idescsi_pc_t *pc) +{ + return IDE_MAX(WAIT_CMD, pc->timeout - jiffies); +} + /* * Our interrupt handler. */ @@ -359,8 +364,7 @@ static void idescsi_pc_intr (ide_drive_t *drive) pc->actually_transferred += temp; pc->current_position += temp; idescsi_discard_data (drive,bcount - temp); - drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies); - ide_set_handler(drive, &idescsi_pc_intr); + ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL); return; } #if IDESCSI_DEBUG_LOG @@ -384,8 +388,7 @@ static void idescsi_pc_intr (ide_drive_t *drive) pc->actually_transferred+=bcount; /* Update the current position */ pc->current_position+=bcount; - drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies); - ide_set_handler(drive, &idescsi_pc_intr); /* And set the interrupt handler again */ + ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL); /* And set the interrupt handler again */ } static void idescsi_transfer_pc (ide_drive_t *drive) @@ -404,8 +407,7 @@ static void idescsi_transfer_pc (ide_drive_t *drive) ide_do_reset (drive); return; } - drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies); - ide_set_handler(drive, &idescsi_pc_intr); /* Set the interrupt routine */ + ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL); /* Set the interrupt routine */ atapi_output_bytes (drive, scsi->pc->c, 12); /* Send the actual packet */ } @@ -439,8 +441,7 @@ static void idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc) (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); } if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) { - drive->timeout = IDE_MAX(WAIT_CMD, pc->timeout - jiffies); - ide_set_handler (drive, &idescsi_transfer_pc); + ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ } else { OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 22e89c588879..ac92f89621f1 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -21,7 +21,7 @@ * support added by Michael Neuffer * * Added request_module("scsi_hostadapter") for kerneld: - * (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules) + * (Put an "alias scsi_hostadapter your_hostadapter" in /etc/modules.conf) * Bjorn Ekwall * (changed to kmod) * diff --git a/drivers/usb/CREDITS b/drivers/usb/CREDITS index bd804e6d98d8..04e67607c52a 100644 --- a/drivers/usb/CREDITS +++ b/drivers/usb/CREDITS @@ -10,7 +10,7 @@ difficult to maintain, add yourself with a patch if desired. Bradley M Keryan Paul Mackerras David E. Nelson - Vojtech Pavlik + Vojtech Pavlik Gregory P. Smith Linus Torvalds Roman Weissgaerber diff --git a/drivers/usb/README.dc2xx b/drivers/usb/README.dc2xx new file mode 100644 index 000000000000..48910d1b92f5 --- /dev/null +++ b/drivers/usb/README.dc2xx @@ -0,0 +1,105 @@ +3 November 1999 +david-b@pacbell.net + +This is an overview of how to use the "dc2xx" USB driver with certain +digital still cameras from Kodak and other vendors. + + +CAMERAS + +This driver will mostly be used with Kodak DC-2xx series digital still +cameras, but it should be trivial to tell it about several non-Kodak +USB-enabled cameras. + +You'll most likely want to hook it up to recent versions of "gPhoto" +(www.gphoto.org), since version 0.4 and later know how to use it to talk +to Kodak DC-240 and DC-280 cameras over USB. + +The DC-260 is currently recognized. However, like other cameras using the +"Digita OS" (from www.flashpoint.com) there is no application software +(such as gPhoto) support for this camera. Until it's available, those +cameras aren't much use with Linux; when it's available, this driver +should be able to handle the cameras' communication requirements. Today, +that's six more cameras. From Kodak: DC-220, DC-260, DC-265, DC-290. +Minolta has the Dimage EX-1500; HP, the PhotoSmart C500. + +It's likely that other digital still cameras can also use this USB driver, +even if they're not from Kodak and don't use Digita. The reason is that +most currently known USB still camera protocols treat USB like a faster +packet-carrying connection than a serial line, which is exactly how this +driver looks to an application. + + +USB HARDWARE + +This has been shown to work on x86 OHCI and UHCI (Intel) chipsets. OHCI has +been trouble free; not so with UHCI, which was first seen to be happy with +2.3.24 kernels. + +As yet, no reports have come from Linux users on non-Intel hardware. +(You could color coordinate your iMac with a DC-240i ... :-) + + +SETUP + +Configure in the DC2XX USB driver, and have it in your kernel. Recently I +compile it right in, but I've done it as a module in the past. + +Create a device, perhaps like this (both read and write): + + # mknod -m 0666 /dev/kodak c 10 170 + +That "170" is not formally assigned, and this command may change. If you're +using a non-Kodak camera, you may prefer another name. + +Don't plug in more than one compatible camera at this time. One of them +will be ignored, but I'd not be sure which one! + + +SANITY TESTING + +First: if you've got /proc support, make sure that the driver has hooked +itself up correctly. + + - you should see an entry in /proc/misc for the a Kodak DC-2xx + minor device number + + - you should see an entry in /proc/bus/usb/drivers for "dc2xx", + if you also enabled USB /proc support. + +Second: when you connect your camera to the computer, does it get recognized +by the driver? + + - if you've got /proc/bus/usb/devices, you should see an entry + something like this. The "ProdID" may be different if you didn't + plug in a DC-240, but the "Driver=dc2xx" had better be there. + + T: Lev=01 Prnt=00 Port=00 Cnt=01 Dev#= 1 Spd=12 MxCh= 0 + D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 + P: Vendor=040a ProdID=0120 Rev= 1.08 + C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=100mA + I: If#= 0 Alt= 0 #EPs= 2 Cls=00(>ifc ) Sub=00 Prot=00 Driver=dc2xx + E: Ad=01(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms + E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms + + - if you don't have /proc support for USB, see if "dmesg" output + tells you that you plugged in your camera. + + USB new device connect, assigned device number 1 + Manufacturer: Eastman Kodak Company + Product: KODAK DC240 Zoom Digital Camera + USB Camera (Kodak DC-240) is connected + usbcore: dc2xx driver claimed interface c3a68600 + ohci-control thread sleeping + +Third: (optional) can you use gPhoto to talk to the camera? + + - When you configure your camera, tell it to use "/dev/kodak" (or + whatever name you used). Right now, gPhoto emits a diagnostic + message (non-GUI) saying that it since it didn't act like a TTY, + it's assuming it's got a USB connection. + + - With the camera turned on, get the "camera summary". It'll + talk to the camera -- and tell you you're using USB. + +If you got that far, you should be able to use everything fine. diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c index c843b73f4eb1..8fca7562cf04 100644 --- a/drivers/usb/acm.c +++ b/drivers/usb/acm.c @@ -1,7 +1,9 @@ /* - * USB Abstract Control Model based on Brad Keryan's USB busmouse driver + * USB Abstract Control Model based on Brad Keryan's USB busmouse driver * - * Armin Fuerst 5/8/1999 + * (C) Copyright 1999 Armin Fuerst + * (C) Copyright 1999 Pavel Machek + * (C) Copyright 1999 Johannes Erdfelt * * version 0.8: Fixed endianity bug, some cleanups. I really hate to have * half of driver in form if (...) { info("x"); return y; } @@ -11,7 +13,7 @@ * wrote this code? ...Oops that was me). Fixed module cleanup. Did some * testing at 3Com => zmodem uload+download works, pppd had trouble but * seems to work now. Changed Menuconfig texts "Communications Device - * Class (ACM)" might be a bit more intuitive. Ported to 2.3.13-1 prepatch. + * Class (ACM)" might be a bit more intuitive. Ported to 2.3.13-1 prepatch. * (2/8/99) * * version 0.6: Modularized driver, added disconnect code, improved @@ -23,8 +25,8 @@ * in uhci_td_allocate. Commenetd out getstringtable which causes crash. * (13/7/99) * - * version 0.4: Small fixes in the FIFO, cleanup. Updated Bulk transfer in - * uhci.c. Should have the correct interface now. + * version 0.4: Small fixes in the FIFO, cleanup. Updated Bulk transfer in + * uhci.c. Should have the correct interface now. * (6/6/99) * * version 0.3: Major changes. Changed Bulk transfer to interrupt based @@ -60,15 +62,14 @@ #include #include #include -#include #include "usb.h" #define NR_PORTS 3 #define ACM_MAJOR 166 /* Wow, major is now officially allocated */ -//#define info(message...); printk(message); -#define info(message...); +//#define info(message...) printk(KERN_DEBUG message) +#define info(message...) #define CTRL_STAT_DTR 1 #define CTRL_STAT_RTS 2 @@ -88,7 +89,7 @@ struct acm_state { int cfgnum; //configuration number on this device struct tty_struct *tty; //the coresponding tty char present; //a device for this struct was detected => this tty is used - char active; //someone has this acm's device open + char active; //someone has this acm's device open unsigned int ctrlstate; //Status of the serial control lines (handshake,...) unsigned int linecoding; //Status of the line coding (Bits, Stop, Parity) int writesize, readsize; //size of the usb buffers @@ -105,56 +106,56 @@ struct acm_state { //functions for various ACM requests -void Set_Control_Line_Status (unsigned int status,struct acm_state *acm) +void Set_Control_Line_Status(unsigned int status, struct acm_state *acm) { - devrequest dr; + struct usb_device *dev = acm->dev; + int ret; info("Set_control_Line_Status\n"); - dr.requesttype = 0x22; - dr.request = 0x22; - dr.value = status; - dr.index = 0; - dr.length = 0; - acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev,0), &dr, NULL, 0, HZ); + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x22, 0x22, + status, 0, NULL, 0, HZ); + if (ret < 0) + printk(KERN_ERR "acm: Set_Control_Line_Status failed\n"); - acm->ctrlstate=status; + acm->ctrlstate = status; } -void Set_Line_Coding (unsigned int coding,struct acm_state *acm) +void Set_Line_Coding(unsigned int coding, struct acm_state *acm) { - devrequest dr; + struct usb_device *dev = acm->dev; + int ret; info("Set_Line_Coding\n"); - dr.requesttype = 0x22; - dr.request = 0x30; - dr.value = coding; - dr.index = 0; - dr.length = 0; - acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev,0), &dr, NULL, 0, HZ); - - acm->linecoding=coding; + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x30, 0x22, + coding, 0, NULL, 0, HZ); + + acm->linecoding = coding; } //Interrupt handler for various usb events static int acm_irq(int state, void *__buffer, int count, void *dev_id) { - unsigned char *data; - struct acm_state *acm = (struct acm_state *) dev_id; + struct acm_state *acm = (struct acm_state *)dev_id; devrequest *dr; - + info("ACM_USB_IRQ\n"); + if (state) { + printk(KERN_DEBUG "acm_irq: strange state received: %x\n", state); + return 0; + } + if (!acm->present) return 0; if (!acm->active) return 1; - - dr=__buffer; - data=__buffer; - data+=sizeof(dr); + + dr = __buffer; + data = __buffer; + data += sizeof(dr); #if 0 printk("reqtype: %02X\n",dr->requesttype); @@ -163,23 +164,23 @@ static int acm_irq(int state, void *__buffer, int count, void *dev_id) printk("wIndex: %02X\n",dr->index); printk("wLength: %02X\n",dr->length); #endif - + switch(dr->request) { case 0x00: /* Network connection */ - printk("Network connection: "); - if (dr->request==0) printk("disconnected\n"); - if (dr->request==1) printk("connected\n"); + printk(KERN_DEBUG "Network connection: "); + if (dr->request==0) printk(KERN_DEBUG "disconnected\n"); + if (dr->request==1) printk(KERN_DEBUG "connected\n"); break; - + case 0x01: /* Response available */ - printk("Response available\n"); + printk(KERN_DEBUG "Response available\n"); break; - + case 0x20: /* Set serial line state */ - printk("acm.c: Set serial control line state\n"); - if ((dr->index==1)&&(dr->length==2)) { + printk(KERN_DEBUG "acm.c: Set serial control line state\n"); + if ((dr->index==1) && (dr->length==2)) { acm->ctrlstate= data[0] || (data[1] << 16); - printk("Serstate: %02X\n",acm->ctrlstate); + printk(KERN_DEBUG "Serstate: %02X\n",acm->ctrlstate); } break; } @@ -197,7 +198,7 @@ static int acm_read_irq(int state, void *__buffer, int count, void *dev_id) info("ACM_READ_IRQ: state %d, %d bytes\n", state, count); if (state) { printk( "acm_read_irq: strange state received: %x\n", state ); - return 0; + return 1; } if (!ACM_READY) @@ -207,13 +208,13 @@ static int acm_read_irq(int state, void *__buffer, int count, void *dev_id) tty_insert_flip_char(tty,data[i],0); tty_flip_buffer_push(tty); - return 0; /* Never return 1 from this routine. It makes uhci do bad things. */ + return 1; } static int acm_write_irq(int state, void *__buffer, int count, void *dev_id) { - struct acm_state *acm = (struct acm_state *) dev_id; - struct tty_struct *tty = acm->tty; + struct acm_state *acm = (struct acm_state *) dev_id; + struct tty_struct *tty = acm->tty; info("ACM_WRITE_IRQ\n"); @@ -221,24 +222,25 @@ static int acm_write_irq(int state, void *__buffer, int count, void *dev_id) return 0; /* stop transfer */ usb_terminate_bulk(acm->dev, acm->writetransfer); - acm->writing=0; + acm->writing = 0; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); - + return 0; /* stop tranfer */ } /*TTY STUFF*/ -static int rs_open(struct tty_struct *tty, struct file * filp) +static int rs_open(struct tty_struct *tty, struct file *filp) { struct acm_state *acm; int ret; - + info("USB_FILE_OPEN\n"); - tty->driver_data=acm=&acm_state_table[MINOR(tty->device)-tty->driver.minor_start]; - acm->tty=tty; + tty->driver_data = acm = + &acm_state_table[MINOR(tty->device) - tty->driver.minor_start]; + acm->tty = tty; if (!acm->present) return -EINVAL; @@ -246,139 +248,147 @@ static int rs_open(struct tty_struct *tty, struct file * filp) if (acm->active++) return 0; + MOD_INC_USE_COUNT; + /* Start reading from the device */ - ret = usb_request_irq(acm->dev,acm->ctrlpipe, acm_irq, acm->ctrlinterval, acm, &acm->ctrltransfer); + ret = usb_request_irq(acm->dev, acm->ctrlpipe, acm_irq, + acm->ctrlinterval, acm, &acm->ctrltransfer); if (ret) - printk (KERN_WARNING "usb-acm: usb_request_irq failed (0x%x)\n", ret); - acm->reading=1; - acm->readtransfer=usb_request_bulk(acm->dev,acm->readpipe, acm_read_irq, acm->readbuffer, acm->readsize, acm); - - Set_Control_Line_Status (CTRL_STAT_DTR | CTRL_STAT_RTS, acm); - + printk(KERN_ERR "usb-acm: usb_request_irq failed (0x%x)\n", ret); + acm->reading = 1; + acm->readtransfer = usb_request_bulk(acm->dev, acm->readpipe, + acm_read_irq, acm->readbuffer, acm->readsize, acm); + + Set_Control_Line_Status(CTRL_STAT_DTR | CTRL_STAT_RTS, acm); + return 0; } -static void rs_close(struct tty_struct *tty, struct file * filp) +static void rs_close(struct tty_struct *tty, struct file *filp) { - struct acm_state *acm = (struct acm_state *) tty->driver_data; + struct acm_state *acm = (struct acm_state *) tty->driver_data; + info("rs_close\n"); - + if (!acm->present) return; if (--acm->active) return; - Set_Control_Line_Status (0, acm); - - if (acm->writing){ + Set_Control_Line_Status(0, acm); + + if (acm->writing) { usb_terminate_bulk(acm->dev, acm->writetransfer); - acm->writing=0; + acm->writing = 0; } - if (acm->reading){ + if (acm->reading) { usb_terminate_bulk(acm->dev, acm->readtransfer); - acm->reading=0; + acm->reading = 0; } -// usb_release_irq(acm->dev,acm->ctrltransfer, acm->ctrlpipe); +// usb_release_irq(acm->dev, acm->ctrltransfer, acm->ctrlpipe); + + MOD_DEC_USE_COUNT; } -static int rs_write(struct tty_struct * tty, int from_user, +static int rs_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) { - struct acm_state *acm = (struct acm_state *) tty->driver_data; + struct acm_state *acm = (struct acm_state *)tty->driver_data; int written; - + info("rs_write\n"); if (!ACM_READY) return -EINVAL; - + if (acm->writing) { - info ("already writing\n"); + info("already writing\n"); return 0; } - written=(count>acm->writesize) ? acm->writesize : count; - - if (from_user) copy_from_user(acm->writebuffer,buf,written); - else memcpy(acm->writebuffer,buf,written); + written = (count>acm->writesize) ? acm->writesize : count; + + if (from_user) + copy_from_user(acm->writebuffer, buf, written); + else + memcpy(acm->writebuffer, buf, written); //start the transfer - acm->writing=1; - acm->writetransfer=usb_request_bulk(acm->dev,acm->writepipe, acm_write_irq, acm->writebuffer, written, acm); + acm->writing = 1; + acm->writetransfer = usb_request_bulk(acm->dev, acm->writepipe, + acm_write_irq, acm->writebuffer, written, acm); return written; } static void rs_put_char(struct tty_struct *tty, unsigned char ch) { - struct acm_state *acm = (struct acm_state *) tty->driver_data; - - printk( "acm: rs_put_char: Who called this unsupported routine?\n" ); + printk(KERN_DEBUG "acm: rs_put_char: Who called this unsupported routine?\n"); BUG(); -} +} -static int rs_write_room(struct tty_struct *tty) +static int rs_write_room(struct tty_struct *tty) { - struct acm_state *acm = (struct acm_state *) tty->driver_data; + struct acm_state *acm = (struct acm_state *) tty->driver_data; info("rs_write_room\n"); - + if (!ACM_READY) return -EINVAL; - + return acm->writing ? 0 : acm->writesize; } -static int rs_chars_in_buffer(struct tty_struct *tty) +static int rs_chars_in_buffer(struct tty_struct *tty) { - struct acm_state *acm = (struct acm_state *) tty->driver_data; + struct acm_state *acm = (struct acm_state *) tty->driver_data; // info("rs_chars_in_buffer\n"); - + if (!ACM_READY) return -EINVAL; - - return acm->writing ? acm->writesize : 0; + + return acm->writing ? acm->writesize : 0; } -static void rs_throttle(struct tty_struct * tty) +static void rs_throttle(struct tty_struct *tty) { - struct acm_state *acm = (struct acm_state *) tty->driver_data; - + struct acm_state *acm = (struct acm_state *) tty->driver_data; + info("rs_throttle\n"); - + if (!ACM_READY) return; -/* +/* if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); -*/ +*/ if (tty->termios->c_cflag & CRTSCTS) - Set_Control_Line_Status (acm->ctrlstate & ~CTRL_STAT_RTS, acm); + Set_Control_Line_Status(acm->ctrlstate & ~CTRL_STAT_RTS, acm); } -static void rs_unthrottle(struct tty_struct * tty) +static void rs_unthrottle(struct tty_struct *tty) { - struct acm_state *acm = (struct acm_state *) tty->driver_data; - + struct acm_state *acm = (struct acm_state *) tty->driver_data; + info("rs_unthrottle\n"); - + if (!ACM_READY) return; -/* +/* if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); -*/ +*/ if (tty->termios->c_cflag & CRTSCTS) - Set_Control_Line_Status (acm->ctrlstate | CTRL_STAT_RTS, acm); + Set_Control_Line_Status(acm->ctrlstate | CTRL_STAT_RTS, acm); } static int get_free_acm(void) { int i; - for (i=0;idescriptor.bNumConfigurations;cfgnum++) { /* The first one should be Communications interface? */ interface = &dev->config[cfgnum].interface[0].altsetting[0]; if (IFCLASS(interface) != 0x02020101) continue; - /*Which uses an interrupt input */ + /* Which uses an interrupt input */ endpoint = &interface->endpoint[0]; if ((endpoint->bEndpointAddress & 0x80) != 0x80 || (endpoint->bmAttributes & 3) != 3) @@ -540,13 +550,12 @@ static struct usb_driver acm_driver = { int usb_acm_init(void) { int cnt; - + info("usb_acm_init\n"); - + //INITIALIZE GLOBAL DATA STRUCTURES - for (cnt=0;cnt @@ -60,6 +61,7 @@ /* XXX need to get registered minor number, cdev 10/MINOR */ +/* XXX or: cdev USB_MAJOR(180)/USB_CAMERA_MINOR */ #define USB_CAMERA_MINOR 170 @@ -75,43 +77,56 @@ static struct camera { short idVendor; short idProduct; + + /* should get this name from the USB subsystem */ const char *nameProduct; } cameras [] = { { 0x040a, 0x0120, "Kodak DC-240" }, { 0x040a, 0x0130, "Kodak DC-280" }, - /* Kodak has several other USB-enabled cameras, which (along with + /* Kodak has several other USB-enabled devices, which (along with * models from other vendors) all use the Flashpoint "Digita * OS" and its wire protocol. This driver should work with such - * cameras, which need different application level protocol code - * from the DC-240/280 models. + * devices, which need different application level protocol code + * from the DC-240/280 models. Note that Digita isn't just for + * cameras -- Epson has a non-USB Digita photo printer. */ /* { 0x040a, 0x0100, "Kodak DC-220" }, */ { 0x040a, 0x0110, "Kodak DC-260" }, /* { 0x040a, 0x0115, "Kodak DC-265" }, */ /* { 0x040a, 0x0140, "Kodak DC-290" }, */ + /* { 0xffff, 0xffff, "Minolta Dimage EX 1500" }, */ -/* { 0xffff, 0xffff, "HP PhotoSmart C500" }, */ +/* { 0x03f0, 0xffff, "HP PhotoSmart C500" }, */ + + /* Other USB cameras may well work here too, so long as they + * just stick to half duplex packet exchanges. + */ }; -/* For now, we only support one camera at a time: there's one - * application-visible device (e.g. /dev/kodak) and the second - * camera detected on the bus is ignored. - */ -static struct camera_state { +struct camera_state { /* these fields valid (dev != 0) iff camera connected */ struct usb_device *dev; /* USB device handle */ char inEP; /* read endpoint */ char outEP; /* write endpoint */ struct camera *info; /* DC-240, etc */ + /* valid iff isOpen */ int isOpen; /* device opened? */ int isActive; /* I/O taking place? */ char *buf; /* buffer for I/O */ + /* always valid */ wait_queue_head_t wait; /* for timed waits */ -} static_camera_state; +}; + + +/* For now, we only support one camera at a time: there's one + * application-visible device (e.g. /dev/kodak) and the second + * (to Nth) camera detected on the bus is ignored. + */ +static struct camera_state static_camera_state; static ssize_t camera_read (struct file *file, @@ -128,7 +143,8 @@ static ssize_t camera_read (struct file *file, /* Big reads are common, for image downloading. Smaller ones * are also common (even "directory listing" commands don't - * send very much data). We preserve packet boundaries here. + * send very much data). We preserve packet boundaries here, + * they matter in the application protocol. */ for (retries = 0; retries < MAX_READ_RETRY; retries++) { unsigned long count; @@ -293,7 +309,7 @@ static int camera_release (struct inode *inode, struct file *file) /* XXX should define some ioctls to expose camera type * to applications ... what USB exposes should suffice. - * Perhaps there's a packet size limitation too? + * apps should be able to see the camera type. */ static struct file_operations usb_camera_fops = { NULL, /* llseek */ @@ -314,17 +330,20 @@ static struct file_operations usb_camera_fops = { }; static struct miscdevice usb_camera = { - USB_CAMERA_MINOR, "USB camera (Kodak DC-2xx)", &usb_camera_fops + USB_CAMERA_MINOR, + "USB camera (Kodak DC-2xx)", + &usb_camera_fops }; -static int camera_probe(struct usb_device *dev) +static void * camera_probe(struct usb_device *dev, unsigned int ifnum) { int i; struct camera *camera_info = NULL; - struct usb_interface_descriptor *intf_desc; + struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; + struct camera_state *camera = &static_camera_state; /* Is it a supported camera? */ @@ -337,27 +356,28 @@ static int camera_probe(struct usb_device *dev) break; } if (camera_info == NULL) - return -1; + return NULL; /* these have one config, one interface */ if (dev->descriptor.bNumConfigurations != 1 || dev->config[0].bNumInterfaces != 1) { printk (KERN_INFO "Bogus camera config info\n"); - return -1; + return NULL; } /* the interface class bit is odd -- the dc240 and dc260 return * a zero there, and at least some dc280s report 0xff */ - intf_desc = &dev->config[0].interface[0].altsetting[0]; - if ((intf_desc->bInterfaceClass != 0 - && intf_desc->bInterfaceClass != 0xff) - || intf_desc->bInterfaceSubClass != 0 - || intf_desc->bInterfaceProtocol != 0 - || intf_desc->bNumEndpoints != 2 + // interface = &dev->config[0].interface[0].altsetting[0]; + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + if ((interface->bInterfaceClass != 0 + && interface->bInterfaceClass != 0xff) + || interface->bInterfaceSubClass != 0 + || interface->bInterfaceProtocol != 0 + || interface->bNumEndpoints != 2 ) { printk (KERN_INFO "Bogus camera interface info\n"); - return -1; + return NULL; } /* can only show one camera at a time through /dev ... */ @@ -368,11 +388,13 @@ static int camera_probe(struct usb_device *dev) } else { printk(KERN_INFO "Ignoring additional USB Camera (%s)\n", camera_info->nameProduct); - return -1; + return NULL; } +// XXX there are now masks for these constants ... see printer.c + /* get input and output endpoints (either order) */ - endpoint = intf_desc->endpoint; + endpoint = interface->endpoint; camera->outEP = camera->inEP = -1; if ((endpoint [0].bEndpointAddress & 0x80) == 0x80) camera->inEP = endpoint [0].bEndpointAddress & 0x7f; @@ -389,35 +411,33 @@ static int camera_probe(struct usb_device *dev) ) { printk (KERN_INFO "Bogus camera endpoints\n"); camera->dev = NULL; - return -1; + return NULL; } if (usb_set_configuration (dev, dev->config[0].bConfigurationValue)) { printk (KERN_INFO "Failed usb_set_configuration: camera\n"); camera->dev = NULL; - return -1; + return NULL; } camera->info = camera_info; - return 0; + return camera; } -static void camera_disconnect(struct usb_device *dev) +static void camera_disconnect(struct usb_device *dev, void *ptr) { - struct camera_state *camera = &static_camera_state; + struct camera_state *camera = (struct camera_state *) ptr; struct camera *info = camera->info; if (camera->dev != dev) return; - /* Because this (currently) gets called whenever the USB bus - * gets reconfigured (e.g. loading a new USB device driver) - * we aren't reflecting this up to userland, though maybe - * that'd be better. The good consequence is bus reconfig - * not breaking apps, and the ability to remove camera for + /* Currently not reflecting this up to userland; at one point + * it got called on bus reconfig, which we clearly don't want. + * A good consequence is the ability to remove camera for * a while without apps needing to do much more than ignore - * some particular error returns. On the bad side, if the + * some particular error returns. On the bad side, if one * camera is swapped for another one, we won't be telling. */ camera->info = NULL; @@ -430,7 +450,10 @@ static struct usb_driver camera_driver = { "dc2xx", camera_probe, camera_disconnect, - { NULL, NULL } + { NULL, NULL }, + + NULL, /* &usb_camera_fops, */ + 0 /* USB_CAMERA_MINOR */ }; @@ -446,8 +469,9 @@ int usb_dc2xx_init(void) camera->isActive = 0; init_waitqueue_head (&camera->wait); + if (usb_register (&camera_driver) < 0) + return -1; misc_register (&usb_camera); - usb_register (&camera_driver); return 0; } diff --git a/drivers/usb/ezusb.c b/drivers/usb/ezusb.c index d3a610259f22..cabfb1d9af4a 100644 --- a/drivers/usb/ezusb.c +++ b/drivers/usb/ezusb.c @@ -311,7 +311,7 @@ static ssize_t ezusb_read(struct file *file, char *buf, size_t sz, loff_t *ppos) if (pos + len > 0x10000) len = 0x10000 - pos; i = usb_control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), 0xa0, 0xc0, pos, 0, b, len, HZ); - if (i) { + if (i < 0) { up(&ez->mutex); printk(KERN_WARNING "ezusb: upload failed pos %u len %u ret %d\n", pos, len, i); *ppos = pos; @@ -366,7 +366,7 @@ static ssize_t ezusb_write(struct file *file, const char *buf, size_t sz, loff_t return -EFAULT; } i = usb_control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), 0xa0, 0x40, pos, 0, b, len, HZ); - if (i) { + if (i < 0) { up(&ez->mutex); printk(KERN_WARNING "ezusb: download failed pos %u len %u ret %d\n", pos, len, i); *ppos = pos; @@ -1052,12 +1052,8 @@ int ezusb_init(void) init_waitqueue_head(&ezusb[u].wait); spin_lock_init(&ezusb[u].lock); } - if (usb_register(&ezusb_driver) < 0) { - printk(KERN_ERR "EZUSB driver cannot register: " - "minor number %d already in use\n", - ezusb_driver.minor); + if (usb_register(&ezusb_driver) < 0) return -1; - } printk(KERN_INFO "ezusb: Anchorchip firmware download driver registered\n"); return 0; diff --git a/drivers/usb/hp_scanner.c b/drivers/usb/hp_scanner.c index 288d461e53c4..c25f6af09279 100644 --- a/drivers/usb/hp_scanner.c +++ b/drivers/usb/hp_scanner.c @@ -299,12 +299,8 @@ usb_driver scanner_driver = { int usb_hp_scanner_init(void) { - if (usb_register(&scanner_driver) < 0) { - printk(KERN_ERR "USB scanner driver cannot register: " - "minor number %d already in use\n", - scanner_driver.minor); + if (usb_register(&scanner_driver) < 0) return -1; - } printk(KERN_DEBUG "USB Scanner support registered.\n"); return 0; diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c index f4b037f70b1d..385b074f1e8c 100644 --- a/drivers/usb/hub.c +++ b/drivers/usb/hub.c @@ -105,7 +105,7 @@ static int usb_hub_configure(struct usb_hub *hub) int i; /* Get the length first */ - if (usb_get_hub_descriptor(dev, buffer, 4)) + if (usb_get_hub_descriptor(dev, buffer, 4) < 0) return -1; header = (struct usb_descriptor_header *)buffer; @@ -113,7 +113,7 @@ static int usb_hub_configure(struct usb_hub *hub) if (!bitmap) return -1; - if (usb_get_hub_descriptor(dev, bitmap, header->bLength)) + if (usb_get_hub_descriptor(dev, bitmap, header->bLength) < 0) return -1; descriptor = (struct usb_hub_descriptor *)bitmap; @@ -166,7 +166,7 @@ static int usb_hub_configure(struct usb_hub *hub) kfree(bitmap); - if (usb_get_hub_status(dev, buffer)) + if (usb_get_hub_status(dev, buffer) < 0) return -1; hubsts = (struct usb_hub_status *)buffer; @@ -305,7 +305,7 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port) wait_ms(50); /* FIXME: This is from the *BSD stack, thanks! :) */ /* Check status */ - if (usb_get_port_status(hub, port + 1, &portsts)) { + if (usb_get_port_status(hub, port + 1, &portsts) < 0) { printk(KERN_ERR "get_port_status failed\n"); return; } @@ -377,7 +377,7 @@ static void usb_hub_events(void) struct usb_port_status portsts; unsigned short portstatus, portchange; - if (usb_get_port_status(dev, i + 1, &portsts)) { + if (usb_get_port_status(dev, i + 1, &portsts) < 0) { printk(KERN_ERR "get_port_status failed\n"); continue; } @@ -474,12 +474,8 @@ int usb_hub_init(void) { int pid; - if (usb_register(&hub_driver) < 0) { - printk(KERN_ERR "USB hub driver cannot register: " - "minor number %d already in use\n", - hub_driver.minor); + if (usb_register(&hub_driver) < 0) return -1; - } pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); @@ -492,7 +488,7 @@ int usb_hub_init(void) /* Fall through if kernel_thread failed */ usb_deregister(&hub_driver); - return 1; + return -1; } void usb_hub_cleanup(void) diff --git a/drivers/usb/keyboard.c b/drivers/usb/keyboard.c index 66f675abf088..86efde519871 100644 --- a/drivers/usb/keyboard.c +++ b/drivers/usb/keyboard.c @@ -256,14 +256,7 @@ usb_kbd_disconnect(struct usb_device *dev, void *ptr) int usb_kbd_init(void) { - if (usb_register(&usb_kbd_driver) < 0) { - printk(KERN_ERR "USB keyboard driver cannot register: " - "minor number %d already in use\n", - usb_kbd_driver.minor); - return -1; - } - - return 0; + return usb_register(&usb_kbd_driver); } void usb_kbd_cleanup(void) diff --git a/drivers/usb/mouse.c b/drivers/usb/mouse.c index 10f24d8d9eee..176dbd768151 100644 --- a/drivers/usb/mouse.c +++ b/drivers/usb/mouse.c @@ -410,12 +410,8 @@ int usb_mouse_init(void) init_waitqueue_head(&mouse->wait); mouse->fasync = NULL; - if (usb_register(&mouse_driver) < 0) { - printk(KERN_ERR "USB mouse driver cannot register: " - "minor number %d already in use\n", - mouse_driver.minor); + if (usb_register(&mouse_driver) < 0) return -1; - } printk(KERN_INFO "USB HID boot protocol mouse driver registered.\n"); return 0; diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index c1bd2b3cfb8d..3a26bf3aeeb4 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -419,12 +419,8 @@ static struct usb_driver printer_driver = { int usb_printer_init(void) { - if (usb_register(&printer_driver)) { - printk(KERN_ERR "USB Printer driver cannot register: " - "minor number %d already in use\n", - printer_driver.minor); + if (usb_register(&printer_driver)) return -1; - } printk(KERN_INFO "USB Printer support registered.\n"); return 0; diff --git a/drivers/usb/proc_usb.c b/drivers/usb/proc_usb.c index 332e9c0efd1d..628f19555174 100644 --- a/drivers/usb/proc_usb.c +++ b/drivers/usb/proc_usb.c @@ -968,27 +968,16 @@ static struct inode_operations proc_usb_device_inode_operations = { NULL /* revalidate */ }; -#define PROCUSB_MAXBUSSES 64 - -static unsigned long busnumbermap[(PROCUSB_MAXBUSSES+8 * sizeof(unsigned long)-1) / (8 * sizeof(unsigned long))] = { 0, }; - void proc_usb_add_bus(struct usb_bus *bus) { - int bnum; char buf[16]; - bus->proc_busnum = -1; bus->proc_entry = NULL; if (!usbdir) return; - bnum = find_first_zero_bit(busnumbermap, PROCUSB_MAXBUSSES); - if (bnum >= PROCUSB_MAXBUSSES) - return; - sprintf(buf, "%03d", bnum); + sprintf(buf, "%03d", bus->busnum); if (!(bus->proc_entry = create_proc_entry(buf, S_IFDIR, usbdir))) return; - set_bit(bnum, busnumbermap); - bus->proc_busnum = bnum; bus->proc_entry->data = bus; } @@ -998,7 +987,6 @@ void proc_usb_remove_bus(struct usb_bus *bus) if (!bus->proc_entry) return; remove_proc_entry(bus->proc_entry->name, usbdir); - clear_bit(bus->proc_busnum, busnumbermap); } void proc_usb_add_device(struct usb_device *dev) diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c index 25b2b303c108..b1895fce78b4 100644 --- a/drivers/usb/uhci.c +++ b/drivers/usb/uhci.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -73,20 +74,20 @@ static LIST_HEAD(uhci_list); * function prototypes */ -static int uhci_get_current_frame_number (struct usb_device *usb_dev); +static int uhci_get_current_frame_number(struct usb_device *usb_dev); -static int uhci_init_isoc (struct usb_device *usb_dev, +static int uhci_init_isoc(struct usb_device *usb_dev, unsigned int pipe, int frame_count, void *context, struct usb_isoc_desc **isocdesc); -static void uhci_free_isoc (struct usb_isoc_desc *isocdesc); +static void uhci_free_isoc(struct usb_isoc_desc *isocdesc); -static int uhci_run_isoc (struct usb_isoc_desc *isocdesc, +static int uhci_run_isoc(struct usb_isoc_desc *isocdesc, struct usb_isoc_desc *pr_isocdesc); -static int uhci_kill_isoc (struct usb_isoc_desc *isocdesc); +static int uhci_kill_isoc(struct usb_isoc_desc *isocdesc); /* * Map status to standard result codes @@ -123,15 +124,12 @@ static int uhci_map_status(int status, int dir_out) /* * Return the result of a TD.. */ -static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned long *rval, int debug) +static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned long *rval) { unsigned int status; struct uhci_td *tmp; int count = 1000, actlength, explength; - if (rval) - *rval = 0; - /* Start at the TD first in the chain, if possible */ if (td->qh && td->qh->first) tmp = td->qh->first; @@ -141,6 +139,9 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned if (!tmp) return USB_ST_INTERNALERROR; + if (rval) + *rval = 0; + /* Locate the first failing td, if any */ do { status = uhci_status_bits(tmp->status); @@ -154,12 +155,12 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned actlength = uhci_actual_length(tmp->status); if (rval) *rval += actlength; - /* This check is bogus, at least for acm. It - always expects 64, but gets as many bytes - as available (typically 1) -- pavel */ - if (0 && (explength != actlength)) { - /* Reset the data toggle on error. */ - if (debug || uhci_debug) + + if (explength != actlength) { + /* If the packet is short, none of the */ + /* packets after this were processed, so */ + /* fix the DT accordingly */ + if (in_interrupt() || uhci_debug) printk(KERN_DEBUG "Set toggle from %p rval %ld%c for status=%x to %d, exp=%d, act=%d\n", tmp, rval ? *rval : 0, rval ? '*' : '/', tmp->status, @@ -168,12 +169,11 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned usb_settoggle(dev->usb, uhci_endpoint(tmp->info), uhci_packetout(tmp->info), uhci_toggle(tmp->info) ^ 1); - break; // Short packet + break; /* Short packet */ } } - if ((tmp->link & UHCI_PTR_TERM) || - (tmp->link & UHCI_PTR_QH)) + if ((tmp->link & UHCI_PTR_TERM) || (tmp->link & UHCI_PTR_QH)) break; tmp = uhci_ptr_to_virt(tmp->link); @@ -181,8 +181,6 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned if (!count) { printk(KERN_ERR "runaway td's in uhci_td_result!\n"); - /* Force debugging on */ - debug = 1; } else { /* If we got to the last TD */ @@ -200,7 +198,7 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned return USB_ST_NOERROR; /* We got to an error, but the controller hasn't finished */ - /* with it yet. */ + /* with it yet */ if (tmp->status & TD_CTRL_ACTIVE) return USB_ST_NOCHANGE; @@ -212,7 +210,7 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned } /* Some debugging code */ - if (debug && uhci_debug) { + if (!count || (!in_interrupt() && uhci_debug)) { printk(KERN_DEBUG "uhci_td_result() failed with status %x\n", status); @@ -296,7 +294,7 @@ static void uhci_remove_qh(struct uhci_qh *qh, struct uhci_qh *remqh) if (lqh->link & UHCI_PTR_TERM) break; - lqh = uhci_ptr_to_virt(lqh->link); + lqh = (struct uhci_qh *)uhci_ptr_to_virt(lqh->link); } if (lqh->link & UHCI_PTR_TERM) { @@ -561,13 +559,17 @@ static void uhci_remove_frame_list(struct uhci *uhci, struct uhci_td *td) * udelay(1000) doesn't sound nice, and schedule() * can't be used as this is called from within interrupt context. */ + /* + * we should do the same thing as we do with the QH's + * see uhci_insert_tds_in_qh and uhci_remove_td --jerdfelt + */ /* for now warn if there's a possible problem */ if (td->status & TD_CTRL_ACTIVE) { unsigned frn = inw(uhci->io_addr + USBFRNUM); __u32 link = uhci->fl->frame[frn % UHCI_NUMFRAMES]; if (!(link & (UHCI_PTR_TERM | UHCI_PTR_QH))) { struct uhci_td *tdl = (struct uhci_td *)uhci_ptr_to_virt(link); - for (;;) { + for (;tdl;) { if (tdl == td) { printk(KERN_WARNING "uhci_remove_frame_list: td possibly still in use!!\n"); break; @@ -589,7 +591,7 @@ static void uhci_remove_frame_list(struct uhci *uhci, struct uhci_td *td) */ static void uhci_remove_transfer(struct uhci_td *td, char removeirq) { - int maxcount = 1000; + int count = 1000; struct uhci_td *curtd; unsigned int nextlink; @@ -598,7 +600,7 @@ static void uhci_remove_transfer(struct uhci_td *td, char removeirq) else curtd = td; - /* Remove it from the skeleton */ + /* Remove the QH from the skeleton and then free it */ uhci_remove_qh(td->qh->skel, td->qh); uhci_qh_free(td->qh); @@ -606,21 +608,24 @@ static void uhci_remove_transfer(struct uhci_td *td, char removeirq) nextlink = curtd->link; /* IOC? => remove handler */ - if (removeirq && (td->status & TD_CTRL_IOC)) + /* HACK: Don't remove if already removed. Prevents deadlock */ + /* in uhci_interrupt_notify and callbacks */ + if (removeirq && (td->status & TD_CTRL_IOC) && + td->irq_list.next != &td->irq_list) uhci_remove_irq_list(td); + /* Remove the TD and then free it */ uhci_remove_td(curtd); uhci_td_free(curtd); if (nextlink & UHCI_PTR_TERM) /* Tail? */ break; - curtd = (struct uhci_td *)uhci_ptr_to_virt(nextlink); - if (!--maxcount) { - printk(KERN_ERR "runaway td's!?\n"); - break; - } - } while (1); + curtd = (struct uhci_td *)uhci_ptr_to_virt(nextlink & ~UHCI_PTR_BITS); + } while (count--); + + if (!count) + printk(KERN_ERR "runaway td's!?\n"); } /* @@ -644,17 +649,18 @@ static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, uhci_td_free(td); if (qh) uhci_qh_free(qh); - return (-ENOMEM); + return USB_ST_INTERNALERROR; } /* Destination: pipe destination with INPUT */ destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid(pipe); /* Infinite errors is 0, so no bits */ - status = (pipe & TD_CTRL_LS) | TD_CTRL_IOC | TD_CTRL_ACTIVE | TD_CTRL_SPD; + status = (pipe & TD_CTRL_LS) | TD_CTRL_IOC | TD_CTRL_ACTIVE | + TD_CTRL_SPD; td->link = UHCI_PTR_TERM; /* Terminate */ - td->status = status; + td->status = status; /* In */ td->info = destination | ((usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)) - 1) << 21) | (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE); @@ -678,6 +684,7 @@ static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, uhci_insert_qh(qh->skel, qh); *handle = (void *)td; + return 0; } @@ -742,7 +749,7 @@ static int uhci_get_current_frame_number(struct usb_device *usb_dev) * Returns 0 for success or negative value for error. * Sets isocdesc before successful return. */ -static int uhci_init_isoc (struct usb_device *usb_dev, +static int uhci_init_isoc(struct usb_device *usb_dev, unsigned int pipe, int frame_count, /* bandwidth % = 100 * this / 1024 */ void *context, @@ -948,7 +955,6 @@ static int uhci_run_isoc (struct usb_isoc_desc *isocdesc, * frame_desc array, but this way won't take less bandwidth * allocation into account. */ - if (isocdesc->frame_spacing <= 0) isocdesc->frame_spacing = 1; @@ -1038,7 +1044,7 @@ static int uhci_kill_isoc (struct usb_isoc_desc *isocdesc) return 0; } /* end uhci_kill_isoc */ -static void uhci_free_isoc (struct usb_isoc_desc *isocdesc) +static void uhci_free_isoc(struct usb_isoc_desc *isocdesc) { int i; @@ -1083,9 +1089,11 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru { DECLARE_WAITQUEUE(wait, current); struct uhci_qh *qh = uhci_qh_alloc(dev); + unsigned long rval; + int ret; if (!qh) - return -1; + return USB_ST_INTERNALERROR; current->state = TASK_UNINTERRUPTIBLE; add_wait_queue(&qh->wakeup, &wait); @@ -1108,9 +1116,12 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru /* Remove it from the skeleton */ uhci_remove_qh(&dev->uhci->skel_control_qh, qh); + /* Need to check result before free'ing the qh */ + ret = uhci_td_result(dev, last, &rval); + uhci_qh_free(qh); - return uhci_td_result(dev, last, NULL, 1); + return (ret < 0) ? ret : rval; } /* @@ -1149,14 +1160,10 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre int maxsze = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)); __u32 nextlink; unsigned long bytesrequested = len; - unsigned long bytesread = 0; -#ifdef DUMP_RAW - unsigned char *orig_data = (unsigned char *) data; -#endif first = td = uhci_td_alloc(dev); if (!td) - return -ENOMEM; + return USB_ST_INTERNALERROR; /* The "pipe" thing contains the destination in bits 8--18 */ destination = (pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; @@ -1184,7 +1191,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre td = uhci_td_alloc(dev); if (!td) { uhci_td_free(prevtd); - return -ENOMEM; + return USB_ST_INTERNALERROR; } prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH; @@ -1214,16 +1221,18 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre prevtd = td; td = uhci_td_alloc(dev); if (!td) - return -ENOMEM; + return USB_ST_INTERNALERROR; prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH; /* Update previous TD */ } /* * Build the final TD for control status + * + * It's IN if the pipe is an output pipe or we're not expecting + * data back. */ - /* It's only IN if the pipe is out AND we aren't expecting data */ destination &= ~0xFF; - if (usb_pipeout(pipe) | (bytesrequested == 0)) + if (usb_pipeout(pipe) || !bytesrequested) destination |= USB_PID_IN; else destination |= USB_PID_OUT; @@ -1243,10 +1252,6 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre count = 1000; td = first; do { - if (!uhci_status_bits(td->status) && ((td->info & 0xFF) == - USB_PID_IN)) - bytesread += uhci_actual_length(td->status); - nextlink = td->link; uhci_remove_td(td); uhci_td_free(td); @@ -1260,36 +1265,9 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre if (!count) printk(KERN_ERR "runaway td's!?\n"); - if (ret && (bytesread >= bytesrequested)) { - printk(KERN_DEBUG "Recovered sufficient data (asked for %ld, got %ld) from failed cmd\n", - bytesrequested, bytesread); - ret = 0; - } - - if (uhci_debug && ret) { - __u8 *p = (__u8 *)cmd; - - printk("dev %d, pipe %X requested %ld bytes, got %ld, status=%d:\n", - usb_dev->devnum, pipe, bytesrequested, bytesread, ret); - printk(KERN_DEBUG "Failed cmd - %02X %02X %02X %02X %02X %02X %02X %02X\n", - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); - } - -#ifdef DUMP_RAW - if (!ret && usb_pipein(pipe)) { /* good Input control msg */ - int i; - - printk (KERN_CRIT "ctrl msg [%02x %02x %04x %04x %04x] on pipe %x returned:\n", - cmd->requesttype, cmd->request, - cmd->value, cmd->index, cmd->length, pipe); - for (i = 0; i < bytesrequested; ) { - printk(" %02x", orig_data[i]); - if (++i % 16 == 0) - printk("\n"); - } - if (i % 16 != 0) - printk("\n"); - } +#ifdef UHCI_DEBUG + if (ret >= 0 && ret != bytesrequested && bytesrequested) + printk("requested %ld bytes, got %d\n", bytesrequested, ret); #endif return ret; @@ -1309,9 +1287,10 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct { DECLARE_WAITQUEUE(wait, current); struct uhci_qh *qh = uhci_qh_alloc(dev); + int ret; if (!qh) - return -ENOMEM; + return USB_ST_INTERNALERROR; current->state = TASK_UNINTERRUPTIBLE; add_wait_queue(&qh->wakeup, &wait); @@ -1333,9 +1312,11 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_remove_qh(&dev->uhci->skel_bulk_qh, qh); + ret = uhci_td_result(dev, last, rval); + uhci_qh_free(qh); - return uhci_td_result(dev, last, rval, 1); + return ret; } /* @@ -1350,9 +1331,10 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval, int timeout) { struct uhci_device *dev = usb_to_uhci(usb_dev); - struct uhci_td *first, *td, *prevtd; + struct uhci_td *first, *td, *prevtd, *curtd; unsigned long destination, status; - int ret; + unsigned int nextlink; + int ret, count; int maxsze = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)); if (usb_endpoint_halted(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) && @@ -1370,7 +1352,7 @@ static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da */ first = td = uhci_td_alloc(dev); if (!td) - return -ENOMEM; + return USB_ST_INTERNALERROR; prevtd = first; // This is fake, but at least it's not NULL while (len > 0) { @@ -1395,7 +1377,7 @@ static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da prevtd = td; td = uhci_td_alloc(dev); if (!td) - return -ENOMEM; + return USB_ST_INTERNALERROR; prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;/* Update previous TD */ } @@ -1412,30 +1394,28 @@ static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da /* Start it up.. */ ret = uhci_run_bulk(dev, first, td, rval, timeout); - { - int count = 100; - struct uhci_td *curtd = first; - unsigned int nextlink; + count = 1000; + curtd = first; - do { - nextlink = curtd->link; - uhci_remove_td(curtd); - uhci_td_free(curtd); + do { + nextlink = curtd->link; + uhci_remove_td(curtd); + uhci_td_free(curtd); - if (nextlink & UHCI_PTR_TERM) /* Tail? */ - break; + if (nextlink & UHCI_PTR_TERM) /* Tail? */ + break; - curtd = uhci_ptr_to_virt(nextlink); - } while (--count); + curtd = uhci_ptr_to_virt(nextlink); + } while (--count); - if (!count) - printk(KERN_DEBUG "runaway td's!?\n"); - } + if (!count) + printk(KERN_DEBUG "uhci: runaway td's!?\n"); - return ret; + return ret < 0; } -static void * uhci_request_bulk(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id) +static void *uhci_request_bulk(struct usb_device *usb_dev, unsigned int pipe, + usb_device_irq handler, void *data, int len, void *dev_id) { struct uhci_device *dev = usb_to_uhci(usb_dev); struct uhci *uhci = dev->uhci; @@ -1460,7 +1440,7 @@ static void * uhci_request_bulk(struct usb_device *usb_dev, unsigned int pipe, u if (pktsze > maxsze) pktsze = maxsze; - td->status = status; + td->status = status; /* Status */ td->info = destination | ((pktsze-1) << 21) | (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE); /* pktsze bytes of data */ td->buffer = virt_to_bus(data); @@ -1468,6 +1448,7 @@ static void * uhci_request_bulk(struct usb_device *usb_dev, unsigned int pipe, u td->qh = bulk_qh; td->dev = dev; td->pipetype = PIPE_BULK; + data += pktsze; len -= pktsze; @@ -1619,9 +1600,9 @@ static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned i if (usb_new_device(usb_dev)) { unsigned short status = inw(port); - printk(KERN_INFO "uhci: disabling malfunctioning port %d\n", + printk(KERN_INFO "uhci: disabling port %d\n", nr + 1); - outw(status | USBPORTSC_PE, port); + outw(status & ~USBPORTSC_PE, port); } } @@ -1699,7 +1680,7 @@ static int fixup_isoc_desc (struct uhci_td *td) return 0; } -int uhci_isoc_callback(struct uhci *uhci, struct uhci_td *td, int status, unsigned long rval) +static int uhci_isoc_callback(struct uhci *uhci, struct uhci_td *td, int status, unsigned long rval) { struct usb_isoc_desc *isocdesc = td->dev_id; int ret; @@ -1732,6 +1713,7 @@ int uhci_isoc_callback(struct uhci *uhci, struct uhci_td *td, int status, unsign /* TBD */ /* usb_dev = td->dev->usb; */ + /* Safe since uhci_interrupt_notify holds the lock */ list_add(&td->irq_list, &uhci->interrupt_list); td->status = (td->status & (TD_CTRL_SPD | TD_CTRL_C_ERR_MASK | @@ -1766,20 +1748,49 @@ int uhci_isoc_callback(struct uhci *uhci, struct uhci_td *td, int status, unsign return 0; } -int uhci_callback(struct uhci *uhci, struct uhci_td *td, int status, unsigned long rval) +static int uhci_bulk_callback(struct uhci *uhci, struct uhci_td *td, int status, unsigned long rval) +{ + if (td->completed(status, bus_to_virt(td->buffer), rval, td->dev_id)) { + struct usb_device *usb_dev = td->dev->usb; + + /* This is safe since uhci_interrupt_notify holds the lock */ + list_add(&td->irq_list, &uhci->interrupt_list); + + /* Reset the status */ + td->status = (td->status & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | TD_CTRL_SPD; + + /* Reset the info */ + td->info = (td->info & (PIPE_DEVEP_MASK | 0xFF | (TD_CTRL_ACTLEN_MASK << 21))) | + (usb_gettoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info)) << TD_TOKEN_TOGGLE); /* pktsze bytes of data */ + + usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info)); + /* The HC only removes it when it completed */ + /* successfully, so force remove and re-add it */ + uhci_remove_td(td); + uhci_insert_td_in_qh(td->qh, td); + } + + return 0; +} + +static int uhci_callback(struct uhci *uhci, struct uhci_td *td, int status, unsigned long rval) { if (td->completed(status, bus_to_virt(td->buffer), rval, td->dev_id)) { struct usb_device *usb_dev = td->dev->usb; + if (td->pipetype != PIPE_INTERRUPT) + return 0; + + /* This is safe since uhci_interrupt_notify holds the lock */ list_add(&td->irq_list, &uhci->interrupt_list); usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info)); td->info &= ~(1 << TD_TOKEN_TOGGLE); /* clear data toggle */ td->info |= usb_gettoggle(usb_dev, uhci_endpoint(td->info), - uhci_packetout(td->info)) << TD_TOKEN_TOGGLE; /* toggle between data0 and data1 */ + uhci_packetout(td->info)) << TD_TOKEN_TOGGLE; /* toggle between data0 and data1 */ td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC; /* The HC only removes it when it completed */ - /* successfully, so force remove and re-add it. */ + /* successfully, so force remove and re-add it */ uhci_remove_td(td); uhci_insert_td_in_qh(td->qh, td); } else if (td->flags & UHCI_TD_REMOVE) { @@ -1797,7 +1808,7 @@ int uhci_callback(struct uhci *uhci, struct uhci_td *td, int status, unsigned lo return 0; } - + static void uhci_interrupt_notify(struct uhci *uhci) { struct list_head *tmp, *head = &uhci->interrupt_list; @@ -1813,8 +1824,7 @@ static void uhci_interrupt_notify(struct uhci *uhci) /* We're interested if there was an error or if the chain of */ /* TD's completed successfully */ - status = uhci_td_result(td->dev, td, &rval, 0); - + status = uhci_td_result(td->dev, td, &rval); if (status == USB_ST_NOCHANGE) continue; @@ -1822,10 +1832,14 @@ static void uhci_interrupt_notify(struct uhci *uhci) list_del(&td->irq_list); INIT_LIST_HEAD(&td->irq_list); - if (td->pipetype == PIPE_ISOCHRONOUS) { + switch (td->pipetype) { + case PIPE_ISOCHRONOUS: uhci_isoc_callback(uhci, td, status, rval); - } - else { + break; + case PIPE_BULK: + uhci_bulk_callback(uhci, td, status, rval); + break; + default: uhci_callback(uhci, td, status, rval); } @@ -1904,8 +1918,8 @@ static void uhci_init_ticktd(struct uhci *uhci) td->link = uhci->fl->frame[0]; td->backptr = &uhci->fl->frame[0]; td->status = TD_CTRL_IOC; - td->info = (15 << 21) | (0x7f << 8) | USB_PID_IN; - /* (ignored) input packet, 16 bytes, device 127 */ + /* (ignored) input packet, 0 bytes, device 127 */ + td->info = (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN; td->buffer = 0; td->qh = NULL; td->pipetype = -1; @@ -2272,8 +2286,8 @@ static int start_uhci(struct pci_dev *dev) if (check_region(io_addr, io_size)) break; - /* disable legacy emulation */ - pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT); + /* disable legacy emulation */ + pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT); pci_enable_device(dev); diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h index e460fb858cb4..7433a996735e 100644 --- a/drivers/usb/uhci.h +++ b/drivers/usb/uhci.h @@ -125,7 +125,7 @@ struct uhci_framelist { #define TD_TOKEN_TOGGLE 19 #define uhci_maxlen(token) ((token) >> 21) -#define uhci_expected_length(info) (((info >> 21) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ +#define uhci_expected_length(info) (((info >> 21) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ #define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE) & 1) #define uhci_endpoint(token) (((token) >> 15) & 0xf) #define uhci_devaddr(token) (((token) >> 8) & 0x7f) @@ -134,7 +134,6 @@ struct uhci_framelist { #define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN) #define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN) - /* * The documentation says "4 words for hardware, 4 words for software". * @@ -163,16 +162,16 @@ struct uhci_td { void *dev_id; atomic_t refcnt; /* Reference counting */ + struct uhci_device *dev; /* The owning device */ struct uhci_qh *qh; /* QH this TD is a part of (ignored for Isochronous) */ + unsigned char pipetype; /* Control, Bulk, Interrupt, Isoc */ int flags; /* Remove, etc */ int isoc_td_number; /* 0-relative number within a usb_isoc_desc. */ - int pipetype; /* Control, Bulk, Interrupt, or Isoc */ - int bandwidth_alloc; /* in microsecs; used only for Interrupt + int bandwidth_alloc; /* in microsecs; used only for Interrupt * transfers, to return its bandwidth */ } __attribute__((aligned(16))); - /* * Note the alignment requirements of the entries * @@ -233,6 +232,7 @@ struct uhci_device { * other than that, that is what we're doing now * * And now we don't put Iso transfers in QH's, so we don't waste one on it + * --jerdfelt * * To keep with Linus' nomenclature, this is called the QH skeleton. These * labels (below) are only signficant to the root hub's QH's @@ -281,7 +281,7 @@ static inline int __interval_to_skel(int interval) if (interval < 8) { return 2; /* int4 for 4-7 ms */ } - return 3; /* int 8 for 8-15 ms */ + return 3; /* int8 for 8-15 ms */ } if (interval < 64) { if (interval < 32) { diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c index da039ff88ed2..4dd039b4c1d1 100644 --- a/drivers/usb/usb-core.c +++ b/drivers/usb/usb-core.c @@ -9,7 +9,6 @@ * library, while this file handles starting drivers, etc. * */ - #include #include @@ -32,7 +31,7 @@ int usb_init(void) { usb_major_init(); #ifdef CONFIG_USB_PROC - proc_usb_init (); + proc_usb_init(); #endif #ifndef CONFIG_USB_MODULE # ifdef CONFIG_USB_UHCI diff --git a/drivers/usb/usb-serial.c b/drivers/usb/usb-serial.c index bb7cc4787989..534b369caba3 100644 --- a/drivers/usb/usb-serial.c +++ b/drivers/usb/usb-serial.c @@ -667,9 +667,6 @@ int usb_serial_init(void) /* register the USB driver */ if (usb_register(&usb_serial_driver) < 0) { tty_unregister_driver(&serial_tty_driver); - printk(KERN_ERR "USB serial driver cannot register: " - "minor number %d already in use\n", - usb_serial_driver.minor); return -1; } diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index 3c877e47ad92..23da3fdb283f 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -36,6 +36,8 @@ static void usb_find_drivers(struct usb_device *); static int usb_find_interface_driver(struct usb_device *, unsigned int); static void usb_check_support(struct usb_device *); +static int usb_debug = 1; + /* * We have a per-interface "registered driver" list. */ @@ -50,13 +52,17 @@ int usb_register(struct usb_driver *new_driver) { struct list_head *tmp; - printk("usbcore: Registering new driver %s\n", new_driver->name); if (new_driver->fops != NULL) { - if (usb_minors[new_driver->minor/16]) + if (usb_minors[new_driver->minor/16]) { + printk(KERN_ERR "Error registering %s driver\n", + new_driver->name); return USB_ST_NOTSUPPORTED; + } usb_minors[new_driver->minor/16] = new_driver; } + printk("usbcore: Registered new driver %s\n", new_driver->name); + /* Add it to the list of known drivers */ list_add(&new_driver->driver_list, &usb_driver_list); @@ -461,7 +467,8 @@ void usb_inc_dev_use(struct usb_device *dev) static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size) { struct usb_descriptor_header *header; - int parsed = 0; + unsigned char *begin; + int parsed = 0, len, numskipped; header = (struct usb_descriptor_header *)buffer; @@ -473,8 +480,8 @@ static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descri } if (header->bDescriptorType != USB_DT_ENDPOINT) { - printk(KERN_INFO "usb: unexpected descriptor 0x%X\n", - endpoint->bDescriptorType); + printk(KERN_INFO "usb: unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X\n", + endpoint->bDescriptorType, USB_DT_ENDPOINT); return parsed; } @@ -487,6 +494,8 @@ static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descri /* Skip over the rest of the Class Specific or Vendor Specific */ /* descriptors */ + begin = buffer; + numskipped = 0; while (size >= sizeof(struct usb_descriptor_header)) { header = (struct usb_descriptor_header *)buffer; @@ -496,67 +505,90 @@ static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descri } /* If we find another descriptor which is at or below us */ - /* in the descriptor hierarchy then return */ + /* in the descriptor heirarchy then we're done */ if ((header->bDescriptorType == USB_DT_ENDPOINT) || (header->bDescriptorType == USB_DT_INTERFACE) || (header->bDescriptorType == USB_DT_CONFIG) || (header->bDescriptorType == USB_DT_DEVICE)) - return parsed; + break; - printk(KERN_INFO "usb: skipping descriptor 0x%X\n", - header->bDescriptorType); + numskipped++; buffer += header->bLength; size -= header->bLength; parsed += header->bLength; } - return parsed; -} + if (numskipped) + printk(KERN_INFO "usb: skipped %d class/vendor specific endpoint descriptors\n", numskipped); -#if 0 -static int usb_parse_hid(struct usb_device *dev, struct usb_hid_descriptor *hid, unsigned char *ptr, int len) -{ - int parsed = usb_expect_descriptor(ptr, len, USB_DT_HID, ptr[0]); - int i; - - if (parsed < 0) + /* Copy any unknown descriptors into a storage area for drivers */ + /* to later parse */ + len = (int)(buffer - begin); + if (!len) { + endpoint->extra = NULL; + endpoint->extralen = 0; return parsed; + } - memcpy(hid, ptr + parsed, ptr[parsed]); - le16_to_cpus(&hid->bcdHID); + endpoint->extra = kmalloc(len, GFP_KERNEL); + if (!endpoint->extra) { + printk(KERN_ERR "Couldn't allocate memory for endpoint extra descriptors\n"); + endpoint->extralen = 0; + return parsed; + } - for (i=0; ibNumDescriptors; i++) - le16_to_cpus(&(hid->desc[i].wDescriptorLength)); + memcpy(endpoint->extra, begin, len); + endpoint->extralen = len; - return parsed + ptr[parsed]; + return parsed; } -#endif static int usb_parse_interface(struct usb_device *dev, struct usb_interface *interface, unsigned char *buffer, int size) { - int i; - int retval, parsed = 0; + int i, len, numskipped, retval, parsed = 0; struct usb_descriptor_header *header; struct usb_interface_descriptor *ifp; + unsigned char *begin; interface->act_altsetting = 0; interface->num_altsetting = 0; + interface->max_altsetting = USB_ALTSETTINGALLOC; - interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * USB_MAXALTSETTING, GFP_KERNEL); + interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * interface->max_altsetting, GFP_KERNEL); if (!interface->altsetting) { - printk("couldn't kmalloc interface->altsetting\n"); + printk(KERN_ERR "couldn't kmalloc interface->altsetting\n"); return -1; } while (size > 0) { + if (interface->num_altsetting >= interface->max_altsetting) { + void *ptr; + int oldmas; + + oldmas = interface->max_altsetting; + interface->max_altsetting += USB_ALTSETTINGALLOC; + if (interface->max_altsetting > USB_MAXALTSETTING) { + printk(KERN_WARNING "usb: too many alternate settings (max %d)\n", + USB_MAXALTSETTING); + return -1; + } + + ptr = interface->altsetting; + interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * interface->max_altsetting, GFP_KERNEL); + if (!interface->altsetting) { + printk("couldn't kmalloc interface->altsetting\n"); + interface->altsetting = ptr; + return -1; + } + memcpy(interface->altsetting, ptr, sizeof(struct usb_interface_descriptor) * oldmas); + + kfree(ptr); + } + ifp = interface->altsetting + interface->num_altsetting; interface->num_altsetting++; - if (interface->num_altsetting >= USB_MAXALTSETTING) { - printk(KERN_WARNING "usb: too many alternate settings\n"); - return -1; - } memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE); /* Skip over the interface */ @@ -564,6 +596,9 @@ static int usb_parse_interface(struct usb_device *dev, struct usb_interface *int parsed += ifp->bLength; size -= ifp->bLength; + begin = buffer; + numskipped = 0; + /* Skip over at Interface class or vendor descriptors */ while (size >= sizeof(struct usb_descriptor_header)) { header = (struct usb_descriptor_header *)buffer; @@ -573,27 +608,48 @@ static int usb_parse_interface(struct usb_device *dev, struct usb_interface *int return -1; } - /* If we find another descriptor which is at or below us */ - /* in the descriptor hierarchy then return */ + /* If we find another descriptor which is at or below */ + /* us in the descriptor heirarchy then return */ if ((header->bDescriptorType == USB_DT_INTERFACE) || - (header->bDescriptorType == USB_DT_ENDPOINT)) - break; - - if ((header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_ENDPOINT) || + (header->bDescriptorType == USB_DT_CONFIG) || (header->bDescriptorType == USB_DT_DEVICE)) - return parsed; + break; - if (header->bDescriptorType == USB_DT_HID) - printk(KERN_INFO "usb: skipping HID descriptor\n"); - else - printk(KERN_INFO "usb: unexpected descriptor 0x%X\n", - header->bDescriptorType); + numskipped++; buffer += header->bLength; parsed += header->bLength; size -= header->bLength; } + if (numskipped) + printk(KERN_INFO "usb: skipped %d class/vendor specific interface descriptors\n", numskipped); + + /* Copy any unknown descriptors into a storage area for */ + /* drivers to later parse */ + len = (int)(buffer - begin); + if (!len) { + ifp->extra = NULL; + ifp->extralen = 0; + } else { + ifp->extra = kmalloc(len, GFP_KERNEL); + if (!ifp->extra) { + printk(KERN_ERR "couldn't allocate memory for interface extra descriptors\n"); + ifp->extralen = 0; + return -1; + } + memcpy(ifp->extra, begin, len); + ifp->extralen = len; + } + + /* Did we hit an unexpected descriptor? */ + header = (struct usb_descriptor_header *)buffer; + if ((size >= sizeof(struct usb_descriptor_header)) && + ((header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE))) + return parsed; + if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { printk(KERN_WARNING "usb: too many endpoints\n"); return -1; @@ -796,7 +852,7 @@ void usb_connect(struct usb_device *dev) { int devnum; - dev->descriptor.bMaxPacketSize0 = 8; /* XXX fixed 8 bytes for now */ + dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */ devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1); if (devnum < 128) { @@ -811,32 +867,20 @@ void usb_connect(struct usb_device *dev) */ int usb_set_address(struct usb_device *dev) { - devrequest dr; - - dr.requesttype = 0; - dr.request = USB_REQ_SET_ADDRESS; - dr.value = dev->devnum; - dr.index = 0; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_snddefctrl(dev), &dr, NULL, 0, HZ); + return usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS, + 0, dev->devnum, 0, NULL, 0, HZ); } int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) { - devrequest dr; int i = 5; int result; - dr.requesttype = USB_DIR_IN; - dr.request = USB_REQ_GET_DESCRIPTOR; - dr.value = (type << 8) + index; - dr.index = 0; - dr.length = size; - while (i--) { - if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size, HZ)) - || result == USB_ST_STALL) + if ((result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, + (type << 8) + index, 0, buf, size, HZ)) >= 0 || + result == USB_ST_STALL) break; } return result; @@ -844,22 +888,16 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size) { - devrequest dr; - - dr.requesttype = USB_DIR_IN; - dr.request = USB_REQ_GET_DESCRIPTOR; - dr.value = (USB_DT_STRING << 8) + index; - dr.index = langid; - dr.length = size; - - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size, HZ); + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, + (USB_DT_STRING << 8) + index, langid, buf, size, HZ); } int usb_get_device_descriptor(struct usb_device *dev) { int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor)); - if (ret == 0) { + if (ret >= 0) { le16_to_cpus(&dev->descriptor.bcdUSB); le16_to_cpus(&dev->descriptor.idVendor); le16_to_cpus(&dev->descriptor.idProduct); @@ -868,62 +906,37 @@ int usb_get_device_descriptor(struct usb_device *dev) return ret; } -int usb_get_status (struct usb_device *dev, int type, int target, void *data) +int usb_get_status(struct usb_device *dev, int type, int target, void *data) { - devrequest dr; - - dr.requesttype = USB_DIR_IN | type; /* USB_RECIP_DEVICE, _INTERFACE, or _ENDPOINT */ - dr.request = USB_REQ_GET_STATUS; - dr.value = 0; - dr.index = target; - dr.length = 2; - - return dev->bus->op->control_msg (dev, usb_rcvctrlpipe (dev,0), &dr, data, 2, HZ); + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, data, 2, HZ); } int usb_get_protocol(struct usb_device *dev) { - unsigned char buf[8]; - devrequest dr; + unsigned char type; + int ret; - dr.requesttype = USB_RT_HIDD | USB_DIR_IN; - dr.request = USB_REQ_GET_PROTOCOL; - dr.value = 0; - dr.index = 1; - dr.length = 1; - - if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 1, HZ)) - return -1; + if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_PROTOCOL, USB_DIR_IN | USB_RT_HIDD, + 0, 1, &type, 1, HZ)) < 0) + return ret; - return buf[0]; + return type; } int usb_set_protocol(struct usb_device *dev, int protocol) { - devrequest dr; - - dr.requesttype = USB_RT_HIDD; - dr.request = USB_REQ_SET_PROTOCOL; - dr.value = protocol; - dr.index = 1; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ); + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_PROTOCOL, USB_RT_HIDD, protocol, 1, NULL, 0, HZ); } /* keyboards want a nonzero duration according to HID spec, but mice should use infinity (0) -keryan */ int usb_set_idle(struct usb_device *dev, int duration, int report_id) { - devrequest dr; - - dr.requesttype = USB_RT_HIDD; - dr.request = USB_REQ_SET_IDLE; - dr.value = (duration << 8) | report_id; - dr.index = 1; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ); + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_IDLE, + USB_RT_HIDD, (duration << 8) | report_id, 1, NULL, 0, HZ); } static void usb_set_maxpacket(struct usb_device *dev) @@ -957,38 +970,30 @@ static void usb_set_maxpacket(struct usb_device *dev) */ int usb_clear_halt(struct usb_device *dev, int endp) { - devrequest dr; int result; __u16 status; - //if (!usb_endpoint_halted(dev, endp & 0x0f, usb_endpoint_out(endp))) - // return 0; - - dr.requesttype = USB_RT_ENDPOINT; - dr.request = USB_REQ_CLEAR_FEATURE; - dr.value = 0; - dr.index = endp; - dr.length = 0; +/* + if (!usb_endpoint_halted(dev, endp & 0x0f, usb_endpoint_out(endp))) + return 0; +*/ - result = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0, HZ); + result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_ENDPOINT, 0, endp, NULL, 0, HZ); /* don't clear if failed */ - if (result) - return result; + if (result < 0) + return result; -#if 1 /* let's be really tough */ - dr.requesttype = USB_DIR_IN | USB_RT_ENDPOINT; - dr.request = USB_REQ_GET_STATUS; - dr.length = 2; - status = 0xffff; + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_ENDPOINT, 0, endp, + &status, sizeof(status), HZ); + if (result < 0) + return result; - result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 2, HZ); + if (status & 1) + return USB_ST_STALL; /* still halted */ - if (result) - return result; - if (status & 1) /* endpoint status is Halted */ - return USB_ST_STALL; /* still halted */ -#endif usb_endpoint_running(dev, endp & 0x0f, usb_endpoint_out(endp)); /* toggle is reset on clear */ @@ -1000,18 +1005,12 @@ int usb_clear_halt(struct usb_device *dev, int endp) int usb_set_interface(struct usb_device *dev, int interface, int alternate) { - devrequest dr; - int err; + int ret; - dr.requesttype = 1; - dr.request = USB_REQ_SET_INTERFACE; - dr.value = alternate; - dr.index = interface; - dr.length = 0; - - err = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ); - if (err) - return err; + if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_INTERFACE, USB_RT_INTERFACE, alternate, + interface, NULL, 0, HZ)) < 0) + return ret; dev->actconfig->interface[interface].act_altsetting = alternate; usb_set_maxpacket(dev); @@ -1020,16 +1019,9 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) int usb_set_configuration(struct usb_device *dev, int configuration) { - devrequest dr; - int i; + int i, ret; struct usb_config_descriptor *cp = NULL; - dr.requesttype = 0; - dr.request = USB_REQ_SET_CONFIGURATION; - dr.value = configuration; - dr.index = 0; - dr.length = 0; - for (i=0; idescriptor.bNumConfigurations; i++) { if (dev->config[i].bConfigurationValue == configuration) { cp = &dev->config[i]; @@ -1040,27 +1032,24 @@ int usb_set_configuration(struct usb_device *dev, int configuration) printk(KERN_INFO "usb: selecting invalid configuration %d\n", configuration); return -1; } - if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ)) - return -1; + + if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_CONFIGURATION, 0, configuration, 0, NULL, 0, HZ)) < 0) + return ret; dev->actconfig = cp; dev->toggle[0] = 0; dev->toggle[1] = 0; usb_set_maxpacket(dev); + return 0; } int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size) { - devrequest dr; - - dr.requesttype = USB_RT_HIDD | USB_DIR_IN; - dr.request = USB_REQ_GET_REPORT; - dr.value = (type << 8) + id; - dr.index = index; - dr.length = size; - - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size, HZ); + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_REPORT, USB_DIR_IN | USB_RT_HIDD, + (type << 8) + id, index, buf, size, HZ); } int usb_get_configuration(struct usb_device *dev) @@ -1092,21 +1081,26 @@ int usb_get_configuration(struct usb_device *dev) /* We grab the first 8 bytes so we know how long the whole */ /* configuration is */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8); - if (result < 0) - return -1; - + if (result < 0) { + printk(KERN_ERR "usb: unable to get descriptor\n"); + return result; + } + /* Get the full buffer */ le16_to_cpus(&desc->wTotalLength); bigbuffer = kmalloc(desc->wTotalLength, GFP_KERNEL); - if (!bigbuffer) - return -1; + if (!bigbuffer) { + printk(KERN_ERR "unable to allocate memory for configuration descriptors\n"); + return USB_ST_INTERNALERROR; + } /* Now that we know the length, get the whole thing */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, desc->wTotalLength); - if (result) { + if (result < 0) { + printk(KERN_ERR "couldn't get all of config descriptors\n"); kfree(bigbuffer); - return -1; + return result; } result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer); @@ -1123,7 +1117,7 @@ int usb_get_configuration(struct usb_device *dev) char *usb_string(struct usb_device *dev, int index) { - int len, i; + int i, len, ret; char *ptr; union { unsigned char buffer[256]; @@ -1137,23 +1131,28 @@ char *usb_string(struct usb_device *dev, int index) if (dev->string_langid == 0) { /* read string descriptor 0 */ - if (usb_get_string(dev, 0, 0, u.buffer, 2) == 0 - && u.desc.bLength >= 4 - && usb_get_string(dev, 0, 0, u.buffer, 4) == 0) + ret = usb_get_string(dev, 0, 0, u.buffer, 4); + if (ret >= 0 && u.desc.bLength >= 4) dev->string_langid = le16_to_cpup(&u.desc.wData[0]); + else + printk(KERN_ERR "usb: error getting string!\n"); dev->string_langid |= 0x10000; /* so it's non-zero */ } - if (usb_get_string(dev, dev->string_langid, index, u.buffer, 2) || + if (usb_get_string(dev, dev->string_langid, index, u.buffer, 4) < 0 || usb_get_string(dev, dev->string_langid, index, u.buffer, - u.desc.bLength)) - return 0; + u.desc.bLength) < 0) { + printk(KERN_ERR "usb: error retrieving string\n"); + return NULL; + } len = u.desc.bLength / 2; /* includes terminating null */ ptr = kmalloc(len, GFP_KERNEL); - if (!ptr) - return 0; + if (!ptr) { + printk(KERN_ERR "usb: couldn't allocate memory for string\n"); + return NULL; + } for (i = 0; i < len - 1; ++i) ptr[i] = le16_to_cpup(&u.desc.wData[i]); @@ -1172,8 +1171,7 @@ char *usb_string(struct usb_device *dev, int index) */ int usb_new_device(struct usb_device *dev) { - int addr; - int err; + int addr, err; printk(KERN_INFO "USB new device connect, assigned device number %d\n", dev->devnum); @@ -1186,11 +1184,9 @@ int usb_new_device(struct usb_device *dev) addr = dev->devnum; dev->devnum = 0; - /* Slow devices */ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8); - if (err) { - printk(KERN_ERR "usbcore: USB device not responding, giving up (error=%d)\n", - err); + if (err < 0) { + printk(KERN_ERR "usbcore: USB device not responding, giving up (error=%d)\n", err); dev->devnum = -1; return 1; } @@ -1207,9 +1203,8 @@ int usb_new_device(struct usb_device *dev) dev->devnum = addr; err = usb_set_address(dev); - if (err) { - printk(KERN_ERR "usbcore: USB device not accepting new address (error=%d)\n", - err); + if (err < 0) { + printk(KERN_ERR "usbcore: USB device not accepting new address (error=%d)\n", err); dev->devnum = -1; return 1; } @@ -1217,15 +1212,15 @@ int usb_new_device(struct usb_device *dev) wait_ms(10); /* Let the SET_ADDRESS settle */ err = usb_get_device_descriptor(dev); - if (err) { - printk(KERN_ERR "usbcore: unable to get device descriptor (error=%d)\n", - err); + if (err < 0) { + printk(KERN_ERR "usbcore: unable to get device descriptor (error=%d)\n", err); dev->devnum = -1; return 1; } - if (usb_get_configuration(dev)) { - printk(KERN_ERR "usbcore: unable to get configuration\n"); + err = usb_get_configuration(dev); + if (err < 0) { + printk(KERN_ERR "usbcore: unable to get configuration (error=%d)\n", err); dev->devnum = -1; return 1; } @@ -1255,14 +1250,26 @@ int usb_new_device(struct usb_device *dev) int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout) { devrequest dr; + int ret; dr.requesttype = requesttype; dr.request = request; - dr.value = value; - dr.index = index; - dr.length = size; + dr.value = cpu_to_le16p(&value); + dr.index = cpu_to_le16p(&index); + dr.length = cpu_to_le16p(&size); + + ret = dev->bus->op->control_msg(dev, pipe, &dr, data, size, timeout); - return dev->bus->op->control_msg(dev, pipe, &dr, data, size, timeout); + if (ret < 0 && usb_debug) { + unsigned char *p = (unsigned char *)&dr; + + printk(KERN_DEBUG "Failed control msg - r:%02X rt:%02X v:%04X i:%04X s:%04X - ret: %d\n", + request, requesttype, value, index, size, ret); + printk(KERN_DEBUG " %02X %02X %02X %02X %02X %02X %02X %02X\n", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + } + + return ret; } int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id, void **handle) @@ -1383,7 +1390,7 @@ int usb_init_isoc(struct usb_device *usb_dev, return err; } -void usb_free_isoc (struct usb_isoc_desc *isocdesc) +void usb_free_isoc(struct usb_isoc_desc *isocdesc) { long bustime; @@ -1402,13 +1409,13 @@ void usb_free_isoc (struct usb_isoc_desc *isocdesc) isocdesc->usb_dev->bus->op->free_isoc (isocdesc); } -int usb_run_isoc (struct usb_isoc_desc *isocdesc, +int usb_run_isoc(struct usb_isoc_desc *isocdesc, struct usb_isoc_desc *pr_isocdesc) { return isocdesc->usb_dev->bus->op->run_isoc (isocdesc, pr_isocdesc); } -int usb_kill_isoc (struct usb_isoc_desc *isocdesc) +int usb_kill_isoc(struct usb_isoc_desc *isocdesc) { return isocdesc->usb_dev->bus->op->kill_isoc (isocdesc); } @@ -1417,6 +1424,7 @@ static int usb_open(struct inode * inode, struct file * file) { int minor = MINOR(inode->i_rdev); struct usb_driver *c = usb_minors[minor/16]; + file->f_op = NULL; if (c && (file->f_op = c->fops) && file->f_op->open) @@ -1481,6 +1489,7 @@ EXPORT_SYMBOL(usb_free_dev); EXPORT_SYMBOL(usb_inc_dev_use); EXPORT_SYMBOL(usb_driver_claim_interface); +EXPORT_SYMBOL(usb_interface_claimed); EXPORT_SYMBOL(usb_driver_release_interface); EXPORT_SYMBOL(usb_init_root_hub); diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h index e8b8dfc41ff1..e7c88fa1cf5c 100644 --- a/drivers/usb/usb.h +++ b/drivers/usb/usb.h @@ -126,15 +126,15 @@ struct usb_proc_ctrltransfer { __u16 value; __u16 index; __u16 length; - __u32 timeout; /* in milliseconds */ - void *data; + __u32 timeout; /* in milliseconds */ + void *data; }; struct usb_proc_bulktransfer { - unsigned int ep; - unsigned int len; - unsigned int timeout; /* in milliseconds */ - void *data; + unsigned int ep; + unsigned int len; + unsigned int timeout; /* in milliseconds */ + void *data; }; struct usb_proc_old_ctrltransfer { @@ -143,31 +143,28 @@ struct usb_proc_old_ctrltransfer { __u16 value; __u16 index; __u16 length; - /* pointer to data */ - void *data; + /* pointer to data */ + void *data; }; struct usb_proc_old_bulktransfer { - unsigned int ep; - unsigned int len; - void *data; + unsigned int ep; + unsigned int len; + void *data; }; struct usb_proc_setinterface { - unsigned int interface; - unsigned int altsetting; + unsigned int interface; + unsigned int altsetting; }; -#define USB_PROC_CONTROL _IOWR('U', 0, struct usb_proc_ctrltransfer) -#define USB_PROC_BULK _IOWR('U', 2, struct usb_proc_bulktransfer) -#define USB_PROC_OLD_CONTROL _IOWR('U', 0, struct usb_proc_old_ctrltransfer) -#define USB_PROC_OLD_BULK _IOWR('U', 2, struct usb_proc_old_bulktransfer) -#define USB_PROC_RESETEP _IOR('U', 3, unsigned int) -#define USB_PROC_SETINTERFACE _IOR('U', 4, struct usb_proc_setinterface) -#define USB_PROC_SETCONFIGURATION _IOR('U', 5, unsigned int) - - - +#define USB_PROC_CONTROL _IOWR('U', 0, struct usb_proc_ctrltransfer) +#define USB_PROC_BULK _IOWR('U', 2, struct usb_proc_bulktransfer) +#define USB_PROC_OLD_CONTROL _IOWR('U', 0, struct usb_proc_old_ctrltransfer) +#define USB_PROC_OLD_BULK _IOWR('U', 2, struct usb_proc_old_bulktransfer) +#define USB_PROC_RESETEP _IOR('U', 3, unsigned int) +#define USB_PROC_SETINTERFACE _IOR('U', 4, struct usb_proc_setinterface) +#define USB_PROC_SETCONFIGURATION _IOR('U', 5, unsigned int) #ifdef __KERNEL__ @@ -180,6 +177,7 @@ struct usb_proc_setinterface { extern int usb_hub_init(void); extern int usb_kbd_init(void); extern int usb_cpia_init(void); +extern int usb_dc2xx_init(void); extern int usb_mouse_init(void); extern int usb_printer_init(void); @@ -251,7 +249,8 @@ struct usb_busmap { /* Everything but the endpoint maximums are aribtrary */ #define USB_MAXCONFIG 8 -#define USB_MAXALTSETTING 16 +#define USB_ALTSETTINGALLOC 4 +#define USB_MAXALTSETTING 128 /* Hard limit */ #define USB_MAXINTERFACES 32 #define USB_MAXENDPOINTS 32 @@ -289,6 +288,9 @@ struct usb_endpoint_descriptor { __u8 bInterval; __u8 bRefresh; __u8 bSynchAddress; + + unsigned char *extra; /* Extra descriptors */ + int extralen; } __attribute__ ((packed)); /* HID descriptor */ @@ -319,8 +321,10 @@ struct usb_interface_descriptor { __u8 bInterfaceProtocol; __u8 iInterface; - struct usb_hid_descriptor *hid; struct usb_endpoint_descriptor *endpoint; + + unsigned char *extra; + int extralen; } __attribute__ ((packed)); struct usb_interface { @@ -328,6 +332,7 @@ struct usb_interface { int act_altsetting; /* active alternate setting */ int num_altsetting; /* number of alternate settings */ + int max_altsetting; /* total memory allocated */ struct usb_driver *driver; /* driver */ void *private_data; @@ -407,13 +412,13 @@ enum { * with the completed frames (TDs). */ enum { - CB_CONTINUE = 0, /* OK, remove all TDs; + CB_CONTINUE = 0, /* OK, remove all TDs; needs to be 0 to be consistent with current callback function ret. values */ - CB_REUSE, /* leave descriptors as NULL, not active */ - CB_RESTART, /* leave descriptors as they are, alive */ - CB_ABORT, /* kill this USB transfer request */ - CB_CONT_RUN /* append the isoc_desc at the end of all active isoc_desc */ + CB_REUSE, /* leave descriptors as NULL, not active */ + CB_RESTART, /* leave descriptors as they are, alive */ + CB_ABORT, /* kill this USB transfer request */ + CB_CONT_RUN /* append the isoc_desc at the end of all active isoc_desc */ }; struct isoc_frame_desc { @@ -448,6 +453,7 @@ struct usb_isoc_desc { void *data; int buf_size; struct usb_isoc_desc *prev_isocdesc; /* previous isoc_desc, for CB_CONT_RUN */ + /* * The following fields are set by the usb_run_isoc() call. */ @@ -504,7 +510,6 @@ struct usb_bus { int bandwidth_isoc_reqs; /* number of Isoc. requesters */ /* procfs entry */ - int proc_busnum; struct proc_dir_entry *proc_entry; }; @@ -534,7 +539,7 @@ struct usb_device { int string_langid; /* language ID for strings */ void *hcpriv; /* Host Controller private data */ - void *audiopriv; /* May be both audio and HID */ + /* procfs entry */ struct proc_dir_entry *proc_entry; diff --git a/drivers/usb/usb_scsi.c b/drivers/usb/usb_scsi.c index 8342a6583816..52a6b74ffbfe 100644 --- a/drivers/usb/usb_scsi.c +++ b/drivers/usb/usb_scsi.c @@ -1365,12 +1365,8 @@ int usb_scsi_init(void) usb_zip_init(); #endif - if (usb_register(&scsi_driver) < 0) { - printk(KERN_ERR "USB SCSI driver cannot register: " - "minor number %d already in use\n", - scsi_driver.minor); + if (usb_register(&scsi_driver) < 0) return -1; - } printk(KERN_INFO "USB SCSI support registered.\n"); return 0; diff --git a/drivers/usb/uss720.c b/drivers/usb/uss720.c index e7006ead3370..dab5e93059e6 100644 --- a/drivers/usb/uss720.c +++ b/drivers/usb/uss720.c @@ -640,12 +640,8 @@ MODULE_DESCRIPTION("USB Parport Cable driver for Cables using the Lucent Technol static int __init uss720_init(void) { - if (usb_register(&uss720_driver) < 0) { - printk(KERN_ERR "USB uss720 driver cannot register: " - "minor number %d already in use\n", - uss720_driver.minor); + if (usb_register(&uss720_driver) < 0) return -1; - } printk(KERN_INFO "uss720: USB<->IEEE1284 cable driver v0.4 registered.\n" KERN_INFO "uss720: (C) 1999 by Thomas Sailer, \n"); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 21e2ab052bda..4bd6e8f7b1dd 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -527,7 +527,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) if ((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; off += start; - vma->vm_pgoff = off >> PAGE_CACHE_SHIFT; + vma->vm_pgoff = off >> PAGE_SHIFT; #if defined(__mc68000__) if (CPU_IS_020_OR_030) pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030; diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index 6c8814567ab2..b33044af310d 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c @@ -181,7 +181,7 @@ void adfs_read_inode (struct inode *inode) inode->i_nlink = 2; inode->i_size = ADFS_NEWDIR_SIZE; inode->i_blksize = PAGE_SIZE; - inode->i_blocks = inode->i_size / sb->s_blocksize; + inode->i_blocks = inode->i_size >> sb->s_blocksize_bits; inode->i_mtime = inode->i_atime = inode->i_ctime = 0; diff --git a/fs/bfs/bfs_defs.h b/fs/bfs/bfs_defs.h index a07ddf34d8f5..54d7dad29592 100644 --- a/fs/bfs/bfs_defs.h +++ b/fs/bfs/bfs_defs.h @@ -5,6 +5,7 @@ #define su_lf_ioff u.bfs_sb.si_lf_ioff #define su_lf_sblk u.bfs_sb.si_lf_sblk #define su_lf_eblk u.bfs_sb.si_lf_eblk +#define su_bmap u.bfs_sb.si_bmap #define su_imap u.bfs_sb.si_imap #define su_sbh u.bfs_sb.si_sbh #define su_bfs_sb u.bfs_sb.si_bfs_sb diff --git a/fs/bfs/file.c b/fs/bfs/file.c index 476d5ada5ff2..4bc1ed99a5d4 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c @@ -41,14 +41,14 @@ static struct file_operations bfs_file_operations = { static int bfs_get_block(struct inode * inode, long block, struct buffer_head * bh_result, int create) { - if (!create) { + long phys = inode->iu_sblock + block; + if (!create || phys <= inode->iu_eblock) { bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = inode->iu_sblock + block; + bh_result->b_blocknr = phys; bh_result->b_state |= (1UL << BH_Mapped); return 0; - } else - DBG(KERN_ERR "BFS-fs: %s(create=%d) impossible!\n", - __FUNCTION__, create); + } + /* no support for file migration, working on it */ return -EIO; } diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 772d395b600e..8267eae4b841 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -196,6 +196,7 @@ static void bfs_put_super(struct super_block *s) { brelse(s->su_sbh); kfree(s->su_imap); + kfree(s->su_bmap); MOD_DEC_USE_COUNT; } @@ -294,24 +295,33 @@ static struct super_block * bfs_read_super(struct super_block * s, s->su_lasti = (bfs_sb->s_start - BFS_BSIZE)/sizeof(struct bfs_inode) + BFS_ROOT_INO - 1; + s->su_bmap = kmalloc(sizeof(struct bfs_bmap) * s->su_lasti, GFP_KERNEL); + if (!s->su_bmap) + goto out; imap_len = s->su_lasti/8 + 1; s->su_imap = kmalloc(imap_len, GFP_KERNEL); - if (!s->su_imap) + if (!s->su_imap) { + kfree(s->su_bmap); goto out; + } memset(s->su_imap, 0, imap_len); - for (i=0; isu_bmap[i].start = s->su_bmap[i].end = 0; set_bit(i, s->su_imap); + } s->s_op = &bfs_sops; inode = iget(s, BFS_ROOT_INO); if (!inode) { kfree(s->su_imap); + kfree(s->su_bmap); goto out; } s->s_root = d_alloc_root(inode); if (!s->s_root) { iput(inode); kfree(s->su_imap); + kfree(s->su_bmap); goto out; } @@ -323,9 +333,10 @@ static struct super_block * bfs_read_super(struct super_block * s, s->su_lf_ioff = 0; for (i=BFS_ROOT_INO; i<=s->su_lasti; i++) { inode = iget(s,i); - if (inode->iu_dsk_ino == 0) + if (inode->iu_dsk_ino == 0) { s->su_freei++; - else { + s->su_bmap[i].start = s->su_bmap[i].end = 0; + } else { set_bit(i, s->su_imap); s->su_freeb -= inode->i_blocks; if (inode->iu_eblock > s->su_lf_eblk) { @@ -333,6 +344,8 @@ static struct super_block * bfs_read_super(struct super_block * s, s->su_lf_sblk = inode->iu_sblock; s->su_lf_ioff = BFS_INO2OFF(i); } + s->su_bmap[i].start = inode->iu_sblock; + s->su_bmap[i].end = inode->iu_eblock; } iput(inode); } diff --git a/fs/buffer.c b/fs/buffer.c index 1580b7a333d3..cf0f89722826 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 1e4628d6d9d7..608b04da1db7 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -32,8 +32,7 @@ static long long ext2_file_lseek(struct file *, long long, int); #if BITS_PER_LONG < 64 static int ext2_open_file (struct inode *, struct file *); - -#else +#endif #define EXT2_MAX_SIZE(bits) \ (((EXT2_NDIR_BLOCKS + (1LL << (bits - 2)) + \ @@ -46,9 +45,6 @@ static long long ext2_max_sizes[] = { EXT2_MAX_SIZE(10), EXT2_MAX_SIZE(11), EXT2_MAX_SIZE(12), EXT2_MAX_SIZE(13) }; -#endif - - /* * Make sure the offset never goes beyond the 32-bit mark.. */ @@ -67,12 +63,8 @@ static long long ext2_file_lseek( offset += file->f_pos; } if (((unsigned long long) offset >> 32) != 0) { -#if BITS_PER_LONG < 64 - return -EINVAL; -#else if (offset > ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(inode->i_sb)]) return -EINVAL; -#endif } if (offset != file->f_pos) { file->f_pos = offset; @@ -131,11 +123,12 @@ static int ext2_release_file (struct inode * inode, struct file * filp) #if BITS_PER_LONG < 64 /* * Called when an inode is about to be open. - * We use this to disallow opening RW large files on 32bit systems. + * We use this to disallow opening RW large files on 32bit systems if + * the caller didn't specify O_LARGEFILE. */ static int ext2_open_file (struct inode * inode, struct file * filp) { - if (inode->u.ext2_i.i_high_size && (filp->f_mode & FMODE_WRITE)) + if (inode->u.ext2_i.i_high_size && !(filp->f_flags & O_LARGEFILE)) return -EFBIG; return 0; } diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index fc6d21f9256d..a980df858823 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -687,15 +687,8 @@ void ext2_read_inode (struct inode * inode) inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl); else { inode->u.ext2_i.i_dir_acl = 0; - inode->u.ext2_i.i_high_size = - le32_to_cpu(raw_inode->i_size_high); -#if BITS_PER_LONG < 64 - if (raw_inode->i_size_high) - inode->i_size = (__u32)-1; -#else - inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) - << 32; -#endif + inode->u.ext2_i.i_high_size = le32_to_cpu(raw_inode->i_size_high); + inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32; } inode->i_generation = le32_to_cpu(raw_inode->i_generation); inode->u.ext2_i.i_block_group = block_group; @@ -816,14 +809,9 @@ static int ext2_update_inode(struct inode * inode, int do_sync) raw_inode->i_file_acl = cpu_to_le32(inode->u.ext2_i.i_file_acl); if (S_ISDIR(inode->i_mode)) raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl); - else { -#if BITS_PER_LONG < 64 - raw_inode->i_size_high = - cpu_to_le32(inode->u.ext2_i.i_high_size); -#else + else raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32); -#endif - } + raw_inode->i_generation = cpu_to_le32(inode->i_generation); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev)); diff --git a/fs/fat/file.c b/fs/fat/file.c index 1706bbc3abb1..9c2c159cbb0e 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -182,6 +182,7 @@ ssize_t default_fat_file_write( void fat_truncate(struct inode *inode) { + struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); int cluster; /* Why no return value? Surely the disk could fail... */ @@ -189,9 +190,9 @@ void fat_truncate(struct inode *inode) return /* -EPERM */; if (IS_IMMUTABLE(inode)) return /* -EPERM */; - cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size; + cluster = SECTOR_SIZE*sbi->cluster_size; MSDOS_I(inode)->i_realsize = ((inode->i_size-1) | (SECTOR_SIZE-1)) + 1; - (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster); + fat_free(inode,(inode->i_size+(cluster-1))>>sbi->cluster_bits); MSDOS_I(inode)->i_attrs |= ATTR_ARCH; inode->i_ctime = inode->i_mtime = CURRENT_TIME; mark_inode_dirty(inode); diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 3951eb48b766..033c40c2b273 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -364,21 +364,22 @@ out: static void fat_read_root(struct inode *inode) { struct super_block *sb = inode->i_sb; + struct msdos_sb_info *sbi = MSDOS_SB(sb); int nr; INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash); MSDOS_I(inode)->i_location = 0; MSDOS_I(inode)->i_fat_inode = inode; - inode->i_uid = MSDOS_SB(sb)->options.fs_uid; - inode->i_gid = MSDOS_SB(sb)->options.fs_gid; + inode->i_uid = sbi->options.fs_uid; + inode->i_gid = sbi->options.fs_gid; inode->i_version = ++event; - inode->i_mode = (S_IRWXUGO & ~MSDOS_SB(sb)->options.fs_umask) | S_IFDIR; - inode->i_op = MSDOS_SB(sb)->dir_ops; - if (MSDOS_SB(sb)->fat_bits == 32) { - MSDOS_I(inode)->i_start = MSDOS_SB(sb)->root_cluster; + inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_umask) | S_IFDIR; + inode->i_op = sbi->dir_ops; + if (sbi->fat_bits == 32) { + MSDOS_I(inode)->i_start = sbi->root_cluster; if ((nr = MSDOS_I(inode)->i_start) != 0) { while (nr != -1) { - inode->i_size += SECTOR_SIZE*MSDOS_SB(sb)->cluster_size; + inode->i_size += SECTOR_SIZE*sbi->cluster_size; if (!(nr = fat_access(sb,nr,-1))) { printk("Directory %ld: bad FAT\n", inode->i_ino); @@ -388,12 +389,13 @@ static void fat_read_root(struct inode *inode) } } else { MSDOS_I(inode)->i_start = 0; - inode->i_size = MSDOS_SB(sb)->dir_entries* + inode->i_size = sbi->dir_entries* sizeof(struct msdos_dir_entry); } - inode->i_blksize = MSDOS_SB(sb)->cluster_size* SECTOR_SIZE; - inode->i_blocks = (inode->i_size+inode->i_blksize-1)/ - inode->i_blksize*MSDOS_SB(sb)->cluster_size; + inode->i_blksize = sbi->cluster_size* SECTOR_SIZE; + inode->i_blocks = + ((inode->i_size+inode->i_blksize-1)>>sbi->cluster_bits) * + sbi->cluster_size; MSDOS_I(inode)->i_logstart = 0; MSDOS_I(inode)->i_realsize = inode->i_size; @@ -429,6 +431,7 @@ fat_read_super(struct super_block *sb, void *data, int silent, struct inode *root_inode; struct buffer_head *bh; struct fat_boot_sector *b; + struct msdos_sb_info *sbi = MSDOS_SB(sb); char *p; int data_sectors,logical_sector_size,sector_mult,fat_clusters=0; int debug,error,fat,cp; @@ -442,12 +445,12 @@ fat_read_super(struct super_block *sb, void *data, int silent, cvf_format[0] = '\0'; cvf_options[0] = '\0'; - MSDOS_SB(sb)->cvf_format = NULL; - MSDOS_SB(sb)->private_data = NULL; + sbi->cvf_format = NULL; + sbi->private_data = NULL; MOD_INC_USE_COUNT; - MSDOS_SB(sb)->dir_ops = fs_dir_inode_ops; - MSDOS_SB(sb)->put_super_callback = NULL; + sbi->dir_ops = fs_dir_inode_ops; + sbi->put_super_callback = NULL; sb->s_op = &fat_sops; if (hardsect_size[MAJOR(sb->s_dev)] != NULL){ blksize = hardsect_size[MAJOR(sb->s_dev)][MINOR(sb->s_dev)]; @@ -457,13 +460,13 @@ fat_read_super(struct super_block *sb, void *data, int silent, } - opts.isvfat = MSDOS_SB(sb)->options.isvfat; + opts.isvfat = sbi->options.isvfat; if (!parse_options((char *) data, &fat, &blksize, &debug, &opts, cvf_format, cvf_options) || (blksize != 512 && blksize != 1024 && blksize != 2048)) goto out_fail; /* N.B. we should parse directly into the sb structure */ - memcpy(&(MSDOS_SB(sb)->options), &opts, sizeof(struct fat_mount_options)); + memcpy(&(sbi->options), &opts, sizeof(struct fat_mount_options)); fat_cache_init(); lock_super(sb); @@ -508,69 +511,79 @@ fat_read_super(struct super_block *sb, void *data, int silent, logical_sector_size = CF_LE_W(get_unaligned((unsigned short *) &b->sector_size)); sector_mult = logical_sector_size >> SECTOR_BITS; - MSDOS_SB(sb)->cluster_size = b->cluster_size*sector_mult; - MSDOS_SB(sb)->fats = b->fats; - MSDOS_SB(sb)->fat_start = CF_LE_W(b->reserved)*sector_mult; + sbi->cluster_size = b->cluster_size*sector_mult; + if (!sbi->cluster_size || (sbi->cluster_size & (sbi->cluster_size-1))) { + printk("fatfs: bogus cluster size\n"); + brelse(bh); + goto out_invalid; + } + for (sbi->cluster_bits=0; + 1<cluster_bitscluster_size; + sbi->cluster_bits++) + ; + sbi->cluster_bits += SECTOR_BITS; + sbi->fats = b->fats; + sbi->fat_start = CF_LE_W(b->reserved)*sector_mult; if (!b->fat_length && b->fat32_length) { struct fat_boot_fsinfo *fsinfo; /* Must be FAT32 */ fat32 = 1; - MSDOS_SB(sb)->fat_length= CF_LE_L(b->fat32_length)*sector_mult; - MSDOS_SB(sb)->root_cluster = CF_LE_L(b->root_cluster); + sbi->fat_length= CF_LE_L(b->fat32_length)*sector_mult; + sbi->root_cluster = CF_LE_L(b->root_cluster); /* MC - if info_sector is 0, don't multiply by 0 */ if(CF_LE_W(b->info_sector) == 0) { - MSDOS_SB(sb)->fsinfo_offset = + sbi->fsinfo_offset = logical_sector_size + 0x1e0; } else { - MSDOS_SB(sb)->fsinfo_offset = + sbi->fsinfo_offset = (CF_LE_W(b->info_sector) * logical_sector_size) + 0x1e0; } - if (MSDOS_SB(sb)->fsinfo_offset + sizeof(struct fat_boot_fsinfo) > sb->s_blocksize) { + if (sbi->fsinfo_offset + sizeof(struct fat_boot_fsinfo) > sb->s_blocksize) { printk("fat_read_super: Bad fsinfo_offset\n"); brelse(bh); goto out_invalid; } fsinfo = (struct fat_boot_fsinfo *) - &bh->b_data[MSDOS_SB(sb)->fsinfo_offset]; + &bh->b_data[sbi->fsinfo_offset]; if (CF_LE_L(fsinfo->signature) != 0x61417272) { printk("fat_read_super: Did not find valid FSINFO " "signature. Found 0x%x\n", CF_LE_L(fsinfo->signature)); } else { - MSDOS_SB(sb)->free_clusters = CF_LE_L(fsinfo->free_clusters); + sbi->free_clusters = CF_LE_L(fsinfo->free_clusters); } } else { fat32 = 0; - MSDOS_SB(sb)->fat_length = CF_LE_W(b->fat_length)*sector_mult; - MSDOS_SB(sb)->root_cluster = 0; - MSDOS_SB(sb)->free_clusters = -1; /* Don't know yet */ + sbi->fat_length = CF_LE_W(b->fat_length)*sector_mult; + sbi->root_cluster = 0; + sbi->free_clusters = -1; /* Don't know yet */ } - MSDOS_SB(sb)->dir_start= CF_LE_W(b->reserved)*sector_mult+ - b->fats*MSDOS_SB(sb)->fat_length; - MSDOS_SB(sb)->dir_entries = + sbi->dir_start= CF_LE_W(b->reserved)*sector_mult+ + b->fats*sbi->fat_length; + sbi->dir_entries = CF_LE_W(get_unaligned((unsigned short *) &b->dir_entries)); - MSDOS_SB(sb)->data_start = MSDOS_SB(sb)->dir_start+ROUND_TO_MULTIPLE(( - MSDOS_SB(sb)->dir_entries << MSDOS_DIR_BITS) >> SECTOR_BITS, + sbi->data_start = sbi->dir_start+ROUND_TO_MULTIPLE(( + sbi->dir_entries << MSDOS_DIR_BITS) >> SECTOR_BITS, sector_mult); data_sectors = CF_LE_W(get_unaligned((unsigned short *) &b->sectors)); if (!data_sectors) { data_sectors = CF_LE_L(b->total_sect); } - data_sectors = data_sectors * sector_mult - MSDOS_SB(sb)->data_start; + data_sectors = data_sectors * sector_mult - sbi->data_start; error = !b->cluster_size || !sector_mult; if (!error) { - MSDOS_SB(sb)->clusters = b->cluster_size ? data_sectors/ + sbi->clusters = b->cluster_size ? data_sectors/ b->cluster_size/sector_mult : 0; - MSDOS_SB(sb)->fat_bits = fat32 ? 32 : + sbi->fat_bits = fat32 ? 32 : (fat ? fat : - (MSDOS_SB(sb)->clusters > MSDOS_FAT12 ? 16 : 12)); - fat_clusters = MSDOS_SB(sb)->fat_length*SECTOR_SIZE*8/ - MSDOS_SB(sb)->fat_bits; - error = !MSDOS_SB(sb)->fats || (MSDOS_SB(sb)->dir_entries & - (MSDOS_DPS-1)) || MSDOS_SB(sb)->clusters+2 > fat_clusters+ + (sbi->clusters > MSDOS_FAT12 ? 16 : 12)); + fat_clusters = sbi->fat_length*SECTOR_SIZE*8/ + sbi->fat_bits; + error = !sbi->fats || (sbi->dir_entries & + (MSDOS_DPS-1)) || sbi->clusters+2 > fat_clusters+ MSDOS_MAX_EXTRA || (logical_sector_size & (SECTOR_SIZE-1)) || !b->secs_track || !b->heads; } @@ -592,59 +605,59 @@ fat_read_super(struct super_block *sb, void *data, int silent, if (i >= 0) error = cvf_formats[i]->mount_cvf(sb,cvf_options); else if (sb->s_blocksize == 512) - MSDOS_SB(sb)->cvf_format = &default_cvf; + sbi->cvf_format = &default_cvf; else - MSDOS_SB(sb)->cvf_format = &bigblock_cvf; + sbi->cvf_format = &bigblock_cvf; if (error || debug) { /* The MSDOS_CAN_BMAP is obsolete, but left just to remember */ printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c," "uid=%d,gid=%d,umask=%03o%s]\n", - MSDOS_SB(sb)->fat_bits,opts.name_check, + sbi->fat_bits,opts.name_check, opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask, - MSDOS_CAN_BMAP(MSDOS_SB(sb)) ? ",bmap" : ""); + MSDOS_CAN_BMAP(sbi) ? ",bmap" : ""); printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%ld,ds=%ld,de=%d,data=%ld," "se=%d,ts=%ld,ls=%d,rc=%ld,fc=%u]\n", - b->media,MSDOS_SB(sb)->cluster_size, - MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start, - MSDOS_SB(sb)->fat_length, - MSDOS_SB(sb)->dir_start,MSDOS_SB(sb)->dir_entries, - MSDOS_SB(sb)->data_start, + b->media,sbi->cluster_size, + sbi->fats,sbi->fat_start, + sbi->fat_length, + sbi->dir_start,sbi->dir_entries, + sbi->data_start, CF_LE_W(*(unsigned short *) &b->sectors), (unsigned long)b->total_sect,logical_sector_size, - MSDOS_SB(sb)->root_cluster,MSDOS_SB(sb)->free_clusters); + sbi->root_cluster,sbi->free_clusters); printk ("Transaction block size = %d\n",blksize); } - if (i<0) if (MSDOS_SB(sb)->clusters+2 > fat_clusters) - MSDOS_SB(sb)->clusters = fat_clusters-2; + if (i<0) if (sbi->clusters+2 > fat_clusters) + sbi->clusters = fat_clusters-2; if (error) goto out_invalid; sb->s_magic = MSDOS_SUPER_MAGIC; /* set up enough so that it can read an inode */ - init_waitqueue_head(&MSDOS_SB(sb)->fat_wait); - init_MUTEX(&MSDOS_SB(sb)->fat_lock); - MSDOS_SB(sb)->prev_free = 0; + init_waitqueue_head(&sbi->fat_wait); + init_MUTEX(&sbi->fat_lock); + sbi->prev_free = 0; cp = opts.codepage ? opts.codepage : 437; sprintf(buf, "cp%d", cp); - MSDOS_SB(sb)->nls_disk = load_nls(buf); - if (! MSDOS_SB(sb)->nls_disk) { + sbi->nls_disk = load_nls(buf); + if (! sbi->nls_disk) { /* Fail only if explicit charset specified */ if (opts.codepage != 0) goto out_fail; - MSDOS_SB(sb)->options.codepage = 0; /* already 0?? */ - MSDOS_SB(sb)->nls_disk = load_nls_default(); + sbi->options.codepage = 0; /* already 0?? */ + sbi->nls_disk = load_nls_default(); } - MSDOS_SB(sb)->nls_io = NULL; - if (MSDOS_SB(sb)->options.isvfat && !opts.utf8) { + sbi->nls_io = NULL; + if (sbi->options.isvfat && !opts.utf8) { p = opts.iocharset ? opts.iocharset : "iso8859-1"; - MSDOS_SB(sb)->nls_io = load_nls(p); - if (! MSDOS_SB(sb)->nls_io) { + sbi->nls_io = load_nls(p); + if (! sbi->nls_io) { /* Fail only if explicit charset specified */ if (opts.iocharset) goto out_unload_nls; - MSDOS_SB(sb)->nls_io = load_nls_default(); + sbi->nls_io = load_nls_default(); } } @@ -660,7 +673,7 @@ fat_read_super(struct super_block *sb, void *data, int silent, if (!sb->s_root) goto out_no_root; if(i>=0) { - MSDOS_SB(sb)->cvf_format = cvf_formats[i]; + sbi->cvf_format = cvf_formats[i]; ++cvf_format_use_count[i]; } return sb; @@ -668,10 +681,10 @@ fat_read_super(struct super_block *sb, void *data, int silent, out_no_root: printk("get root inode failed\n"); iput(root_inode); - if (MSDOS_SB(sb)->nls_io) - unload_nls(MSDOS_SB(sb)->nls_io); + if (sbi->nls_io) + unload_nls(sbi->nls_io); out_unload_nls: - unload_nls(MSDOS_SB(sb)->nls_disk); + unload_nls(sbi->nls_disk); goto out_fail; out_invalid: if (!silent) @@ -686,8 +699,9 @@ out_fail: kfree(opts.iocharset); } sb->s_dev = 0; - if(MSDOS_SB(sb)->private_data)kfree(MSDOS_SB(sb)->private_data); - MSDOS_SB(sb)->private_data=NULL; + if(sbi->private_data) + kfree(sbi->private_data); + sbi->private_data=NULL; MOD_DEC_USE_COUNT; return NULL; @@ -737,21 +751,22 @@ static int is_exec(char *extension) static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) { struct super_block *sb = inode->i_sb; + struct msdos_sb_info *sbi = MSDOS_SB(sb); int nr; INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash); MSDOS_I(inode)->i_location = 0; MSDOS_I(inode)->i_fat_inode = inode; - inode->i_uid = MSDOS_SB(sb)->options.fs_uid; - inode->i_gid = MSDOS_SB(sb)->options.fs_gid; + inode->i_uid = sbi->options.fs_uid; + inode->i_gid = sbi->options.fs_gid; inode->i_version = ++event; if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) { inode->i_mode = MSDOS_MKMODE(de->attr,S_IRWXUGO & - ~MSDOS_SB(sb)->options.fs_umask) | S_IFDIR; - inode->i_op = MSDOS_SB(inode->i_sb)->dir_ops; + ~sbi->options.fs_umask) | S_IFDIR; + inode->i_op = sbi->dir_ops; MSDOS_I(inode)->i_start = CF_LE_W(de->start); - if (MSDOS_SB(sb)->fat_bits == 32) { + if (sbi->fat_bits == 32) { MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16); } @@ -767,8 +782,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) inode->i_size = 0; if ((nr = MSDOS_I(inode)->i_start) != 0) while (nr != -1) { - inode->i_size += SECTOR_SIZE*MSDOS_SB(inode-> - i_sb)->cluster_size; + inode->i_size += SECTOR_SIZE*sbi->cluster_size; if (!(nr = fat_access(sb,nr,-1))) { printk("Directory %ld: bad FAT\n", inode->i_ino); @@ -779,13 +793,13 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) } else { /* not a directory */ inode->i_mode = MSDOS_MKMODE(de->attr, ((IS_NOEXEC(inode) || - (MSDOS_SB(sb)->options.showexec && + (sbi->options.showexec && !is_exec(de->ext))) ? S_IRUGO|S_IWUGO : S_IRWXUGO) - & ~MSDOS_SB(sb)->options.fs_umask) | S_IFREG; + & ~sbi->options.fs_umask) | S_IFREG; inode->i_op = &fat_file_inode_operations; MSDOS_I(inode)->i_start = CF_LE_W(de->start); - if (MSDOS_SB(sb)->fat_bits == 32) { + if (sbi->fat_bits == 32) { MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16); } @@ -795,13 +809,14 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) MSDOS_I(inode)->i_realsize = ((inode->i_size-1)|(SECTOR_SIZE-1))+1; } if(de->attr & ATTR_SYS) - if (MSDOS_SB(sb)->options.sys_immutable) + if (sbi->options.sys_immutable) inode->i_flags |= S_IMMUTABLE; MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED; /* this is as close to the truth as we can get ... */ - inode->i_blksize = MSDOS_SB(sb)->cluster_size*SECTOR_SIZE; - inode->i_blocks = (inode->i_size+inode->i_blksize-1)/ - inode->i_blksize*MSDOS_SB(sb)->cluster_size; + inode->i_blksize = sbi->cluster_size*SECTOR_SIZE; + inode->i_blocks = + ((inode->i_size+inode->i_blksize-1)>>sbi->cluster_bits) * + sbi->cluster_size; inode->i_mtime = inode->i_atime = date_dos2unix(CF_LE_W(de->time),CF_LE_W(de->date)); inode->i_ctime = diff --git a/fs/hfs/file.c b/fs/hfs/file.c index 6b01cd9e0dd5..594d6527152a 100644 --- a/fs/hfs/file.c +++ b/fs/hfs/file.c @@ -498,7 +498,6 @@ hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos, written = -EFAULT; break; } - update_vm_cache(inode,pos,p,c); pos += c; written += c; buf += c; diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 795425201d2b..dee4f28e7fe7 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -195,6 +195,12 @@ xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp) #define SM_my_id_sz (3+1+SM_my_name_sz) #define SM_mon_id_sz (1+XDR_QUADLEN(20)+SM_my_id_sz) #define SM_mon_sz (SM_mon_id_sz+4) +#define SM_monres_sz 2 +#define SM_unmonres_sz 1 + +#ifndef MAX +# define MAX(a, b) (((a) > (b))? (a) : (b)) +#endif static struct rpc_procinfo nsm_procedures[] = { { "sm_null", @@ -205,10 +211,10 @@ static struct rpc_procinfo nsm_procedures[] = { (kxdrproc_t) xdr_error, 0, 0 }, { "sm_mon", (kxdrproc_t) xdr_encode_mon, - (kxdrproc_t) xdr_decode_stat_res, SM_mon_sz, 2 }, + (kxdrproc_t) xdr_decode_stat_res, MAX(SM_mon_sz, SM_monres_sz) << 2, 0 }, { "sm_unmon", (kxdrproc_t) xdr_encode_mon, - (kxdrproc_t) xdr_decode_stat, SM_mon_id_sz, 1 }, + (kxdrproc_t) xdr_decode_stat, MAX(SM_mon_id_sz, SM_unmonres_sz) << 2, 0 }, { "sm_unmon_all", (kxdrproc_t) xdr_error, (kxdrproc_t) xdr_error, 0, 0 }, diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 36da6986d328..ec2c1a4e476b 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -122,12 +122,8 @@ void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo) } if (nwi->attributes & aRONLY) inode->i_mode &= ~0222; } - inode->i_blocks = 0; - if ((inode->i_size)&&(inode->i_blksize)) { - inode->i_blocks = (inode->i_size-1)/(inode->i_blksize)+1; - } + inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT; - /* TODO: times? I'm not sure... */ inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwinfo->i.modifyTime), le16_to_cpu(nwinfo->i.modifyDate)); inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwinfo->i.creationTime), @@ -192,14 +188,10 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo) inode->i_nlink = 1; inode->i_uid = server->m.uid; inode->i_gid = server->m.gid; - inode->i_blksize = NCP_BLOCK_SIZE; inode->i_rdev = 0; + inode->i_blksize = NCP_BLOCK_SIZE; - inode->i_blocks = 0; - if ((inode->i_blksize != 0) && (inode->i_size != 0)) { - inode->i_blocks = - (inode->i_size - 1) / inode->i_blksize + 1; - } + inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT; inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime), le16_to_cpu(nwi->modifyDate)); diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c index 2d1bf6adb9a6..b4ff17851b4f 100644 --- a/fs/ncpfs/mmap.c +++ b/fs/ncpfs/mmap.c @@ -119,6 +119,11 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; if (!inode->i_sb || !S_ISREG(inode->i_mode)) return -EACCES; + /* we do not support files bigger than 4GB... We eventually + supports just 4GB... */ + if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff + > (1U << (32 - PAGE_SHIFT))) + return -EFBIG; if (!IS_RDONLY(inode)) { inode->i_atime = CURRENT_TIME; } diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 714dae89307d..92309db268a0 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h @@ -36,7 +36,8 @@ #define NCP_MIN_SYMLINK_SIZE 8 #define NCP_MAX_SYMLINK_SIZE 512 -#define NCP_BLOCK_SIZE 512 +#define NCP_BLOCK_SHIFT 9 +#define NCP_BLOCK_SIZE (1 << (NCP_BLOCK_SHIFT)) int ncp_negotiate_buffersize(struct ncp_server *, int, int *); int ncp_negotiate_size_and_options(struct ncp_server *server, int size, diff --git a/fs/proc/array.c b/fs/proc/array.c index b9dde9fd431d..e72203cfae95 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -54,8 +54,6 @@ #include #include #include -#include -#include #include #include #include @@ -67,6 +65,7 @@ #include #include #include +#include #include #include diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index efe22c0b0e96..d58914e7d618 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -330,6 +330,7 @@ ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, copy_to_user(buffer,__va(*fpos),buflen); #endif acc += buflen; + *fpos += buflen; return acc; diff --git a/fs/read_write.c b/fs/read_write.c index 81f6d1141ee0..eb729a4fdcbd 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -63,8 +63,12 @@ asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin) !(inode = dentry->d_inode)) goto out_putf; retval = -EINVAL; - if (origin <= 2) - retval = llseek(file, offset, origin); + if (origin <= 2) { + loff_t res = llseek(file, offset, origin); + retval = res; + if (res != (loff_t)retval) + retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ + } out_putf: fput(file); bad: diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index e27ac8d838ff..2a1626bdd5ad 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -324,7 +324,7 @@ static int empty_dir(struct inode * inode) block = 0; bh = NULL; pos = offset = 2*SYSV_DIRSIZE; - if (inode->i_size % SYSV_DIRSIZE) + if ((unsigned long)(inode->i_size) % SYSV_DIRSIZE) goto bad_dir; if (inode->i_size < pos) goto bad_dir; diff --git a/fs/udf/super.c b/fs/udf/super.c index e2e1a9e0a5c0..97a0843bb428 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1184,7 +1184,7 @@ udf_load_partition(struct super_block *sb, lb_addr *fileset) if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP15) { UDF_SB_TYPEVIRT(sb,i).s_start_offset = UDF_I_EXT0OFFS(UDF_SB_VAT(sb)); - UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - 36) / sizeof(Uint32); + UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - 36) >> 2; } else if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP20) { @@ -1197,7 +1197,7 @@ udf_load_partition(struct super_block *sb, lb_addr *fileset) le16_to_cpu(((struct VirtualAllocationTable20 *)bh->b_data + UDF_I_EXT0OFFS(UDF_SB_VAT(sb)))->lengthHeader) + UDF_I_EXT0OFFS(UDF_SB_VAT(sb)); UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - - UDF_SB_TYPEVIRT(sb,i).s_start_offset) / sizeof(Uint32); + UDF_SB_TYPEVIRT(sb,i).s_start_offset) >> 2; udf_release_data(bh); } UDF_SB_PARTROOT(sb,i) = udf_get_pblock(sb, 0, i, 0); diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c index f11ccf7afb5f..676f8b3e6145 100644 --- a/fs/udf/truncate.c +++ b/fs/udf/truncate.c @@ -64,7 +64,7 @@ static void trunc(struct inode * inode) lb_addr bloc, eloc, neloc = { 0, 0 }; Uint32 extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc; int etype; - int first_block = (inode->i_size + inode->i_sb->s_blocksize - 1) / inode->i_sb->s_blocksize; + int first_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; struct buffer_head *bh = NULL; int adsize; diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index 45faeda3b22e..9138abfc33c9 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h @@ -293,7 +293,6 @@ extern inline pte_t mk_pte(struct page *page, pgprot_t pgprot) extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; } -#define page_pte_prot(page,prot) mk_pte(page, prot) #define page_pte(page) page_pte_prot(page, __pgprot(0)) #define pmd_page(pmd) \ diff --git a/include/asm-ppc/amigaints.h b/include/asm-ppc/amigaints.h index 2de0f46e7034..c7a50189e62d 100644 --- a/include/asm-ppc/amigaints.h +++ b/include/asm-ppc/amigaints.h @@ -1 +1,135 @@ -#include +/* +** amigaints.h -- Amiga Linux interrupt handling structs and prototypes +** +** Copyright 1992 by Greg Harp +** +** This file is subject to the terms and conditions of the GNU General Public +** License. See the file COPYING in the main directory of this archive +** for more details. +** +** Created 10/2/92 by Greg Harp +*/ + +#ifndef _ASMm68k_AMIGAINTS_H_ +#define _ASMm68k_AMIGAINTS_H_ + +/* +** Amiga Interrupt sources. +** +*/ + +#define AUTO_IRQS (8) +#define AMI_STD_IRQS (14) +#define CIA_IRQS (5) +#define AMI_IRQS (32) /* AUTO_IRQS+AMI_STD_IRQS+2*CIA_IRQS */ + +/* vertical blanking interrupt */ +#define IRQ_AMIGA_VERTB 0 + +/* copper interrupt */ +#define IRQ_AMIGA_COPPER 1 + +/* Audio interrupts */ +#define IRQ_AMIGA_AUD0 2 +#define IRQ_AMIGA_AUD1 3 +#define IRQ_AMIGA_AUD2 4 +#define IRQ_AMIGA_AUD3 5 + +/* Blitter done interrupt */ +#define IRQ_AMIGA_BLIT 6 + +/* floppy disk interrupts */ +#define IRQ_AMIGA_DSKSYN 7 +#define IRQ_AMIGA_DSKBLK 8 + +/* builtin serial port interrupts */ +#define IRQ_AMIGA_RBF 9 +#define IRQ_AMIGA_TBE 10 + +/* software interrupts */ +#define IRQ_AMIGA_SOFT 11 + +/* interrupts from external hardware */ +#define IRQ_AMIGA_PORTS 12 +#define IRQ_AMIGA_EXTER 13 + +/* CIA interrupt sources */ +#define IRQ_AMIGA_CIAA 14 +#define IRQ_AMIGA_CIAA_TA 14 +#define IRQ_AMIGA_CIAA_TB 15 +#define IRQ_AMIGA_CIAA_ALRM 16 +#define IRQ_AMIGA_CIAA_SP 17 +#define IRQ_AMIGA_CIAA_FLG 18 +#define IRQ_AMIGA_CIAB 19 +#define IRQ_AMIGA_CIAB_TA 19 +#define IRQ_AMIGA_CIAB_TB 20 +#define IRQ_AMIGA_CIAB_ALRM 21 +#define IRQ_AMIGA_CIAB_SP 22 +#define IRQ_AMIGA_CIAB_FLG 23 + +/* auto-vector interrupts */ +#define IRQ_AMIGA_AUTO 24 +#define IRQ_AMIGA_AUTO_0 24 /* This is just a dummy */ +#define IRQ_AMIGA_AUTO_1 25 +#define IRQ_AMIGA_AUTO_2 26 +#define IRQ_AMIGA_AUTO_3 27 +#define IRQ_AMIGA_AUTO_4 28 +#define IRQ_AMIGA_AUTO_5 29 +#define IRQ_AMIGA_AUTO_6 30 +#define IRQ_AMIGA_AUTO_7 31 + +#define IRQ_FLOPPY IRQ_AMIGA_DSKBLK + +/* INTREQR masks */ +#define IRQ1_MASK 0x0007 /* INTREQR mask for IRQ 1 */ +#define IRQ2_MASK 0x0008 /* INTREQR mask for IRQ 2 */ +#define IRQ3_MASK 0x0070 /* INTREQR mask for IRQ 3 */ +#define IRQ4_MASK 0x0780 /* INTREQR mask for IRQ 4 */ +#define IRQ5_MASK 0x1800 /* INTREQR mask for IRQ 5 */ +#define IRQ6_MASK 0x2000 /* INTREQR mask for IRQ 6 */ +#define IRQ7_MASK 0x4000 /* INTREQR mask for IRQ 7 */ + +#define IF_SETCLR 0x8000 /* set/clr bit */ +#define IF_INTEN 0x4000 /* master interrupt bit in INT* registers */ +#define IF_EXTER 0x2000 /* external level 6 and CIA B interrupt */ +#define IF_DSKSYN 0x1000 /* disk sync interrupt */ +#define IF_RBF 0x0800 /* serial receive buffer full interrupt */ +#define IF_AUD3 0x0400 /* audio channel 3 done interrupt */ +#define IF_AUD2 0x0200 /* audio channel 2 done interrupt */ +#define IF_AUD1 0x0100 /* audio channel 1 done interrupt */ +#define IF_AUD0 0x0080 /* audio channel 0 done interrupt */ +#define IF_BLIT 0x0040 /* blitter done interrupt */ +#define IF_VERTB 0x0020 /* vertical blanking interrupt */ +#define IF_COPER 0x0010 /* copper interrupt */ +#define IF_PORTS 0x0008 /* external level 2 and CIA A interrupt */ +#define IF_SOFT 0x0004 /* software initiated interrupt */ +#define IF_DSKBLK 0x0002 /* diskblock DMA finished */ +#define IF_TBE 0x0001 /* serial transmit buffer empty interrupt */ + +struct irq_server { + unsigned short count, reentrance; +}; + +extern void amiga_do_irq(int irq, struct pt_regs *fp); +extern void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server); + +/* CIA interrupt control register bits */ + +#define CIA_ICR_TA 0x01 +#define CIA_ICR_TB 0x02 +#define CIA_ICR_ALRM 0x04 +#define CIA_ICR_SP 0x08 +#define CIA_ICR_FLG 0x10 +#define CIA_ICR_ALL 0x1f +#define CIA_ICR_SETCLR 0x80 + +/* to access the interrupt control registers of CIA's use only +** these functions, they behave exactly like the amiga os routines +*/ + +extern struct ciabase ciaa_base, ciab_base; + +extern unsigned char cia_set_irq(unsigned int irq, int set); +extern unsigned char cia_able_irq(unsigned int irq, int enable); + +#endif /* asm-m68k/amigaints.h */ diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h index 673d74397892..c62d78c7989f 100644 --- a/include/asm-ppc/pgtable.h +++ b/include/asm-ppc/pgtable.h @@ -629,9 +629,12 @@ extern void flush_hash_segments(unsigned low_vsid, unsigned high_vsid); extern void flush_hash_page(unsigned context, unsigned long va); -#define SWP_TYPE(entry) (((pte_val(entry)) >> 1) & 0x7f) -#define SWP_OFFSET(entry) ((pte_val(entry)) >> 8) -#define SWP_ENTRY(type,offset) __pte(((type) << 1) | ((offset) << 8)) +/* Encode and de-code a swap entry */ +#define SWP_TYPE(entry) (((entry).val >> 1) & 0x3f) +#define SWP_OFFSET(entry) ((entry).val >> 8) +#define SWP_ENTRY(type,offset) ((swp_entry_t) { (((type) << 1) | ((offset) << 8)) }) +#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define swp_entry_to_pte(x) ((pte_t) { (x).val }) #define module_map vmalloc #define module_unmap vfree diff --git a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h index 974f78a47bed..6e425b60b58b 100644 --- a/include/asm-ppc/processor.h +++ b/include/asm-ppc/processor.h @@ -17,6 +17,7 @@ #define MSR_SF (1<<63) #define MSR_ISF (1<<61) #endif /* CONFIG_PPC64 */ +#define MSR_VEC (1<<25) /* Enable AltiVec */ #define MSR_POW (1<<18) /* Enable Power Management */ #define MSR_TGPR (1<<17) /* TLB Update registers in use */ #define MSR_ILE (1<<16) /* Interrupt Little-Endian enable */ @@ -249,6 +250,7 @@ extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); /* Lazy FPU handling on uni-processor */ extern struct task_struct *last_task_used_math; +extern struct task_struct *last_task_used_altivec; /* * this is the minimum allowable io space due to the location @@ -277,6 +279,9 @@ struct thread_struct { double fpr[32]; /* Complete floating point set */ unsigned long fpscr_pad; /* fpr ... fpscr must be contiguous */ unsigned long fpscr; /* Floating point status */ + unsigned long vrf[128]; + unsigned long vscr; + unsigned long vrsave; }; #define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack) diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index 2bf822e3340b..f6b2013ad638 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h @@ -61,6 +61,8 @@ extern void read_rtc_time(void); extern void pmac_find_display(void); extern void giveup_fpu(struct task_struct *); extern void enable_kernel_fp(void); +extern void giveup_altivec(struct task_struct *); +extern void load_up_altivec(struct task_struct *); extern void cvt_fd(float *from, double *to, unsigned long *fpscr); extern void cvt_df(double *from, float *to, unsigned long *fpscr); extern int call_rtas(const char *, int, int, unsigned long *, ...); diff --git a/include/asm-sh/bitops.h b/include/asm-sh/bitops.h index de026bcd2bd8..bf0d00c0ad64 100644 --- a/include/asm-sh/bitops.h +++ b/include/asm-sh/bitops.h @@ -96,7 +96,7 @@ extern __inline__ int test_and_change_bit(int nr, void * addr) extern __inline__ int test_bit(int nr, const void *addr) { - return 1UL & (((const int *) addr)[nr >> 5] >> (nr & 31)); + return 1UL & (((const unsigned int *) addr)[nr >> 5] >> (nr & 31)); } extern __inline__ unsigned long ffz(unsigned long word) @@ -107,8 +107,8 @@ extern __inline__ unsigned long ffz(unsigned long word) "shlr %1\n\t" "bt/s 1b\n\t" " add #1, %0" - : "=r" (result) - : "r" (word), "0" (~0L)); + : "=r" (result), "=r" (word) + : "0" (~0L), "1" (word)); return result; } @@ -151,10 +151,18 @@ found_middle: #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) +#ifdef __LITTLE_ENDIAN__ +#define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr)) +#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr), (addr)) +#define ext2_test_bit(nr, addr) test_bit((nr), (addr)) +#define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr), (size)) +#define ext2_find_next_zero_bit(addr, size, offset) \ + find_next_zero_bit((addr), (size), (offset)) +#else extern __inline__ int ext2_set_bit(int nr,void * addr) { int mask, retval; - unsigned long flags; + unsigned long flags; unsigned char *ADDR = (unsigned char *) addr; ADDR += nr >> 3; @@ -169,7 +177,7 @@ extern __inline__ int ext2_set_bit(int nr,void * addr) extern __inline__ int ext2_clear_bit(int nr, void * addr) { int mask, retval; - unsigned long flags; + unsigned long flags; unsigned char *ADDR = (unsigned char *) addr; ADDR += nr >> 3; @@ -243,6 +251,7 @@ found_first: found_middle: return result + ffz(__swab32(tmp)); } +#endif /* Bitmap functions for the minix filesystem. */ #define minix_set_bit(nr,addr) test_and_set_bit(nr,addr) diff --git a/include/asm-sh/io.h b/include/asm-sh/io.h index 57f0367b0c91..dd9205b329ff 100644 --- a/include/asm-sh/io.h +++ b/include/asm-sh/io.h @@ -72,6 +72,24 @@ extern __inline__ unsigned long inl(unsigned long addr) return readl(addr); } +extern __inline__ void insb(unsigned long addr, void *buffer, int count) +{ + unsigned char *buf=buffer; + while(count--) *buf++=inb(addr); +} + +extern __inline__ void insw(unsigned long addr, void *buffer, int count) +{ + unsigned short *buf=buffer; + while(count--) *buf++=inw(addr); +} + +extern __inline__ void insl(unsigned long addr, void *buffer, int count) +{ + unsigned long *buf=buffer; + while(count--) *buf++=inl(addr); +} + extern __inline__ void outb(unsigned char b, unsigned long addr) { return writeb(b,addr); @@ -87,6 +105,24 @@ extern __inline__ void outl(unsigned int b, unsigned long addr) return writel(b,addr); } +extern __inline__ void outsb(unsigned long addr, const void *buffer, int count) +{ + const unsigned char *buf=buffer; + while(count--) outb(*buf++, addr); +} + +extern __inline__ void outsw(unsigned long addr, const void *buffer, int count) +{ + const unsigned short *buf=buffer; + while(count--) outw(*buf++, addr); +} + +extern __inline__ void outsl(unsigned long addr, const void *buffer, int count) +{ + const unsigned long *buf=buffer; + while(count--) outl(*buf++, addr); +} + extern __inline__ unsigned long ctrl_inb(unsigned long addr) { return *(volatile unsigned char*)addr; diff --git a/include/asm-sh/ioctls.h b/include/asm-sh/ioctls.h index 3905e572cabd..5d3e2cd245f5 100644 --- a/include/asm-sh/ioctls.h +++ b/include/asm-sh/ioctls.h @@ -10,10 +10,10 @@ #define FIONREAD _IOR('f', 127, int) #define TIOCINQ FIONREAD -#define TCGETS _IOR('t', 19, struct termios) -#define TCSETS _IOW('t', 20, struct termios) -#define TCSETSW _IOW('t', 21, struct termios) -#define TCSETSF _IOW('t', 22, struct termios) +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 #define TCGETA _IOR('t', 23, struct termio) #define TCSETA _IOW('t', 24, struct termio) @@ -84,8 +84,8 @@ #define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */ #define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */ #define TIOCSERSWILD _IOW('T', 85, int) /* 0x5455 */ -#define TIOCGLCKTRMIOS _IOR('T', 86, struct termios) /* 0x5456 */ -#define TIOCSLCKTRMIOS _IOW('T', 87, struct termios) /* 0x5457 */ +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 #define TIOCSERGSTRUCT _IOR('T', 88, struct async_struct) /* 0x5458 */ /* For debugging only */ #define TIOCSERGETLSR _IOR('T', 89, unsigned int) /* 0x5459 */ /* Get line status register */ /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h index a1c06075bae4..f05fd7ac3539 100644 --- a/include/asm-sh/irq.h +++ b/include/asm-sh/irq.h @@ -9,10 +9,13 @@ * */ +#include + #define TIMER_IRQ 16 /* Hard-wired */ #define TIMER_IRP_OFFSET 12 #define TIMER_PRIORITY 1 +#if defined(__SH4__) /* * 48 = 32+16 * @@ -21,6 +24,11 @@ * */ #define NR_IRQS 48 +#elif defined(CONFIG_CPU_SUBTYPE_SH7708) +#define NR_IRQS 32 +#elif defined(CONFIG_CPU_SUBTYPE_SH7709) +#define NR_IRQS 61 +#endif extern void disable_irq(unsigned int); extern void disable_irq_nosync(unsigned int); diff --git a/include/asm-sh/mmu_context.h b/include/asm-sh/mmu_context.h index aca17690fc74..e16a7d7751f6 100644 --- a/include/asm-sh/mmu_context.h +++ b/include/asm-sh/mmu_context.h @@ -16,10 +16,13 @@ */ extern unsigned long mmu_context_cache; -#define MMU_CONTEXT_ASID_MASK 0xff -#define MMU_CONTEXT_VERSION_MASK 0xffffff00 -#define MMU_CONTEXT_FIRST_VERSION 0x100 -#define NO_CONTEXT 0 +#define MMU_CONTEXT_ASID_MASK 0x000000ff +#define MMU_CONTEXT_VERSION_MASK 0xffffff00 +#define MMU_CONTEXT_FIRST_VERSION 0x00000100 +#define NO_CONTEXT 0 + +/* ASID is 8-bit value, so it can't be 0x100 */ +#define MMU_NO_ASID 0x100 extern __inline__ void get_new_mmu_context(struct mm_struct *mm) @@ -34,7 +37,7 @@ get_new_mmu_context(struct mm_struct *mm) flush_tlb_all(); /* Fix version if needed. Note that we avoid version #0 to distingush NO_CONTEXT. */ - if (!mc) + if (!mc) mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION; } mm->context = mc; @@ -71,7 +74,7 @@ extern __inline__ void init_new_context(struct task_struct *tsk, */ extern __inline__ void destroy_context(struct mm_struct *mm) { - mm->context = NO_CONTEXT; + /* Do nothing */ } /* Other MMU related constants. */ @@ -84,11 +87,11 @@ extern __inline__ void destroy_context(struct mm_struct *mm) #define MMUCR 0xFFFFFFE0 /* MMU Control Register */ -#define MMU_TLB_ADDRESS_ARRAY 0xF2000000 -#define MMU_PAGE_ASSOC_BIT 0x80 +#define MMU_TLB_ADDRESS_ARRAY 0xF2000000 +#define MMU_PAGE_ASSOC_BIT 0x80 -#define MMU_NTLB_ENTRIES 128 /* for 7708 */ -#define MMU_CONTROL_INIT 0x007 /* SV=0, TF=1, IX=1, AT=1 */ +#define MMU_NTLB_ENTRIES 128 /* for 7708 */ +#define MMU_CONTROL_INIT 0x007 /* SV=0, TF=1, IX=1, AT=1 */ #elif defined(__SH4__) #define MMU_PTEH 0xFF000000 /* Page table entry register HIGH */ @@ -98,26 +101,26 @@ extern __inline__ void destroy_context(struct mm_struct *mm) #define MMUCR 0xFF000010 /* MMU Control Register */ -#define MMU_ITLB_ADDRESS_ARRAY 0xF2000000 -#define MMU_UTLB_ADDRESS_ARRAY 0xF6000000 -#define MMU_PAGE_ASSOC_BIT 0x80 +#define MMU_ITLB_ADDRESS_ARRAY 0xF2000000 +#define MMU_UTLB_ADDRESS_ARRAY 0xF6000000 +#define MMU_PAGE_ASSOC_BIT 0x80 -#define MMU_NTLB_ENTRIES 64 /* for 7750 */ -#define MMU_CONTROL_INIT 0x205 /* SQMD=1, SV=0, TI=1, AT=1 */ +#define MMU_NTLB_ENTRIES 64 /* for 7750 */ +#define MMU_CONTROL_INIT 0x205 /* SQMD=1, SV=0, TI=1, AT=1 */ #endif -extern __inline__ void set_asid (unsigned long asid) +extern __inline__ void set_asid(unsigned long asid) { __asm__ __volatile__ ("mov.l %0,%1" : /* no output */ : "r" (asid), "m" (__m(MMU_PTEH))); } -extern __inline__ unsigned long get_asid (void) +extern __inline__ unsigned long get_asid(void) { unsigned long asid; - __asm__ __volatile__ ("mov.l %1,%0" + __asm__ __volatile__ ("mov.l %1,%0" : "=r" (asid) : "m" (__m(MMU_PTEH))); asid &= MMU_CONTEXT_ASID_MASK; @@ -143,8 +146,9 @@ extern __inline__ void switch_mm(struct mm_struct *prev, if (prev != next) { unsigned long __pgdir = (unsigned long)next->pgd; - __asm__ __volatile__("mov.l %0,%1": \ - :"r" (__pgdir), "m" (__m(MMU_TTB))); + __asm__ __volatile__("mov.l %0,%1" + : /* no output */ + : "r" (__pgdir), "m" (__m(MMU_TTB))); activate_context(next); clear_bit(cpu, &prev->cpu_vm_mask); } diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index 228c8d2d80ff..867c071229d2 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h @@ -39,9 +39,6 @@ typedef struct { unsigned long pgprot; } pgprot_t; #define pgd_val(x) ((x).pgd) #define pgprot_val(x) ((x).pgprot) -#define __pte(x) ((pte_t) { (x) } ) -#define __pmd(x) ((pmd_t) { (x) } ) -#define __pgd(x) ((pgd_t) { (x) } ) #define __pgprot(x) ((pgprot_t) { (x) } ) #endif /* !__ASSEMBLY__ */ @@ -56,13 +53,12 @@ typedef struct { unsigned long pgprot; } pgprot_t; * * which has the same constant encoded.. */ -#define __PAGE_OFFSET (0x80000000) #define __MEMORY_START CONFIG_MEMORY_START -#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET+__MEMORY_START) -#define __pa(x) ((unsigned long)(x)-__PAGE_OFFSET) -#define __va(x) ((void *)((unsigned long)(x)+__PAGE_OFFSET)) +#define PAGE_OFFSET (0x80000000) +#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) +#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) #define MAP_NR(addr) ((__pa(addr)-__MEMORY_START) >> PAGE_SHIFT) #ifndef __ASSEMBLY__ @@ -74,7 +70,6 @@ extern int console_loglevel; */ #define BUG() do { \ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ - console_loglevel = 0; \ asm volatile("nop"); \ } while (0) diff --git a/include/asm-sh/pgtable-2level.h b/include/asm-sh/pgtable-2level.h index ebfa410b3c73..2ec0bcbccdb5 100644 --- a/include/asm-sh/pgtable-2level.h +++ b/include/asm-sh/pgtable-2level.h @@ -32,7 +32,7 @@ extern inline int pgd_none(pgd_t pgd) { return 0; } extern inline int pgd_bad(pgd_t pgd) { return 0; } extern inline int pgd_present(pgd_t pgd) { return 1; } -#define pgd_clear(xp) do { pgd_val(*(xp)) = 0; } while (0) +#define pgd_clear(xp) do { } while (0) #define pgd_page(pgd) \ ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK)) @@ -57,6 +57,4 @@ extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address) return (pmd_t *) pgd; } -#define SWP_ENTRY(type,offset) __pte((((type) << 1) | ((offset) << 8))) - #endif /* __ASM_SH_PGTABLE_2LEVEL_H */ diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h index 7ea944afa6e5..97a9a3ad8fb5 100644 --- a/include/asm-sh/pgtable.h +++ b/include/asm-sh/pgtable.h @@ -92,7 +92,7 @@ extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page); #define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS) #define TWOLEVEL_PGDIR_SHIFT 22 -#define BOOT_USER_PGD_PTRS (__PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT) +#define BOOT_USER_PGD_PTRS (PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT) #define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS) #ifndef __ASSEMBLY__ @@ -183,7 +183,7 @@ extern void __handle_bad_pmd_kernel(pmd_t * pmd); #define pte_none(x) (!pte_val(x)) #define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE)) #define pte_clear(xp) do { pte_val(*(xp)) = 0; } while (0) -#define pte_pagenr(x) ((unsigned long)((pte_val(x) >> PAGE_SHIFT))) +#define pte_pagenr(x) ((unsigned long)(((pte_val(x) -__MEMORY_START) >> PAGE_SHIFT))) #define pmd_none(x) (!pmd_val(x)) #define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) @@ -194,7 +194,7 @@ extern void __handle_bad_pmd_kernel(pmd_t * pmd); * Permanent address of a page. Obviously must never be * called on a highmem page. */ -#define page_address(page) ({ if (PageHighMem(page)) BUG(); PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT); }) +#define page_address(page) ({ PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT) + __MEMORY_START; }) #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) #define pte_page(x) (mem_map+pte_pagenr(x)) @@ -228,7 +228,7 @@ extern inline pte_t mk_pte(struct page *page, pgprot_t pgprot) pte_t __pte; pte_val(__pte) = (page-mem_map)*(unsigned long long)PAGE_SIZE + - pgprot_val(pgprot); + __MEMORY_START + pgprot_val(pgprot); return __pte; } @@ -274,8 +274,13 @@ extern __inline__ pgd_t *get_pgd_slow(void) pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL); if (ret) { + /* Clear User space */ memset(ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(ret + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + + /* XXX: Copy vmalloc-ed space??? */ + memcpy(ret + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); } return ret; } @@ -412,8 +417,12 @@ extern pgd_t swapper_pg_dir[1024]; extern void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte); -#define SWP_TYPE(entry) (((pte_val(entry)) >> 1) & 0x3f) -#define SWP_OFFSET(entry) ((pte_val(entry)) >> 8) +/* Encode and de-code a swap entry */ +#define SWP_TYPE(x) (((x).val >> 1) & 0x3f) +#define SWP_OFFSET(x) ((x).val >> 8) +#define SWP_ENTRY(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) }) +#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define swp_entry_to_pte(x) ((pte_t) { (x).val }) #define module_map vmalloc #define module_unmap vfree diff --git a/include/asm-sh/resource.h b/include/asm-sh/resource.h index 5f536d5f8fbe..857c37166606 100644 --- a/include/asm-sh/resource.h +++ b/include/asm-sh/resource.h @@ -22,16 +22,16 @@ #define INIT_RLIMITS \ { \ - { LONG_MAX, LONG_MAX }, \ - { LONG_MAX, LONG_MAX }, \ - { LONG_MAX, LONG_MAX }, \ - { _STK_LIM, LONG_MAX }, \ - { 0, LONG_MAX }, \ - { LONG_MAX, LONG_MAX }, \ - { 0, 0 }, \ - { INR_OPEN, INR_OPEN }, \ - { LONG_MAX, LONG_MAX }, \ - { LONG_MAX, LONG_MAX }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { _STK_LIM, RLIM_INFINITY }, \ + { 0, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ + { INR_OPEN, INR_OPEN }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ } #endif /* __KERNEL__ */ diff --git a/include/asm-sh/spinlock.h b/include/asm-sh/spinlock.h index 8db187a2962f..16f70ffd721d 100644 --- a/include/asm-sh/spinlock.h +++ b/include/asm-sh/spinlock.h @@ -1,53 +1,6 @@ #ifndef __ASM_SH_SPINLOCK_H #define __ASM_SH_SPINLOCK_H -#ifndef __SMP__ - -typedef struct { } spinlock_t; -#define SPIN_LOCK_UNLOCKED { } - -#define spin_lock_init(lock) do { } while(0) -#define spin_lock(lock) do { } while(0) -#define spin_trylock(lock) (1) -#define spin_unlock_wait(lock) do { } while(0) -#define spin_unlock(lock) do { } while(0) -#define spin_lock_irq(lock) cli() -#define spin_unlock_irq(lock) sti() - -#define spin_lock_irqsave(lock, flags) save_and_cli(flags) -#define spin_unlock_irqrestore(lock, flags) restore_flags(flags) - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * NOTE! it is quite common to have readers in interrupts - * but no interrupt writers. For those circumstances we - * can "mix" irq-safe locks - any writer needs to get a - * irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - */ -typedef struct { } rwlock_t; -#define RW_LOCK_UNLOCKED (rwlock_t) { } - -#define read_lock(lock) do { } while(0) -#define read_unlock(lock) do { } while(0) -#define write_lock(lock) do { } while(0) -#define write_unlock(lock) do { } while(0) -#define read_lock_irq(lock) cli() -#define read_unlock_irq(lock) sti() -#define write_lock_irq(lock) cli() -#define write_unlock_irq(lock) sti() - -#define read_lock_irqsave(lock, flags) save_and_cli(flags) -#define read_unlock_irqrestore(lock, flags) restore_flags(flags) -#define write_lock_irqsave(lock, flags) save_and_cli(flags) -#define write_unlock_irqrestore(lock, flags) restore_flags(flags) - -#else - #error "No SMP on SH" -#endif /* SMP */ - #endif /* __ASM_SH_SPINLOCK_H */ diff --git a/include/asm-sh/string.h b/include/asm-sh/string.h index 56ea9d8e895e..bcff30489041 100644 --- a/include/asm-sh/string.h +++ b/include/asm-sh/string.h @@ -120,24 +120,6 @@ extern void *memchr(const void *__s, int __c, size_t __n); #define __HAVE_ARCH_BCOPY #define __HAVE_ARCH_MEMSCAN -extern __inline__ void *memscan(void *__addr, int __c, size_t __size) -{ - register char *__end; - unsigned long __dummy; - - __asm__("mov #0,%2\n" - "1:\n\t" - "cmp/eq %0,%1\n\t" - "bt 2f\n\t" - "cmp/eq %5,%2\n\t" - "bf/s 1b\n\t" - " mov.b @%0+,%2\n\t" - "add #-1,%0\n\t" - "2:" - : "=r" (__addr), "=r" (__end), "=&z" (__dummy) - : "0" (__addr), "1" ((char *)__addr + __size), "r" (__c)); - - return __addr; -} +#define memscan memchr #endif /* __ASM_SH_STRING_H */ diff --git a/include/asm-sh/uaccess.h b/include/asm-sh/uaccess.h index 4d888da0aff7..b64de2cd51bd 100644 --- a/include/asm-sh/uaccess.h +++ b/include/asm-sh/uaccess.h @@ -1,4 +1,4 @@ -/* $Id: uaccess.h,v 1.3 1999/10/12 14:46:20 gniibe Exp $ +/* $Id: uaccess.h,v 1.6 1999/10/29 13:10:44 gniibe Exp $ * * User space memory access functions * @@ -392,16 +392,14 @@ extern __inline__ long __strnlen_user(const char *__s, long __n) unsigned long __dummy; __asm__ __volatile__( - "mov #-1,%1\n" - "9:\n\t" + "9:\n" "cmp/eq %4,%0\n\t" - "bt 5f\n\t" - "cmp/eq #0,%1\n\t" - "bf/s 9b\n\t" + "bt 2f\n" "1:\t" - " mov.b @%0+,%1\n\t" - "5:\t" - "sub %3,%0\n" + "mov.b @(%0,%3),%1\n\t" + "tst %1,%1\n\t" + "bf/s 9b\n\t" + " add #1,%0\n" "2:\n" ".section .fixup,\"ax\"\n" "3:\n\t" @@ -415,14 +413,14 @@ extern __inline__ long __strnlen_user(const char *__s, long __n) " .balign 4\n" " .long 1b,3b\n" ".previous" - : "=&r" (res), "=&z" (__dummy) - : "0" (__s), "r" (__s), "r" (__s+__n), "i" (-EFAULT)); + : "=z" (res), "=&r" (__dummy) + : "0" (0), "r" (__s), "r" (__n), "i" (-EFAULT)); return res; } extern __inline__ long strnlen_user(const char *s, long n) { - if(!access_ok(VERIFY_READ, s, n)) + if (!__addr_ok(s)) return 0; else return __strnlen_user(s, n); diff --git a/include/linux/bfs_fs.h b/include/linux/bfs_fs.h index ce1da8f12876..880ac7f0baf0 100644 --- a/include/linux/bfs_fs.h +++ b/include/linux/bfs_fs.h @@ -32,7 +32,7 @@ struct bfs_inode { __u32 i_atime; __u32 i_mtime; __u32 i_ctime; - __u8 i_padding[16]; + __u32 i_padding[4]; }; #define BFS_NAMELEN 14 @@ -55,7 +55,7 @@ struct bfs_super_block { __s32 s_bto; char s_fsname[6]; char s_volume[6]; - __u8 s_padding[472]; + __u32 s_padding[118]; }; #define BFS_NZFILESIZE(ip) \ diff --git a/include/linux/bfs_fs_i.h b/include/linux/bfs_fs_i.h index 304d6189c936..647352882d97 100644 --- a/include/linux/bfs_fs_i.h +++ b/include/linux/bfs_fs_i.h @@ -10,9 +10,9 @@ * BFS file system in-core inode info */ struct bfs_inode_info { - __u32 i_dsk_ino; /* inode number from the disk, can be 0 */ - __u32 i_sblock; - __u32 i_eblock; + unsigned long i_dsk_ino; /* inode number from the disk, can be 0 */ + unsigned long i_sblock; + unsigned long i_eblock; }; #endif /* _LINUX_BFS_FS_I */ diff --git a/include/linux/bfs_fs_sb.h b/include/linux/bfs_fs_sb.h index 18dd9bba820b..f0f54d606e82 100644 --- a/include/linux/bfs_fs_sb.h +++ b/include/linux/bfs_fs_sb.h @@ -6,18 +6,26 @@ #ifndef _LINUX_BFS_FS_SB #define _LINUX_BFS_FS_SB +/* + * BFS block map entry, an array of these is kept in bfs_sb_info. + */ + struct bfs_bmap { + unsigned long start, end; + }; + /* * BFS file system in-core superblock info */ struct bfs_sb_info { - __u32 si_blocks; - __u32 si_freeb; - __u32 si_freei; - __u32 si_lf_ioff; - __u32 si_lf_sblk; - __u32 si_lf_eblk; - __u32 si_lasti; - __u8 *si_imap; + unsigned long si_blocks; + unsigned long si_freeb; + unsigned long si_freei; + unsigned long si_lf_ioff; + unsigned long si_lf_sblk; + unsigned long si_lf_eblk; + unsigned long si_lasti; + struct bfs_bmap * si_bmap; + char * si_imap; struct buffer_head * si_sbh; /* buffer header w/superblock */ struct bfs_super_block * si_bfs_sb; /* superblock in si_sbh->b_data */ }; diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 3879d1e6170f..ac5170e83eb3 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -2,6 +2,7 @@ #define _LINUX_HIGHMEM_H #include +#include #include #ifdef CONFIG_HIGHMEM diff --git a/include/linux/ide.h b/include/linux/ide.h index 4af0cd2533c2..10cfa16057b3 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -403,6 +403,12 @@ typedef struct hwif_s { */ typedef void (ide_handler_t)(ide_drive_t *); +/* + * when ide_timer_expiry fires, invoke a handler of this type + * to decide what to do. + */ +typedef int (ide_expiry_t)(ide_drive_t *); + typedef struct hwgroup_s { spinlock_t spinlock; /* protects "busy" and "handler" */ ide_handler_t *handler;/* irq handler, if active */ @@ -413,6 +419,7 @@ typedef struct hwgroup_s { struct timer_list timer; /* failsafe timer */ struct request wrq; /* local copy of current write rq */ unsigned long poll_timeout; /* timeout value during long polls */ + ide_expiry_t *expiry; /* queried upon timeouts */ } ide_hwgroup_t; /* @@ -584,7 +591,7 @@ void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecoun * This is used on exit from the driver, to designate the next irq handler * and also to start the safety timer. */ -void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler); +void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry); /* * Error reporting, in human readable form (luxurious, but a memory hog). diff --git a/include/linux/joystick.h b/include/linux/joystick.h index ce6923de5951..0aa715cb39c6 100644 --- a/include/linux/joystick.h +++ b/include/linux/joystick.h @@ -23,7 +23,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: + * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ diff --git a/include/linux/msdos_fs_sb.h b/include/linux/msdos_fs_sb.h index 7abd87148f1e..93053c6b65c2 100644 --- a/include/linux/msdos_fs_sb.h +++ b/include/linux/msdos_fs_sb.h @@ -34,6 +34,7 @@ struct vfat_unicode { struct msdos_sb_info { unsigned short cluster_size; /* sectors/cluster */ + unsigned short cluster_bits; /* sectors/cluster */ unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */ unsigned short fat_start; unsigned long fat_length; /* FAT start & length (sec.) */ diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 57c9a60c4ccd..19a3faf05844 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -1,8 +1,6 @@ #ifndef _LINUX_PAGEMAP_H #define _LINUX_PAGEMAP_H -#include - /* * Page-mapping primitive inline functions * @@ -11,9 +9,11 @@ #include #include -#include #include +#include +#include + /* * The page cache can done in larger chunks than * one page, because it allows for more efficient diff --git a/ipc/shm.c b/ipc/shm.c index 05d863330761..58b41189a9a8 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -84,26 +84,26 @@ static pte_t **shm_alloc(unsigned long pages) unsigned short last = pages % PTRS_PER_PTE; pte_t **ret, **ptr; - ret = kmalloc ((dir+1) * sizeof(unsigned long), GFP_KERNEL); - if (ret == NULL) - return NULL; + ret = kmalloc ((dir+1) * sizeof(pte_t *), GFP_KERNEL); + if (!ret) + goto out; for (ptr = ret; ptr < ret+dir ; ptr++) { *ptr = (pte_t *)__get_free_page (GFP_KERNEL); - if (*ptr == NULL) + if (!*ptr) goto free; memset (*ptr, 0, PAGE_SIZE); } /* The last one is probably not of PAGE_SIZE: we use kmalloc */ if (last) { - *ptr = kmalloc (last*sizeof(pte_t *), GFP_KERNEL); - if (*ptr == NULL) + *ptr = kmalloc (last*sizeof(pte_t), GFP_KERNEL); + if (!*ptr) goto free; - memset (*ptr, 0, last*sizeof(pte_t *)); + memset (*ptr, 0, last*sizeof(pte_t)); } - +out: return ret; free: @@ -897,10 +897,10 @@ failed: unlock_kernel(); return 0; } - if (page_count(page_map)) + if (page_count(page_map) != 1) goto check_table; if (!(page_map = prepare_highmem_swapout(page_map))) - goto check_table; + goto failed; SHM_ENTRY (shp, idx) = swp_entry_to_pte(swap_entry); swap_successes++; shm_swp++; diff --git a/ipc/util.c b/ipc/util.c index 7e34c107a6b1..b391c44899a4 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -101,7 +101,7 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) return -ENOSYS; } -asmlinkage long sys_shmget (key_t key, int size, int flag) +asmlinkage long sys_shmget (key_t key, size_t size, int shmflag) { return -ENOSYS; } diff --git a/mm/filemap.c b/mm/filemap.c index 39c024c259bb..b7d976dc62f7 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -839,6 +839,7 @@ static void generic_file_readahead(int reada_ok, struct file * filp, struct inode * inode, struct page * page) { + unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT; unsigned long index = page->index; unsigned long max_ahead, ahead; unsigned long raend; @@ -858,10 +859,10 @@ static void generic_file_readahead(int reada_ok, if (PageLocked(page)) { if (!filp->f_ralen || index >= raend || index + filp->f_ralen < raend) { raend = index; - if (raend < (unsigned long) (inode->i_size >> PAGE_CACHE_SHIFT)) + if (raend < end_index) max_ahead = filp->f_ramax; filp->f_rawin = 0; - filp->f_ralen = PAGE_CACHE_SIZE; + filp->f_ralen = 1; if (!max_ahead) { filp->f_raend = index + filp->f_ralen; filp->f_rawin += filp->f_ralen; @@ -876,7 +877,7 @@ static void generic_file_readahead(int reada_ok, * it is the moment to try to read ahead asynchronously. * We will later force unplug device in order to force asynchronous read IO. */ - else if (reada_ok && filp->f_ramax && raend >= PAGE_CACHE_SIZE && + else if (reada_ok && filp->f_ramax && raend >= 1 && index <= raend && index + filp->f_ralen >= raend) { /* * Add ONE page to max_ahead in order to try to have about the same IO max size @@ -884,9 +885,9 @@ static void generic_file_readahead(int reada_ok, * Compute the position of the last page we have tried to read in order to * begin to read ahead just at the next page. */ - raend -= PAGE_CACHE_SIZE; - if (raend < inode->i_size) - max_ahead = filp->f_ramax + PAGE_CACHE_SIZE; + raend -= 1; + if (raend < end_index) + max_ahead = filp->f_ramax + 1; if (max_ahead) { filp->f_rawin = filp->f_ralen; @@ -901,10 +902,10 @@ static void generic_file_readahead(int reada_ok, */ ahead = 0; while (ahead < max_ahead) { - ahead += PAGE_CACHE_SIZE; - if ((raend + ahead) >= inode->i_size) + ahead ++; + if ((raend + ahead) >= end_index) break; - if (page_cache_read(filp, (raend + ahead) >> PAGE_CACHE_SHIFT) < 0) + if (page_cache_read(filp, raend + ahead) < 0) break; } /* @@ -925,7 +926,7 @@ static void generic_file_readahead(int reada_ok, filp->f_ralen += ahead; filp->f_rawin += filp->f_ralen; - filp->f_raend = raend + ahead + PAGE_CACHE_SIZE; + filp->f_raend = raend + ahead + 1; filp->f_ramax += filp->f_ramax; @@ -1791,13 +1792,16 @@ generic_file_write(struct file *file, const char *buf, { struct dentry *dentry = file->f_dentry; struct inode *inode = dentry->d_inode; - unsigned long pos = *ppos; unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur; + loff_t pos = *ppos; struct page *page, **hash, *cached_page; unsigned long written; long status; int err; + if (pos < 0) + return -EINVAL; + cached_page = NULL; down(&inode->i_sem); @@ -1816,37 +1820,35 @@ generic_file_write(struct file *file, const char *buf, * Check whether we've reached the file size limit. */ err = -EFBIG; - if (pos >= limit) { - send_sig(SIGXFSZ, current, 0); - goto out; + if (limit != RLIM_INFINITY) { + if (pos >= limit) { + send_sig(SIGXFSZ, current, 0); + goto out; + } + if (count > limit - pos) { + send_sig(SIGXFSZ, current, 0); + count = limit - pos; + } } status = 0; - /* - * Check whether to truncate the write, - * and send the signal if we do. - */ - if (count > limit - pos) { - send_sig(SIGXFSZ, current, 0); - count = limit - pos; - } while (count) { - unsigned long bytes, pgoff, offset; + unsigned long bytes, index, offset; /* * Try to find the page in the cache. If it isn't there, * allocate a free page. */ offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ - pgoff = pos >> PAGE_CACHE_SHIFT; + index = pos >> PAGE_CACHE_SHIFT; bytes = PAGE_CACHE_SIZE - offset; if (bytes > count) bytes = count; - hash = page_hash(&inode->i_data, pgoff); + hash = page_hash(&inode->i_data, index); repeat_find: - page = __find_lock_page(&inode->i_data, pgoff, hash); + page = __find_lock_page(&inode->i_data, index, hash); if (!page) { if (!cached_page) { cached_page = page_cache_alloc(); @@ -1856,7 +1858,7 @@ repeat_find: break; } page = cached_page; - if (add_to_page_cache_unique(page,&inode->i_data,pgoff,hash)) + if (add_to_page_cache_unique(page, &inode->i_data, index, hash)) goto repeat_find; cached_page = NULL; diff --git a/mm/memory.c b/mm/memory.c index 347fce8cd15b..a0452b335a86 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -58,9 +58,9 @@ struct page *highmem_start_page; * a common occurrence (no need to read the page to know * that it's zero - better for the cache and memory subsystem). */ -static inline void copy_cow_page(struct page * from, struct page * to) +static inline void copy_cow_page(struct page * from, struct page * to, unsigned long address) { - if (from == ZERO_PAGE(to)) { + if (from == ZERO_PAGE(address)) { clear_highpage(to); return; } @@ -416,11 +416,11 @@ static struct page * follow_page(unsigned long address) * Given a physical address, is there a useful struct page pointing to it? */ -struct page * get_page_map(struct page *page) +struct page * get_page_map(struct page *page, unsigned long vaddr) { if (MAP_NR(page) >= max_mapnr) return 0; - if (page == ZERO_PAGE(page)) + if (page == ZERO_PAGE(vaddr)) return 0; if (PageReserved(page)) return 0; @@ -484,7 +484,7 @@ int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len) dprintk (KERN_ERR "Missing page in map_user_kiobuf\n"); goto retry; } - map = get_page_map(map); + map = get_page_map(map, ptr); if (map) { if (TryLockPage(map)) { goto retry; @@ -743,7 +743,7 @@ struct page * put_dirty_page(struct task_struct * tsk, struct page *page, return 0; } flush_page_to_ram(page); - set_pte(pte, pte_mkwrite(page_pte_prot(page, PAGE_COPY))); + set_pte(pte, pte_mkwrite(mk_pte(page, PAGE_COPY))); /* no need for flush_tlb */ return page; } @@ -819,7 +819,7 @@ static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma, if (pte_val(*page_table) == pte_val(pte)) { if (PageReserved(old_page)) ++vma->vm_mm->rss; - copy_cow_page(old_page, new_page); + copy_cow_page(old_page, new_page, address); flush_page_to_ram(new_page); flush_cache_page(vma, address); set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot)))); diff --git a/mm/swapfile.c b/mm/swapfile.c index dc733dfc731b..bc661dc2fc2c 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -613,7 +613,7 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags) swapfilesize = 0; if (blk_size[MAJOR(dev)]) swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)] - / (PAGE_SIZE / 1024); + >> (PAGE_SHIFT - 10); } else if (S_ISREG(swap_dentry->d_inode->i_mode)) { error = -EBUSY; for (i = 0 ; i < nr_swapfiles ; i++) { @@ -622,7 +622,7 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags) if (swap_dentry->d_inode == swap_info[i].swap_file->d_inode) goto bad_swap; } - swapfilesize = swap_dentry->d_inode->i_size / PAGE_SIZE; + swapfilesize = swap_dentry->d_inode->i_size >> PAGE_SHIFT; } else goto bad_swap; -- 2.39.5