diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/COPYING linux-2.5/COPYING --- linux-2.5.5/COPYING Wed Feb 20 02:10:53 2002 +++ linux-2.5/COPYING Sun Mar 3 17:54:35 2002 @@ -307,7 +307,7 @@ the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 19yy + Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -329,7 +329,7 @@ If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/CREDITS linux-2.5/CREDITS --- linux-2.5.5/CREDITS Wed Feb 20 02:10:56 2002 +++ linux-2.5/CREDITS Sun Mar 3 20:43:46 2002 @@ -1219,10 +1219,10 @@ S: Germany N: Christoph Hellwig -E: hch@caldera.de E: hch@infradead.org D: misc driver & makefile hacking D: freevxfs driver +D: sysvfs maintainer S: Triftstraße 26 S: 38644 Goslar S: Germany @@ -1579,8 +1579,10 @@ S: Luxembourg N: Gerd Knorr -E: kraxel@goldbach.in-berlin.de -D: SCSI CD-ROM driver hacking, vesafb, v4l, minor bug fixes +W: http://bytesex.org +E: kraxel@bytesex.org +E: kraxel@suse.de +D: video4linux, bttv, vesafb, some scsi, misc fixes N: Harald Koenig E: koenig@tat.physik.uni-tuebingen.de @@ -2130,7 +2132,7 @@ S: Germany N: Thomas Molina -E: tmolina@home.com +E: tmolina@cox.net D: bug fixes, documentation, minor hackery N: David Mosberger-Tang @@ -2672,6 +2674,16 @@ D: Linux-Support, -Mailbox, -Stammtisch D: several improvements to system programs S: Oldenburg +S: Germany + +N: Robert Schwebel +E: robert@schwebel.de +W: http://www.schwebel.de +D: Embedded hacker and book author, +D: AMD Elan support for Linux +S: Pengutronix +S: Braunschweiger Strasse 79 +S: 31134 Hildesheim S: Germany N: Darren Senn diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/Changes linux-2.5/Documentation/Changes --- linux-2.5.5/Documentation/Changes Wed Feb 20 02:11:05 2002 +++ linux-2.5/Documentation/Changes Fri Mar 1 17:12:19 2002 @@ -54,6 +54,7 @@ o util-linux 2.10o # fdformat --version o modutils 2.4.2 # insmod -V o e2fsprogs 1.25 # tune2fs +o jfsutils 1.0.14 # fsck.jfs -V o reiserfsprogs 3.x.0j # reiserfsck 2>&1|grep reiserfsprogs o pcmcia-cs 3.1.21 # cardmgr -V o PPP 2.4.0 # pppd --version @@ -165,6 +166,16 @@ The latest version of e2fsprogs fixes several bugs in fsck and debugfs. Obviously, it's a good idea to upgrade. +JFSutils +-------- + +The jfsutils package contains the utilities for the file system. +The following utilities are available: +o fsck.jfs - initiate replay of the transaction log, and check + and repair a JFS formatted partition. +o mkfs.jfs - create a JFS formatted partition. +o other file system utilities are also available in this package. + Reiserfsprogs ------------- @@ -302,6 +313,10 @@ E2fsprogs --------- o + +JFSutils +-------- +o Reiserfsprogs ------------- diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/DMA-mapping.txt linux-2.5/Documentation/DMA-mapping.txt --- linux-2.5.5/Documentation/DMA-mapping.txt Wed Feb 20 02:11:03 2002 +++ linux-2.5/Documentation/DMA-mapping.txt Fri Feb 8 15:35:52 2002 @@ -759,13 +759,10 @@ Struct scatterlist must contain, at a minimum, the following members: - char *address; struct page *page; unsigned int offset; unsigned int length; - The "address" member will disappear in 2.5.x - This means that your pci_{map,unmap}_sg() and all other interfaces dealing with scatterlists must be able to cope properly with page being non NULL. @@ -774,9 +771,6 @@ either specified by "address" or by a "page+offset" pair. If "address" is NULL, then "page+offset" is being used. If "page" is NULL, then "address" is being used. - - In 2.5.x, all scatterlists will use "page+offset". But during - 2.4.x we still have to support the old method. 2) More to come... diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/DocBook/Makefile linux-2.5/Documentation/DocBook/Makefile --- linux-2.5.5/Documentation/DocBook/Makefile Wed Feb 20 02:11:02 2002 +++ linux-2.5/Documentation/DocBook/Makefile Mon Feb 25 18:56:40 2002 @@ -59,8 +59,8 @@ $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/wan/z85230.c \ z8530book.sgml -via-audio.sgml: via-audio.tmpl $(TOPDIR)/drivers/sound/via82cxxx_audio.c - $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/sound/via82cxxx_audio.c \ +via-audio.sgml: via-audio.tmpl $(TOPDIR)/sound/oss/via82cxxx_audio.c + $(TOPDIR)/scripts/docgen $(TOPDIR)/sound/oss/via82cxxx_audio.c \ via-audio.sgml tulip-user.sgml: tulip-user.tmpl @@ -100,8 +100,8 @@ $(TOPDIR)/drivers/hotplug/pci_hotplug_core.c \ $(TOPDIR)/drivers/hotplug/pci_hotplug_util.c \ $(TOPDIR)/drivers/block/ll_rw_blk.c \ - $(TOPDIR)/drivers/sound/sound_core.c \ - $(TOPDIR)/drivers/sound/sound_firmware.c \ + $(TOPDIR)/sound/sound_core.c \ + $(TOPDIR)/sound/sound_firmware.c \ $(TOPDIR)/drivers/net/wan/syncppp.c \ $(TOPDIR)/drivers/net/wan/z85230.c \ $(TOPDIR)/drivers/usb/hcd.c \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/DocBook/deviceiobook.tmpl linux-2.5/Documentation/DocBook/deviceiobook.tmpl --- linux-2.5.5/Documentation/DocBook/deviceiobook.tmpl Wed Feb 20 02:11:02 2002 +++ linux-2.5/Documentation/DocBook/deviceiobook.tmpl Sun Feb 10 18:25:05 2002 @@ -224,9 +224,5 @@ - - Public Functions Provided -!Einclude/asm-i386/io.h - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/DocBook/kernel-api.tmpl linux-2.5/Documentation/DocBook/kernel-api.tmpl --- linux-2.5.5/Documentation/DocBook/kernel-api.tmpl Wed Feb 20 02:10:53 2002 +++ linux-2.5/Documentation/DocBook/kernel-api.tmpl Mon Feb 25 18:56:40 2002 @@ -203,8 +203,8 @@ Sound Devices -!Edrivers/sound/sound_core.c -!Idrivers/sound/sound_firmware.c +!Esound/sound_core.c +!Isound/sound_firmware.c diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/DocBook/via-audio.tmpl linux-2.5/Documentation/DocBook/via-audio.tmpl --- linux-2.5.5/Documentation/DocBook/via-audio.tmpl Wed Feb 20 02:11:03 2002 +++ linux-2.5/Documentation/DocBook/via-audio.tmpl Mon Feb 25 18:56:40 2002 @@ -537,7 +537,7 @@ - Optimize included headers to eliminate headers found in linux/drivers/sound + Optimize included headers to eliminate headers found in linux/sound @@ -587,7 +587,7 @@ Internal Functions -!Idrivers/sound/via82cxxx_audio.c +!Isound/oss/via82cxxx_audio.c diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/SubmittingDrivers linux-2.5/Documentation/SubmittingDrivers --- linux-2.5.5/Documentation/SubmittingDrivers Wed Feb 20 02:11:04 2002 +++ linux-2.5/Documentation/SubmittingDrivers Wed Feb 6 12:58:02 2002 @@ -3,7 +3,7 @@ This document is intended to explain how to submit device drivers to the Linux 2.2 and 2.4 kernel trees. Note that if you are interested in video -card drivers you should probably talk to XFree86 (http://wwww.xfree86.org) +card drivers you should probably talk to XFree86 (http://www.xfree86.org) instead. Also read the Documentation/SubmittingPatches document. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/arm/Interrupts linux-2.5/Documentation/arm/Interrupts --- linux-2.5.5/Documentation/arm/Interrupts Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/arm/Interrupts Fri Mar 1 15:07:37 2002 @@ -0,0 +1,173 @@ +2.5.2-rmk5 +---------- + +This is the first kernel that contains a major shake up of some of the +major architecture-specific subsystems. + +Firstly, it contains some pretty major changes to the way we handle the +MMU TLB. Each MMU TLB variant is now handled completely separately - +we have TLB v3, TLB v4 (without write buffer), TLB v4 (with write buffer), +and finally TLB v4 (with write buffer, with I TLB invalidate entry). +There is more assembly code inside each of these functions, mainly to +allow more flexible TLB handling for the future. + +Secondly, the IRQ subsystem. + +The 2.5 kernels will be having major changes to the way IRQs are handled. +Unfortunately, this means that machine types that touch the irq_desc[] +array (basically all machine types) will break, and this means every +machine type that we currently have. + +Lets take an example. On the Assabet with Neponset, we have: + + GPIO25 IRR:2 + SA1100 ------------> Neponset -----------> SA1111 + IIR:1 + -----------> USAR + IIR:0 + -----------> SMC9196 + +The way stuff currently works, all SA1111 interrupts are mutually +exclusive of each other - if you're processing one interrupt from the +SA1111 and another comes in, you have to wait for that interrupt to +finish processing before you can service the new interrupt. Eg, an +IDE PIO-based interrupt on the SA1111 excludes all other SA1111 and +SMC9196 interrupts until it has finished transferring its multi-sector +data, which can be a long time. Note also that since we loop in the +SA1111 IRQ handler, SA1111 IRQs can hold off SMC9196 IRQs indefinitely. + + +The new approach brings several new ideas... + +We introduce the concept of a "parent" and a "child". For example, +to the Neponset handler, the "parent" is GPIO25, and the "children"d +are SA1111, SMC9196 and USAR. + +We also bring the idea of an IRQ "chip" (mainly to reduce the size of +the irqdesc array). This doesn't have to be a real "IC"; indeed the +SA11x0 IRQs are handled by two separate "chip" structures, one for +GPIO0-10, and another for all the rest. It is just a container for +the various operations (maybe this'll change to a better name). +This structure has the following operations: + +struct irqchip { + /* + * Acknowledge the IRQ. + * If this is a level-based IRQ, then it is expected to mask the IRQ + * as well. + */ + void (*ack)(unsigned int irq); + /* + * Mask the IRQ in hardware. + */ + void (*mask)(unsigned int irq); + /* + * Unmask the IRQ in hardware. + */ + void (*unmask)(unsigned int irq); + /* + * Re-run the IRQ + */ + void (*rerun)(unsigned int irq); + /* + * Set the type of the IRQ. + */ + int (*type)(unsigned int irq, unsigned int, type); +}; + +ack - required. May be the same function as mask for IRQs + handled by do_level_IRQ. +mask - required. +unmask - required. +rerun - optional. Not required if you're using do_level_IRQ for all + IRQs that use this 'irqchip'. Generally expected to re-trigger + the hardware IRQ if possible. If not, may call the handler + directly. +type - optional. If you don't support changing the type of an IRQ, + it should be null so people can detect if they are unable to + set the IRQ type. + +For each IRQ, we keep the following information: + + - "disable" depth (number of disable_irq()s without enable_irq()s) + - flags indicating what we can do with this IRQ (valid, probe, + noautounmask) as before + - status of the IRQ (probing, enable, etc) + - chip + - per-IRQ handler + - irqaction structure list + +The handler can be one of the 3 standard handlers - "level", "edge" and +"simple", or your own specific handler if you need to do something special. + +The "level" handler is what we currently have - its pretty simple. +"edge" knows about the brokenness of such IRQ implementations - that you +need to leave the hardware IRQ enabled while processing it, and queueing +further IRQ events should the IRQ happen again while processing. The +"simple" handler is very basic, and does not perform any hardware +manipulation, nor state tracking. This is useful for things like the +SMC9196 and USAR above. + +So, what's changed? + +1. Machine implementations must not write to the irqdesc array. + +2. New functions to manipulate the irqdesc array. The first 4 are expected + to be useful only to machine specific code. The last is recommended to + only be used by machine specific code, but may be used in drivers if + absolutely necessary. + + set_irq_chip(irq,chip) + + Set the mask/unmask methods for handling this IRQ + + set_irq_handler(irq,handler) + + Set the handler for this IRQ (level, edge, simple) + + set_irq_chained_handler(irq,handler) + + Set a "chained" handler for this IRQ - automatically + enables this IRQ (eg, Neponset and SA1111 handlers). + + set_irq_flags(irq,flags) + + Set the valid/probe/noautoenable flags. + + set_irq_type(irq,type) + + Set active the IRQ edge(s)/level. This replaces the + SA1111 INTPOL manipulation, and the set_GPIO_IRQ_edge() + function. Type should be one of the following: + + #define IRQT_NOEDGE (0) + #define IRQT_RISING (__IRQT_RISEDGE) + #define IRQT_FALLING (__IRQT_FALEDGE) + #define IRQT_BOTHEDGE (__IRQT_RISEDGE|__IRQT_FALEDGE) + #define IRQT_LOW (__IRQT_LOWLVL) + #define IRQT_HIGH (__IRQT_HIGHLVL) + +3. set_GPIO_IRQ_edge() is obsolete, and should be replaced by set_irq_type. + +4. Direct access to SA1111 INTPOL is depreciated. Use set_irq_type instead. + +5. A handler is expected to perform any necessary acknowledgement of the + parent IRQ via the correct chip specific function. For instance, if + the SA1111 is directly connected to a SA1110 GPIO, then you should + acknowledge the SA1110 IRQ each time you re-read the SA1111 IRQ status. + +6. For any child which doesn't have its own IRQ enable/disable controls + (eg, SMC9196), the handler must mask or acknowledge the parent IRQ + while the child handler is called, and the child handler should be the + "simple" handler (not "edge" nor "level"). After the handler completes, + the parent IRQ should be unmasked, and the status of all children must + be re-checked for pending events. (see the Neponset IRQ handler for + details). + +7. fixup_irq() is gone, as is include/asm-arm/arch-*/irq.h + +Please note that this will not solve all problems - some of them are +hardware based. Mixing level-based and edge-based IRQs on the same +parent signal (eg neponset) is one such area where a software based +solution can't provide the full answer to low IRQ latency. + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/arm/mem_alignment linux-2.5/Documentation/arm/mem_alignment --- linux-2.5.5/Documentation/arm/mem_alignment Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/arm/mem_alignment Tue Feb 26 21:24:48 2002 @@ -0,0 +1,58 @@ +Too many problems poped up because of unnoticed misaligned memory access in +kernel code lately. Therefore the alignment fixup is now unconditionally +configured in for SA11x0 based targets. According to Alan Cox, this is a +bad idea to configure it out, but Russell King has some good reasons for +doing so on some f***ed up ARM architectures like the EBSA110. However +this is not the case on many design I'm aware of, like all SA11x0 based +ones. + +Of course this is a bad idea to rely on the alignment trap to perform +unaligned memory access in general. If those access are predictable, you +are better to use the macros provided by include/asm/unaligned.h. The +alignment trap can fixup misaligned access for the exception cases, but at +a high performance cost. It better be rare. + +Now for user space applications, it is possible to configure the alignment +trap to SIGBUS any code performing unaligned access (good for debugging bad +code), or even fixup the access by software like for kernel code. The later +mode isn't recommended for performance reasons (just think about the +floating point emulation that works about the same way). Fix your code +instead! + +Please note that randomly changing the behaviour without good thought is +real bad - it changes the behaviour of all unaligned instructions in user +space, and might cause programs to fail unexpectedly. + +To change the alignment trap behavior, simply echo a number into +/proc/sys/debug/alignment. The number is made up from various bits: + +bit behavior when set +--- ----------------- + +0 A user process performing an unaligned memory access + will cause the kernel to print a message indicating + process name, pid, pc, instruction, address, and the + fault code. + +1 The kernel will attempt to fix up the user process + performing the unaligned access. This is of course + slow (think about the floating point emulator) and + not recommended for production use. + +2 The kernel will send a SIGBUS signal to the user process + performing the unaligned access. + +Note that not all combinations are supported - only values 0 through 5. +(6 and 7 don't make sense). + +For example, the following will turn on the warnings, but without +fixing up or sending SIGBUS signals: + + echo 1 > /proc/sys/debug/alignment + +You can also read the content of the same file to get statistical +information on unaligned access occurences plus the current mode of +operation for user space code. + + +Nicolas Pitre, Mar 13, 2001. Modified Russell King, Nov 30, 2001. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/driver-model.txt linux-2.5/Documentation/driver-model.txt --- linux-2.5.5/Documentation/driver-model.txt Wed Feb 20 02:10:59 2002 +++ linux-2.5/Documentation/driver-model.txt Fri Mar 1 15:07:37 2002 @@ -118,7 +118,18 @@ By virtue of having a complete hierarchical view of all the devices in the system, exporting a complete hierarchical view to userspace becomes relatively -easy. +easy. This has been accomplished by implementing a special purpose virtual +file system named driverfs. It is hence possible for the user to mount the +whole driverfs on a particular mount point in the unified UNIX file hierarchy. + +This can be done permanently by providing the following entry into the +/dev/fstab (under the provision that the mount point does exist, of course): + +none /devices driverfs defaults 0 0 + +Or by hand on the command line: + +~: mount -t driverfs none /devices Whenever a device is inserted into the tree, a directory is created for it. This directory may be populated at each layer of discovery - the global layer, @@ -342,6 +353,8 @@ user requests the system to suspend, it will walk the device tree, as exported via driverfs, and tell each device to go to sleep. It will do this multiple times based on what the system policy is. + +[ FIXME: URL pointer to the corresponding utility is missing here! ] Device resume should happen in the same manner when the system awakens. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/fb/tridentfb.txt linux-2.5/Documentation/fb/tridentfb.txt --- linux-2.5.5/Documentation/fb/tridentfb.txt Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/fb/tridentfb.txt Fri Feb 8 03:15:29 2002 @@ -0,0 +1,49 @@ +Tridentfb is a framebuffer driver for some Trident chip based cards. + +The following list of chips is thought to be supported although not all are +tested: + +those from the Image series with Cyber in their names - accelerated +those with Blade in their names (Blade3D,CyberBlade...) - accelerated +the newer CyberBladeXP family - nonaccelerated + +Only PCI/AGP based cards are supported, none of the older Tridents. + +How to use it? +============== +Just do your usual console work :) + +When booting you can pass the following parameters +================================================== + +noaccel - turns off acceleration (when it doesn't work for your card) +accel - force text acceleration (for boards which by default are noacceled) + +fp - use flat panel related stuff +crt - assume monitor is present instead of fp + +center - for flat panels and resolutions smaller than native size center the + image, otherwise use +stretch + +memsize - integer value in Kb, use if your card's memory size is misdetected. + look at the driver output to see what it says when initializing. +memdiff - integer value in Kb,should be nonzero if your card reports + more memory than it actually has.For instance mine is 192K less than + detection says in all three BIOS selectable situations 2M, 4M, 8M. + Only use if your video memory is taken from main memory hence of + configurable size.Otherwise use memsize. + If in some modes which barely fit the memory you see garbage at the bottom + this might help by not letting change to that mode anymore. + +nativex - the width in pixels of the flat panel.If you know it (usually 1024 + 800 or 1280) and it is not what the driver seems to detect use it. + +bpp - bits per pixel (8,16 or 32) +mode - a mode name like 800x600 (as described in Documentation/fb/modedb.txt) + +Using insane values for the above parameters will probably result in driver +misbehaviour so take care(for instance memsize=12345678 or memdiff=23784 or +nativex=93) + +Contact: jani@astechnix.ro diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/filesystems/00-INDEX linux-2.5/Documentation/filesystems/00-INDEX --- linux-2.5.5/Documentation/filesystems/00-INDEX Wed Feb 20 02:11:03 2002 +++ linux-2.5/Documentation/filesystems/00-INDEX Fri Mar 1 15:07:37 2002 @@ -22,6 +22,8 @@ - info and mount options for the OS/2 HPFS. isofs.txt - info and mount options for the ISO 9660 (CDROM) filesystem. +jfs.txt + - info and mount options for the JFS filesystem. ncpfs.txt - info on Novell Netware(tm) filesystem using NCP protocol. ntfs.txt diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/filesystems/Locking linux-2.5/Documentation/filesystems/Locking --- linux-2.5.5/Documentation/filesystems/Locking Wed Feb 20 02:10:59 2002 +++ linux-2.5/Documentation/filesystems/Locking Mon Feb 25 22:20:45 2002 @@ -134,6 +134,10 @@ int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); int (*commit_write)(struct file *, struct page *, unsigned, unsigned); int (*bmap)(struct address_space *, long); + int (*flushpage) (struct page *, unsigned long); + int (*releasepage) (struct page *, int); + int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int); + locking rules: All may block BKL PageLocked(page) @@ -143,6 +147,8 @@ prepare_write: no yes commit_write: no yes bmap: yes +flushpage: no yes +releasepage: no yes ->prepare_write(), ->commit_write(), ->sync_page() and ->readpage() may be called from the request handler (/dev/loop). @@ -155,6 +161,15 @@ filesystems and by the swapper. The latter will eventually go away. All instances do not actually need the BKL. Please, keep it that way and don't breed new callers. + ->flushpage() is called when the filesystem must attempt to drop +some or all of the buffers from the page when it is being truncated. It +returns zero on success. If ->flushpage is zero, the kernel uses +block_flushpage() instead. + ->releasepage() is called when the kernel is about to try to drop the +buffers from the page in preparation for freeing it. It returns zero to +indicate that the buffers are (or may be) freeable. If ->releasepage is zero, +the kernel assumes that the fs has no private interest in the buffers. + Note: currently almost all instances of address_space methods are using BKL for internal serialization and that's one of the worst sources of contention. Normally they are calling library functions (in fs/buffer.c) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/filesystems/cramfs.txt linux-2.5/Documentation/filesystems/cramfs.txt --- linux-2.5.5/Documentation/filesystems/cramfs.txt Wed Feb 20 02:11:05 2002 +++ linux-2.5/Documentation/filesystems/cramfs.txt Mon Feb 25 22:20:45 2002 @@ -10,7 +10,7 @@ You can't write to a cramfs filesystem (making it compressible and compact also makes it _very_ hard to update on-the-fly), so you have to -create the disk image with the "mkcramfs" utility in scripts/cramfs. +create the disk image with the "mkcramfs" utility. Usage Notes @@ -19,9 +19,7 @@ File sizes are limited to less than 16MB. Maximum filesystem size is a little over 256MB. (The last file on the -filesystem is allowed to extend past 256MB.) (Comments in mkcramfs.c -suggest that ROM sizes may be limited to 64MB, though that's not a -limitation in cramfs code.) +filesystem is allowed to extend past 256MB.) Only the low 8 bits of gid are stored. The current version of mkcramfs simply truncates to 8 bits, which is a potential security @@ -48,18 +46,28 @@ For /usr/share/magic ------------------- +-------------------- -0 long 0x28cd3d45 Linux cramfs ->4 long x size %d ->8 long x flags 0x%x ->12 long x future 0x%x +0 ulelong 0x28cd3d45 Linux cramfs offset 0 +>4 ulelong x size %d +>8 ulelong x flags 0x%x +>12 ulelong x future 0x%x >16 string >\0 signature "%.16s" ->32 long x fsid.crc 0x%x ->36 long x fsid.edition %d ->40 long x fsid.blocks %d ->44 long x fsid.files %d +>32 ulelong x fsid.crc 0x%x +>36 ulelong x fsid.edition %d +>40 ulelong x fsid.blocks %d +>44 ulelong x fsid.files %d >48 string >\0 name "%.16s" +512 ulelong 0x28cd3d45 Linux cramfs offset 512 +>516 ulelong x size %d +>520 ulelong x flags 0x%x +>524 ulelong x future 0x%x +>528 string >\0 signature "%.16s" +>544 ulelong x fsid.crc 0x%x +>548 ulelong x fsid.edition %d +>552 ulelong x fsid.blocks %d +>556 ulelong x fsid.files %d +>560 string >\0 name "%.16s" Hacker Notes diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/filesystems/jfs.txt linux-2.5/Documentation/filesystems/jfs.txt --- linux-2.5.5/Documentation/filesystems/jfs.txt Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/filesystems/jfs.txt Fri Mar 1 15:07:37 2002 @@ -0,0 +1,136 @@ +IBM's Journaled File System (JFS) for Linux version 1.0.15 +Team members +Steve Best sbest@us.ibm.com +Dave Kleikamp shaggy@austin.ibm.com +Barry Arndt barndt@us.ibm.com +Christoph Hellwig hch@caldera.de + + +Release February 15, 2002 (version 1.0.15) + +This is our fifty-third release of IBM's Enterprise JFS technology port to Linux. +Beta 1 was release 0.1.0 on 12/8/2000, Beta 2 was release 0.2.0 on 3/7/2001, +Beta 3 was release 0.3.0 on 4/30/2001, and release 1.0.0 on 6/28/2001. + +The changelog.jfs file contains detailed information of changes done in each source +code drop. + +JFS has a source tree that can be built on 2.4.3 - 2.4.17 and 2.5.4 kernel.org +source trees. + +Our current goal on the 2.5.x series of the kernel is to update to the latest +2.5.x version and only support the latest version of this kernel. +This will change when the distros start shipping the 2.5.x series of the kernel. + +Our current goal on the 2.4.x series of the kernel is to continue to support +all of the kernels in this series as we do today. + +There is an anonymous cvs access available for the JFS tree. The steps below are +what is needed to pull the JFS cvs tree from the oss.software.ibm.com server. + +id anoncvs +password anoncvs + +To checkout 2.4.x series of the JFS files do the following: +CVSROOT should be set to :pserver:anoncvs@oss.software.ibm.com:/usr/cvs/jfs +cvs checkout linux24 + +To checkout 2.5.2 series of the JFS files do the following: +CVSROOT should be set to :pserver:anoncvs@oss.software.ibm.com:/usr/cvs/jfs +cvs checkout linux25 + +To checkout the JFS utilities do the following: +CVSROOT should be set to :pserver:anoncvs@oss.software.ibm.com:/usr/cvs/jfs +cvs checkout jfsutils + +The cvs tree contains the latest changes being done to JFS. To receive notification +of commits to the cvs tree, please send e-mail to linuxjfs@us.ibm.com stating that +you would like notifications sent to you. + +The jfs-2.4-1.0.15-patch.tar.gz is the easiest way to get the latest file system +source code on your system. There are also patch files that can move your jfs source +code from one release to another. If you have release 1.0.14 and would like to move +to release 1.0.15 the patch file named jfs-2.4-1_0_14-to-1_0_15-patch.gz will do that. + +The jfs-2.4-1.0.15-patch.tar.gz file contains a readme and patch files for different +levels of the 2.4 kernel. Please see the README in the jfs-2.4-1.0.15-patch.tar.gz +file for help on applying the two patch files. + + +The following files in the kernel source tree have been changed so JFS can be built. +The jfs-2.4-1.0.15.tar.gz source tar ball contains each of the files below with +the extension of the kernel level it is associated with. As an example, there are now +four Config.in files named Config.in-2.4.0, Config.in-2.4.5, Config.in-2.4.7 and +Config.in-2.4.17. + + +If you use the jfs-2.4-1.0.15.tar.gz to build JFS you must rename each of the +kernel files to the file names listed below. The standard kernel from www.kernel.org +is the source of the kernel files that are included in the jfs tar file. + + +In sub dir fs Config.in, Makefile +In sub dir fs/nls Config.in +In sub dir Documentation Configure.help, Changes +In sub dir Documentation/filesystems 00-INDEX +In sub dir linux MAINTAINERS + +Please backup the above files before the JFS tar file is added to the kernel source +tree. All JFS files are located in the include/linux/jfs or fs/jfs sub dirs. + +Our development team has used the Linux kernel levels 2.4.3 - 2.4.17 kernels +with gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release) +for our port so far. A goal of the JFS team is to have JFS run on all architectures +that Linux supports, there is no architecture specific code in JFS. JFS has been run +on the following architectures (x86, PowerPC, Alpha, s/390, ARM) so far. + +To make JFS build, during the "make config" step of building the kernel answer y to +the Prompt for development and/or incomplete code/drivers in the Code maturity level +options section. In the Filesystems section use the m for the answer to +JFS filesystem support (experimental) (CONFIG_JFS_FS) [Y/m/n?] + + +Build in /usr/src/linux with the command: + + +make modules +make modules_install + +If you rebuild jfs.o after having mounted and unmounted a partition, "modprobe -r jfs" +will unload the old module. + +For the file system debugging messages are being written to /var/log/messages. + +Please see the readme in the utilities package for information about building +the JFS utilities. + +JFS TODO list: + +Plans for our near term development items + + - get defrag capabilities operational in the FS + - get extendfs capabilities operational in the FS + - test EXTENDFS utility, for growing JFS partitions + - test defrag utility, calls file system to defrag the file system. + - add support for block sizes (512,1024,2048) + - add support for logfile on dedicated partition + + +Longer term work items + + - get access control list functionality operational + - get extended attributes functionality operational + - add quota support + +Please send bugs, comments, cards and letters to linuxjfs@us.ibm.com. + +The JFS mailing list can be subscribed to by using the link labeled "Mail list Subscribe" +at our web page http://oss.software.ibm.com/jfs/. + + + + + + + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/filesystems/porting linux-2.5/Documentation/filesystems/porting --- linux-2.5.5/Documentation/filesystems/porting Wed Feb 20 02:10:58 2002 +++ linux-2.5/Documentation/filesystems/porting Thu Feb 21 02:23:35 2002 @@ -81,11 +81,12 @@ [mandatory] ->lookup(), ->truncate(), ->create(), ->unlink(), ->mknod(), ->mkdir(), -->rmdir(), ->link(), ->symlink() and ->rename() are called without BKL now. -Grab it on the entry, drop upon return - that will guarantee the same -locking you used to have. If your method or its parts do not need BKL - -better yet, now you can shift lock_kernel() / unlock_kernel() so that -they would protect exactly what needs to be protected. +->rmdir(), ->link(), ->lseek(), ->symlink() and ->rename() are called +without BKL now. Grab it on the entry, drop upon return - that will +guarantee the same locking you used to have. If your method or its +parts do not need BKL - better yet, now you can shift lock_kernel() and +unlock_kernel() so that they would protect exactly what needs to be +protected. --- [informational] diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/filesystems/tmpfs.txt linux-2.5/Documentation/filesystems/tmpfs.txt --- linux-2.5.5/Documentation/filesystems/tmpfs.txt Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/filesystems/tmpfs.txt Thu Dec 13 16:32:35 2001 @@ -0,0 +1,102 @@ +Tmpfs is a file system which keeps all files in virtual memory. + + +Everything in tmpfs is temporary in the sense that no files will be +created on your hard drive. If you unmount a tmpfs instance, +everything stored therein is lost. + +tmpfs puts everything into the kernel internal caches and grows and +shrinks to accommodate the files it contains and is able to swap +unneeded pages out to swap space. It has maximum size limits which can +be adjusted on the fly via 'mount -o remount ...' + +If you compare it to ramfs (which was the template to create tmpfs) +you gain swapping and limit checking. Another similar thing is the RAM +disk (/dev/ram*), which simulates a fixed size hard disk in physical +RAM, where you have to create an ordinary filesystem on top. Ramdisks +cannot swap and you do not have the possibility to resize them. + +Since tmpfs lives completely in the page cache and on swap, all tmpfs +pages currently in memory will show up as cached. It will not show up +as shared or something like that. Further on you can check the actual +RAM+swap use of a tmpfs instance with df(1) and du(1). + + +tmpfs has the following uses: + +1) There is always a kernel internal mount which you will not see at + all. This is used for shared anonymous mappings and SYSV shared + memory. + + This mount does not depend on CONFIG_TMPFS. If CONFIG_TMPFS is not + set, the user visible part of tmpfs is not build. But the internal + mechanisms are always present. + +2) glibc 2.2 and above expects tmpfs to be mounted at /dev/shm for + POSIX shared memory (shm_open, shm_unlink). Adding the following + line to /etc/fstab should take care of this: + + tmpfs /dev/shm tmpfs defaults 0 0 + + Remember to create the directory that you intend to mount tmpfs on + if necessary (/dev/shm is automagically created if you use devfs). + + This mount is _not_ needed for SYSV shared memory. The internal + mount is used for that. (In the 2.3 kernel versions it was + necessary to mount the predecessor of tmpfs (shm fs) to use SYSV + shared memory) + +3) Some people (including me) find it very convenient to mount it + e.g. on /tmp and /var/tmp and have a big swap partition. But be + aware: loop mounts of tmpfs files do not work due to the internal + design. So mkinitrd shipped by most distributions will fail with a + tmpfs /tmp. + +4) And probably a lot more I do not know about :-) + + +tmpfs has a couple of mount options: + +size: The limit of allocated bytes for this tmpfs instance. The + default is half of your physical RAM without swap. If you + oversize your tmpfs instances the machine will deadlock + since the OOM handler will not be able to free that memory. +nr_blocks: The same as size, but in blocks of PAGECACHE_SIZE. +nr_inodes: The maximum number of inodes for this instance. The default + is half of the number of your physical RAM pages. + +These parameters accept a suffix k, m or g for kilo, mega and giga and +can be changed on remount. + +To specify the initial root directory you can use the following mount +options: + +mode: The permissions as an octal number +uid: The user id +gid: The group id + +These options do not have any effect on remount. You can change these +parameters with chmod(1), chown(1) and chgrp(1) on a mounted filesystem. + + +So 'mount -t tmpfs -o size=10G,nr_inodes=10k,mode=700 tmpfs /mytmpfs' +will give you tmpfs instance on /mytmpfs which can allocate 10GB +RAM/SWAP in 10240 inodes and it is only accessible by root. + + +TODOs: + +1) give the size option a percent semantic: If you give a mount option + size=50% the tmpfs instance should be able to grow to 50 percent of + RAM + swap. So the instance should adapt automatically if you add + or remove swap space. +2) loop mounts: This is difficult since loop.c relies on the readpage + operation. This operation gets a page from the caller to be filled + with the content of the file at that position. But tmpfs always has + the page and thus cannot copy the content to the given page. So it + cannot provide this operation. The VM had to be changed seriously + to achieve this. +3) Show the number of tmpfs RAM pages. (As shared?) + +Author: + Christoph Rohland , 1.12.01 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/kbuild/config-language.txt linux-2.5/Documentation/kbuild/config-language.txt --- linux-2.5.5/Documentation/kbuild/config-language.txt Wed Feb 20 02:11:01 2002 +++ linux-2.5/Documentation/kbuild/config-language.txt Mon Feb 4 22:15:16 2002 @@ -30,7 +30,7 @@ scripts/Configure make config, make oldconfig scripts/Menuconfig make menuconfig scripts/tkparse make xconfig - mconfig (in development) + mconfig ftp.kernel.org/pub/linux/kernel/people/hch/mconfig/ 'Configure' is a bash script which interprets Config.in files by sourcing them. Some of the Config Language commands are native bash commands; @@ -52,9 +52,6 @@ into an internal syntax tree and then hands the syntax tree to one of several user-interface front ends. -This document describes the behaviour of all four interpreters, even though -mconfig has not been released at the time of writing. - === Statements @@ -489,7 +486,7 @@ Configure: implemented Menuconfig: implemented XConfig: implemented -mconfig: not implemented +mconfig: implemented Example: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/kernel-parameters.txt linux-2.5/Documentation/kernel-parameters.txt --- linux-2.5.5/Documentation/kernel-parameters.txt Wed Feb 20 02:11:03 2002 +++ linux-2.5/Documentation/kernel-parameters.txt Fri Jan 18 17:23:40 2002 @@ -17,6 +17,7 @@ CD Appropriate CD support is enabled. DEVFS devfs support is enabled. DRM Direct Rendering Management support is enabled. + EFI EFI Partitioning (GPT) is enabled EIDE EIDE/ATAPI support is enabled. FB The frame buffer device is enabled. HW Appropriate hardware is enabled. @@ -218,6 +219,9 @@ gc_3= [HW,JOY] gdth= [HW,SCSI] + + gpt [EFI] Forces disk with valid GPT signature but + invalid Protective MBR to be treated as GPT. gscd= [HW,CD] diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/networking/3c359.txt linux-2.5/Documentation/networking/3c359.txt --- linux-2.5.5/Documentation/networking/3c359.txt Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/networking/3c359.txt Tue Feb 26 21:24:48 2002 @@ -0,0 +1,58 @@ + +3COM PCI TOKEN LINK VELOCITY XL TOKEN RING CARDS README + +Release 0.9.0 - Release + Jul 17th 2000 Mike Phillips + + 1.2.0 - Final + Feb 17th 2002 Mike Phillips + Updated for submission to the 2.4.x kernel. + +Thanks: + Terry Murphy from 3Com for tech docs and support, + Adam D. Ligas for testing the driver. + +Note: + This driver will NOT work with the 3C339 Token Ring cards, you need +to use the tms380 driver instead. + +Options: + +The driver accepts three options: ringspeed, pkt_buf_sz and message_level. + +These options can be specified differently for each card found. + +ringspeed: Has one of three settings 0 (default), 4 or 16. 0 will +make the card autosense the ringspeed and join at the appropriate speed, +this will be the default option for most people. 4 or 16 allow you to +explicitly force the card to operate at a certain speed. The card will fail +if you try to insert it at the wrong speed. (Although some hubs will allow +this so be *very* careful). The main purpose for explicitly setting the ring +speed is for when the card is first on the ring. In autosense mode, if the card +cannot detect any active monitors on the ring it will open at the same speed as +its last opening. This can be hazardous if this speed does not match the speed +you want the ring to operate at. + +pkt_buf_sz: This is this initial receive buffer allocation size. This will +default to 4096 if no value is entered. You may increase performance of the +driver by setting this to a value larger than the network packet size, although +the driver now re-sizes buffers based on MTU settings as well. + +message_level: Controls level of messages created by the driver. Defaults to 0: +which only displays start-up and critical messages. Presently any non-zero +value will display all soft messages as well. NB This does not turn +debuging messages on, that must be done by modified the source code. + +Variable MTU size: + +The driver can handle a MTU size upto either 4500 or 18000 depending upon +ring speed. The driver also changes the size of the receive buffers as part +of the mtu re-sizing, so if you set mtu = 18000, you will need to be able +to allocate 16 * (sk_buff with 18000 buffer size) call it 18500 bytes per ring +position = 296,000 bytes of memory space, plus of course anything +necessary for the tx sk_buff's. Remember this is per card, so if you are +building routers, gateway's etc, you could start to use a lot of memory +real fast. + +2/17/02 Mike Phillips + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/networking/arcnet-hardware.txt linux-2.5/Documentation/networking/arcnet-hardware.txt --- linux-2.5.5/Documentation/networking/arcnet-hardware.txt Wed Feb 20 02:11:02 2002 +++ linux-2.5/Documentation/networking/arcnet-hardware.txt Sun Mar 3 17:54:35 2002 @@ -2256,7 +2256,7 @@ When I got my two cards, one of them had this switch set to "enhanced". That card didn't work at all, it wasn't even recognized by the driver. The other card had this switch set to "compatible" and it behaved absolutely normally. I -guess that the switch on one of the cards, must have been changed accidently +guess that the switch on one of the cards, must have been changed accidentally when the card was taken out of its former host. The question remains unanswered, what is the purpose of the "enhanced" position? diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/networking/bonding.txt linux-2.5/Documentation/networking/bonding.txt --- linux-2.5.5/Documentation/networking/bonding.txt Wed Feb 20 02:10:58 2002 +++ linux-2.5/Documentation/networking/bonding.txt Sun Mar 3 17:54:35 2002 @@ -503,7 +503,7 @@ Resources and links =================== -Current developement on this driver is posted to: +Current development on this driver is posted to: - http://www.sourceforge.net/projects/bonding/ Donald Becker's Ethernet Drivers and diag programs may be found at : diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/networking/e1000.txt linux-2.5/Documentation/networking/e1000.txt --- linux-2.5.5/Documentation/networking/e1000.txt Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/networking/e1000.txt Tue Feb 26 21:24:48 2002 @@ -0,0 +1,245 @@ +Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters +=============================================================== + +February 5, 2002 + + +Contents +======== + +- In This Release +- Supported Adapters +- Command Line Parameters +- Speed and Duplex Configuration +- Known Issues +- Support + + +In This Release +=============== + +This file describes the Linux* Base Driver for the Intel(R) PRO/1000 Family +of Adapters, version 4.2.x. +This driver includes support for Itanium(TM)-based systems. + +This release version includes the following: + + - support for the ethtool 1.4 interface. A third-party application can use + the ethtool interface to get and set driver parameters. + + - the zero copy feature. Zero copy provides faster information throughput. + By default, this feature is enabled if using a kernel that supports it. + Zero copy is not supported on the original PWLA8490 (plain) adapter. + + +Supported Adapters +================== + +The following Intel network adapters are compatible with the drivers in this +release: + + Controller Adapter Name Board IDs + ---------- ------------ --------- + + 82542 PRO/1000 Gigabit Server Adapter 700262-xxx, 717037-xxx + + 82543 PRO/1000 F Server Adapter 738640-xxx, A38888-xxx, + A06512-xxx + + 82543 PRO/1000 T Server Adapter A19845-xxx, A33948-xxx + + 82544 PRO/1000 XT Server Adapter A51580-xxx + + 82544 PRO/1000 XF Server Adapter A50484-xxx + + 82544 PRO/1000 T Desktop Adapter A62947-xxx + + +To verify your Intel adapter is supported, find the board ID number on the +adapter. Look for a label that has a barcode and a number in the format of +123456-001 (six digits hyphen three digits). Match this to the list of +numbers above. + +For more information on how to identify your adapter, go to the Adapter & +Driver ID Guide at: + + http://support.intel.com/support/network/adapter/pro100/21397.htm + +For the latest Intel network drivers for Linux, go to: + + http://appsr.intel.com/scripts-df/support_intel.asp + + +Command Line Parameters +======================= + +If the driver is built as a module, the following parameters are used by +entering them on the command line with the modprobe or insmod command. +For example, with two PRO/1000 PCI adapters, entering: + + insmod e1000 TxDescriptors=80,128 + +loads the e1000 driver with 80 TX resources for the first adapter and 128 TX +resources for the second adapter. + +For more information about the AutoNeg, Duplex, and Speed parameters, see the +"Speed and Duplex Configuration" section in this document. + + +AutoNeg (Intel PRO/1000 T and PRO/1000 XT server adapters only) +Valid Range: 0-0x0F, 0x20-0x2F +Default Value: 0x2F + This parameter is a bit mask that specifies which speed and duplex + settings the board advertises. When this parameter is used, the Speed and + Duplex parameters must not be specified. + +Duplex (Intel PRO/1000 T and PRO/1000 XT server adapters only) +Valid Range: 0-2 (0=auto-negotiate, 1=half, 2=full) +Default Value: 0 + Defines the direction in which data is allowed to flow. Can by either one + or two-directional. If both Duplex and the link partner are set to auto- + negotiate, the board auto-detects the correct duplex. If the link partner + is forced (either full or half), Duplex defaults to half-duplex. + +FlowControl +Valid Range: 0-3 (0=none, 1=Rx only, 2=Tx only, 3=Rx&Tx) +Default: Read flow control settings from the EEPROM + This parameter controls the automatic generation(Tx) and response(Rx) to + Ethernet PAUSE frames. + +RxDescriptors +Valid Range: 80-256 for 82542 and 82543-based adapters + 80-4096 for 82544-based adapters +Default Value: 256 + This value is the number of receive descriptors allocated by the driver. + Increasing this value allows the driver to buffer more incoming packets. + Each descriptor is 16 bytes. A receive buffer is also allocated for each + descriptor and can be either 2048, 4096, 8192, or 16384 bytes, depending + on the MTU setting. + +RxIntDelay +Valid Range: 0-65535 (0=off) +Default Value: 64 + This value delays the generation of receive interrupts in units of 1.024 + microseconds. Receive interrupt reduction can improve CPU efficiency if + properly tuned for specific network traffic. Increasing this value adds + extra latency to frame reception and can end up decreasing the throughput + of TCP traffic. If the system is reporting dropped receives, this value + may be set too high, causing the driver to run out of available receive + descriptors. + +Speed (Intel PRO/1000 T and PRO/1000 XT server adapters only) +Valid Settings: 0, 10, 100, 1000 +Default Value: 0 (auto-negotiate at all supported speeds) + Speed forces the line speed to the specified value in megabits per second + (Mbps). If this parameter is not specified or is set to 0 and the link + partner is set to auto-negotiate, the board will auto-detect the correct + speed. Duplex must also be set when Speed is set to either 10 or 100. + +TxDescriptors +Valid Range: 80-256 for 82542 and 82543-based adapters + 80-4096 for 82544-based adapters +Default Value: 256 + This value is the number of transmit descriptors allocated by the driver. + Increasing this value allows the driver to queue more transmits. Each + descriptor is 16 bytes. + +TxIntDelay +Valid Range: 0-65535 (0=off) +Default Value: 64 + This value delays the generation of transmit interrupts in units of 1.024 + microseconds. Transmit interrupt reduction can improve CPU efficiency if + properly tuned for specific network traffic. If the system is reporting + dropped transmits, this value may be set too high causing the driver to + run out of available transmit descriptors. + +XsumRX (not available on the PRO/1000 Gigabit Server Adapter) +Valid Range: 0-1 +Default Value: 1 + A value of '1' indicates that the driver should enable IP checksum + offload for received packets (both UDP and TCP) to the adapter hardware. + + +Speed and Duplex Configuration +============================== + +Three keywords are used to control the speed and duplex configuration of the +PRO/1000 T and PRO/1000 XT server adapters. These keywords are Speed, Duplex, +and AutoNeg. + +If the board uses a fiber interface, these keywords are ignored, and the +fiber interface board only links at 1000 Mbps full-duplex. + +For copper-based boards, the keywords interact as follows: + + The default operation is auto-negotiate. The board advertises all supported + speed and duplex combinations, and it links at the highest common speed and + duplex mode IF the link partner is set to auto-negotiate. + + If Speed = 1000, limited auto-negotiation is enabled and only 1000 Mbps is + advertised (The 1000BaseT spec requires auto-negotiation.) + + If Speed = 10 or 100, then both Speed and Duplex must be set. Auto- + negotiation is disabled, and the AutoNeg parameter is ignored. Partner MUST + also be forced. + +The AutoNeg parameter is used when more control is required over the auto- +negotiation process. When this parameter is used, Speed and Duplex must not +be specified. This parameter is a bitmap that specifies which speed and +duplex settings are advertised to the link partner. + +Bit 7 6 5 4 3 2 1 0 +Speed (Mbps) N/A N/A 1000 N/A 100 100 10 10 +Duplex Full Full Half Full Half + +Note that setting AutoNeg does not guarantee that the board will link at the +highest specified speed or duplex mode, but the board will link at the +highest possible speed/duplex of the link partner IF the link partner is also +set to auto-negotiate. If the link partner is forced speed/duplex, the +adapter MUST be forced to the same speed/duplex. + + +Known Issues +============ + + Driver Hangs Under Heavy Traffic Loads + -------------------------------------- + + Intel is aware that previously released e1000 drivers may hang under very + specific types of heavy traffic loads. This version includes a workaround + that resets the adapter automatically if a hang condition is detected. This + workaround ensures network traffic flow is not affected when a hang occurs. + + Jumbo Frames System Requirement + ------------------------------- + + Memory allocation failures have been observed on Linux systems with 64 MB + of RAM or less that are running Jumbo Frames. If you are using Jumbo + Frames, your system may require more than the advertised minimum + requirement of 64 MB of system memory. + + +Support +======= + +For general information and support, go to the Intel support website at: + + http://support.intel.com + +If an issue is identified with the released source code on the supported +kernel with a supported adapter, email the specific information related to +the issue to linux.nics@intel.com. + + +License +======= + +This software program is released under the terms of a license agreement +between you ('Licensee') and Intel. Do not use or load this software or any +associated materials (collectively, the 'Software') until you have carefully +read the full terms and conditions of the LICENSE located in this software +package. By loading or using the Software, you agree to the terms of this +Agreement. If you do not agree with the terms of this Agreement, do not +install or use the Software. + +* Other names and brands may be claimed as the property of others. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/networking/ppp_generic.txt linux-2.5/Documentation/networking/ppp_generic.txt --- linux-2.5.5/Documentation/networking/ppp_generic.txt Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/networking/ppp_generic.txt Fri Feb 8 02:38:26 2002 @@ -0,0 +1,432 @@ + PPP Generic Driver and Channel Interface + ---------------------------------------- + + Paul Mackerras + paulus@samba.org + 7 Feb 2002 + +The generic PPP driver in linux-2.4 provides an implementation of the +functionality which is of use in any PPP implementation, including: + +* the network interface unit (ppp0 etc.) +* the interface to the networking code +* PPP multilink: splitting datagrams between multiple links, and + ordering and combining received fragments +* the interface to pppd, via a /dev/ppp character device +* packet compression and decompression +* TCP/IP header compression and decompression +* detecting network traffic for demand dialling and for idle timeouts +* simple packet filtering + +For sending and receiving PPP frames, the generic PPP driver calls on +the services of PPP `channels'. A PPP channel encapsulates a +mechanism for transporting PPP frames from one machine to another. A +PPP channel implementation can be arbitrarily complex internally but +has a very simple interface with the generic PPP code: it merely has +to be able to send PPP frames, receive PPP frames, and optionally +handle ioctl requests. Currently there are PPP channel +implementations for asynchronous serial ports, synchronous serial +ports, and for PPP over ethernet. + +This architecture makes it possible to implement PPP multilink in a +natural and straightforward way, by allowing more than one channel to +be linked to each ppp network interface unit. The generic layer is +responsible for splitting datagrams on transmit and recombining them +on receive. + + +PPP channel API +--------------- + +See include/linux/ppp_channel.h for the declaration of the types and +functions used to communicate between the generic PPP layer and PPP +channels. + +Each channel has to provide two functions to the generic PPP layer, +via the ppp_channel.ops pointer: + +* start_xmit() is called by the generic layer when it has a frame to + send. The channel has the option of rejecting the frame for + flow-control reasons. In this case, start_xmit() should return 0 + and the channel should call the ppp_output_wakeup() function at a + later time when it can accept frames again, and the generic layer + will then attempt to retransmit the rejected frame(s). If the frame + is accepted, the start_xmit() function should return 1. + +* ioctl() provides an interface which can be used by a user-space + program to control aspects of the channel's behaviour. This + procedure will be called when a user-space program does an ioctl + system call on an instance of /dev/ppp which is bound to the + channel. (Usually it would only be pppd which would do this.) + +The generic PPP layer provides seven functions to channels: + +* ppp_register_channel() is called when a channel has been created, to + notify the PPP generic layer of its presence. For example, setting + a serial port to the PPPDISC line discipline causes the ppp_async + channel code to call this function. + +* ppp_unregister_channel() is called when a channel is to be + destroyed. For example, the ppp_async channel code calls this when + a hangup is detected on the serial port. + +* ppp_output_wakeup() is called by a channel when it has previously + rejected a call to its start_xmit function, and can now accept more + packets. + +* ppp_input() is called by a channel when it has received a complete + PPP frame. + +* ppp_input_error() is called by a channel when it has detected that a + frame has been lost or dropped (for example, because of a FCS (frame + check sequence) error). + +* ppp_channel_index() returns the channel index assigned by the PPP + generic layer to this channel. The channel should provide some way + (e.g. an ioctl) to transmit this back to user-space, as user-space + will need it to attach an instance of /dev/ppp to this channel. + +* ppp_unit_number() returns the unit number of the ppp network + interface to which this channel is connected, or -1 if the channel + is not connected. + +Connecting a channel to the ppp generic layer is initiated from the +channel code, rather than from the generic layer. The channel is +expected to have some way for a user-level process to control it +independently of the ppp generic layer. For example, with the +ppp_async channel, this is provided by the file descriptor to the +serial port. + +Generally a user-level process will initialize the underlying +communications medium and prepare it to do PPP. For example, with an +async tty, this can involve setting the tty speed and modes, issuing +modem commands, and then going through some sort of dialog with the +remote system to invoke PPP service there. We refer to this process +as `discovery'. Then the user-level process tells the medium to +become a PPP channel and register itself with the generic PPP layer. +The channel then has to report the channel number assigned to it back +to the user-level process. From that point, the PPP negotiation code +in the PPP daemon (pppd) can take over and perform the PPP +negotiation, accessing the channel through the /dev/ppp interface. + +At the interface to the PPP generic layer, PPP frames are stored in +skbuff structures and start with the two-byte PPP protocol number. +The frame does *not* include the 0xff `address' byte or the 0x03 +`control' byte that are optionally used in async PPP. Nor is there +any escaping of control characters, nor are there any FCS or framing +characters included. That is all the responsibility of the channel +code, if it is needed for the particular medium. That is, the skbuffs +presented to the start_xmit() function contain only the 2-byte +protocol number and the data, and the skbuffs presented to ppp_input() +must be in the same format. + +The channel must provide an instance of a ppp_channel struct to +represent the channel. The channel is free to use the `private' field +however it wishes. The channel should initialize the `mtu' and +`hdrlen' fields before calling ppp_register_channel() and not change +them until after ppp_unregister_channel() returns. The `mtu' field +represents the maximum size of the data part of the PPP frames, that +is, it does not include the 2-byte protocol number. + +If the channel needs some headroom in the skbuffs presented to it for +transmission (i.e., some space free in the skbuff data area before the +start of the PPP frame), it should set the `hdrlen' field of the +ppp_channel struct to the amount of headroom required. The generic +PPP layer will attempt to provide that much headroom but the channel +should still check if there is sufficient headroom and copy the skbuff +if there isn't. + +On the input side, channels should ideally provide at least 2 bytes of +headroom in the skbuffs presented to ppp_input(). The generic PPP +code does not require this but will be more efficient if this is done. + + +Buffering and flow control +-------------------------- + +The generic PPP layer has been designed to minimize the amount of data +that it buffers in the transmit direction. It maintains a queue of +transmit packets for the PPP unit (network interface device) plus a +queue of transmit packets for each attached channel. Normally the +transmit queue for the unit will contain at most one packet; the +exceptions are when pppd sends packets by writing to /dev/ppp, and +when the core networking code calls the generic layer's start_xmit() +function with the queue stopped, i.e. when the generic layer has +called netif_stop_queue(), which only happens on a transmit timeout. +The start_xmit function always accepts and queues the packet which it +is asked to transmit. + +Transmit packets are dequeued from the PPP unit transmit queue and +then subjected to TCP/IP header compression and packet compression +(Deflate or BSD-Compress compression), as appropriate. After this +point the packets can no longer be reordered, as the decompression +algorithms rely on receiving compressed packets in the same order that +they were generated. + +If multilink is not in use, this packet is then passed to the attached +channel's start_xmit() function. If the channel refuses to take +the packet, the generic layer saves it for later transmission. The +generic layer will call the channel's start_xmit() function again +when the channel calls ppp_output_wakeup() or when the core +networking code calls the generic layer's start_xmit() function +again. The generic layer contains no timeout and retransmission +logic; it relies on the core networking code for that. + +If multilink is in use, the generic layer divides the packet into one +or more fragments and puts a multilink header on each fragment. It +decides how many fragments to use based on the length of the packet +and the number of channels which are potentially able to accept a +fragment at the moment. A channel is potentially able to accept a +fragment if it doesn't have any fragments currently queued up for it +to transmit. The channel may still refuse a fragment; in this case +the fragment is queued up for the channel to transmit later. This +scheme has the effect that more fragments are given to higher- +bandwidth channels. It also means that under light load, the generic +layer will tend to fragment large packets across all the channels, +thus reducing latency, while under heavy load, packets will tend to be +transmitted as single fragments, thus reducing the overhead of +fragmentation. + + +SMP safety +---------- + +The PPP generic layer has been designed to be SMP-safe. Locks are +used around accesses to the internal data structures where necessary +to ensure their integrity. As part of this, the generic layer +requires that the channels adhere to certain requirements and in turn +provides certain guarantees to the channels. Essentially the channels +are required to provide the appropriate locking on the ppp_channel +structures that form the basis of the communication between the +channel and the generic layer. This is because the channel provides +the storage for the ppp_channel structure, and so the channel is +required to provide the guarantee that this storage exists and is +valid at the appropriate times. + +The generic layer requires these guarantees from the channel: + +* The ppp_channel object must exist from the time that + ppp_register_channel() is called until after the call to + ppp_unregister_channel() returns. + +* No thread may be in a call to any of ppp_input(), ppp_input_error(), + ppp_output_wakeup(), ppp_channel_index() or ppp_unit_number() for a + channel at the time that ppp_unregister_channel() is called for that + channel. + +* ppp_register_channel() and ppp_unregister_channel() must be called + from process context, not interrupt or softirq/BH context. + +* The remaining generic layer functions may be called at softirq/BH + level but must not be called from a hardware interrupt handler. + +* The generic layer may call the channel start_xmit() function at + softirq/BH level but will not call it at interrupt level. Thus the + start_xmit() function may not block. + +* The generic layer will only call the channel ioctl() function in + process context. + +The generic layer provides these guarantees to the channels: + +* The generic layer will not call the start_xmit() function for a + channel while any thread is already executing in that function for + that channel. + +* The generic layer will not call the ioctl() function for a channel + while any thread is already executing in that function for that + channel. + +* By the time a call to ppp_unregister_channel() returns, no thread + will be executing in a call from the generic layer to that channel's + start_xmit() or ioctl() function, and the generic layer will not + call either of those functions subsequently. + + +Interface to pppd +----------------- + +The PPP generic layer exports a character device interface called +/dev/ppp. This is used by pppd to control PPP interface units and +channels. Although there is only one /dev/ppp, each open instance of +/dev/ppp acts independently and can be attached either to a PPP unit +or a PPP channel. This is achieved using the file->private_data field +to point to a separate object for each open instance of /dev/ppp. In +this way an effect similar to Solaris' clone open is obtained, +allowing us to control an arbitrary number of PPP interfaces and +channels without having to fill up /dev with hundreds of device names. + +When /dev/ppp is opened, a new instance is created which is initially +unattached. Using an ioctl call, it can then be attached to an +existing unit, attached to a newly-created unit, or attached to an +existing channel. An instance attached to a unit can be used to send +and receive PPP control frames, using the read() and write() system +calls, along with poll() if necessary. Similarly, an instance +attached to a channel can be used to send and receive PPP frames on +that channel. + +In multilink terms, the unit represents the bundle, while the channels +represent the individual physical links. Thus, a PPP frame sent by a +write to the unit (i.e., to an instance of /dev/ppp attached to the +unit) will be subject to bundle-level compression and to fragmentation +across the individual links (if multilink is in use). In contrast, a +PPP frame sent by a write to the channel will be sent as-is on that +channel, without any multilink header. + +A channel is not initially attached to any unit. In this state it can +be used for PPP negotiation but not for the transfer of data packets. +It can then be connected to a PPP unit with an ioctl call, which +makes it available to send and receive data packets for that unit. + +The ioctl calls which are available on an instance of /dev/ppp depend +on whether it is unattached, attached to a PPP interface, or attached +to a PPP channel. The ioctl calls which are available on an +unattached instance are: + +* PPPIOCNEWUNIT creates a new PPP interface and makes this /dev/ppp + instance the "owner" of the interface. The argument should point to + an int which is the desired unit number if >= 0, or -1 to assign the + lowest unused unit number. Being the owner of the interface means + that the interface will be shut down if this instance of /dev/ppp is + closed. + +* PPPIOCATTACH attaches this instance to an existing PPP interface. + The argument should point to an int containing the unit number. + This does not make this instance the owner of the PPP interface. + +* PPPIOCATTCHAN attaches this instance to an existing PPP channel. + The argument should point to an int containing the channel number. + +The ioctl calls available on an instance of /dev/ppp attached to a +channel are: + +* PPPIOCDETACH detaches the instance from the channel. This ioctl is + deprecated since the same effect can be achieved by closing the + instance. In order to prevent possible races this ioctl will fail + with an EINVAL error if more than one file descriptor refers to this + instance (i.e. as a result of dup(), dup2() or fork()). + +* PPPIOCCONNECT connects this channel to a PPP interface. The + argument should point to an int containing the interface unit + number. It will return an EINVAL error if the channel is already + connected to an interface, or ENXIO if the requested interface does + not exist. + +* PPPIOCDISCONN disconnects this channel from the PPP interface that + it is connected to. It will return an EINVAL error if the channel + is not connected to an interface. + +* All other ioctl commands are passed to the channel ioctl() function. + +The ioctl calls that are available on an instance that is attached to +an interface unit are: + +* PPPIOCSMRU sets the MRU (maximum receive unit) for the interface. + The argument should point to an int containing the new MRU value. + +* PPPIOCSFLAGS sets flags which control the operation of the + interface. The argument should be a pointer to an int containing + the new flags value. The bits in the flags value that can be set + are: + SC_COMP_TCP enable transmit TCP header compression + SC_NO_TCP_CCID disable connection-id compression for + TCP header compression + SC_REJ_COMP_TCP disable receive TCP header decompression + SC_CCP_OPEN Compression Control Protocol (CCP) is + open, so inspect CCP packets + SC_CCP_UP CCP is up, may (de)compress packets + SC_LOOP_TRAFFIC send IP traffic to pppd + SC_MULTILINK enable PPP multilink fragmentation on + transmitted packets + SC_MP_SHORTSEQ expect short multilink sequence + numbers on received multilink fragments + SC_MP_XSHORTSEQ transmit short multilink sequence nos. + + The values of these flags are defined in . Note + that the values of the SC_MULTILINK, SC_MP_SHORTSEQ and + SC_MP_XSHORTSEQ bits are ignored if the CONFIG_PPP_MULTILINK option + is not selected. + +* PPPIOCGFLAGS returns the value of the status/control flags for the + interface unit. The argument should point to an int where the ioctl + will store the flags value. As well as the values listed above for + PPPIOCSFLAGS, the following bits may be set in the returned value: + SC_COMP_RUN CCP compressor is running + SC_DECOMP_RUN CCP decompressor is running + SC_DC_ERROR CCP decompressor detected non-fatal error + SC_DC_FERROR CCP decompressor detected fatal error + +* PPPIOCSCOMPRESS sets the parameters for packet compression or + decompression. The argument should point to a ppp_option_data + structure (defined in ), which contains a + pointer/length pair which should describe a block of memory + containing a CCP option specifying a compression method and its + parameters. The ppp_option_data struct also contains a `transmit' + field. If this is 0, the ioctl will affect the receive path, + otherwise the transmit path. + +* PPPIOCGUNIT returns, in the int pointed to by the argument, the unit + number of this interface unit. + +* PPPIOCSDEBUG sets the debug flags for the interface to the value in + the int pointed to by the argument. Only the least significant bit + is used; if this is 1 the generic layer will print some debug + messages during its operation. This is only intended for debugging + the generic PPP layer code; it is generally not helpful for working + out why a PPP connection is failing. + +* PPPIOCGDEBUG returns the debug flags for the interface in the int + pointed to by the argument. + +* PPPIOCGIDLE returns the time, in seconds, since the last data + packets were sent and received. The argument should point to a + ppp_idle structure (defined in ). If the + CONFIG_PPP_FILTER option is enabled, the set of packets which reset + the transmit and receive idle timers is restricted to those which + pass the `active' packet filter. + +* PPPIOCSMAXCID sets the maximum connection-ID parameter (and thus the + number of connection slots) for the TCP header compressor and + decompressor. The lower 16 bits of the int pointed to by the + argument specify the maximum connection-ID for the compressor. If + the upper 16 bits of that int are non-zero, they specify the maximum + connection-ID for the decompressor, otherwise the decompressor's + maximum connection-ID is set to 15. + +* PPPIOCSNPMODE sets the network-protocol mode for a given network + protocol. The argument should point to an npioctl struct (defined + in ). The `protocol' field gives the PPP protocol + number for the protocol to be affected, and the `mode' field + specifies what to do with packets for that protocol: + + NPMODE_PASS normal operation, transmit and receive packets + NPMODE_DROP silently drop packets for this protocol + NPMODE_ERROR drop packets and return an error on transmit + NPMODE_QUEUE queue up packets for transmit, drop received + packets + + At present NPMODE_ERROR and NPMODE_QUEUE have the same effect as + NPMODE_DROP. + +* PPPIOCGNPMODE returns the network-protocol mode for a given + protocol. The argument should point to an npioctl struct with the + `protocol' field set to the PPP protocol number for the protocol of + interest. On return the `mode' field will be set to the network- + protocol mode for that protocol. + +* PPPIOCSPASS and PPPIOCSACTIVE set the `pass' and `active' packet + filters. These ioctls are only available if the CONFIG_PPP_FILTER + option is selected. The argument should point to a sock_fprog + structure (defined in ) containing the compiled BPF + instructions for the filter. Packets are dropped if they fail the + `pass' filter; otherwise, if they fail the `active' filter they are + passed but they do not reset the transmit or receive idle timer. + +* PPPIOCSMRRU enables or disables multilink processing for received + packets and sets the multilink MRRU (maximum reconstructed receive + unit). The argument should point to an int containing the new MRRU + value. If the MRRU value is 0, processing of received multilink + fragments is disabled. This ioctl is only available if the + CONFIG_PPP_MULTILINK option is selected. + +Last modified: 7-feb-2002 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/power/pci.txt linux-2.5/Documentation/power/pci.txt --- linux-2.5.5/Documentation/power/pci.txt Wed Feb 20 02:10:58 2002 +++ linux-2.5/Documentation/power/pci.txt Sun Mar 3 17:54:35 2002 @@ -63,7 +63,7 @@ callbacks. This currently takes place only during APM state transitions. Upon going to sleep, the PCI subsystem walks its device tree twice. Both times, it does -a depth first walk of the device tree. The first walk saves each of the device's state +a depth first walk of the device tree. The first walk saves each of the device's state and checks for devices that will prevent the system from entering a global power state. The next walk then places the devices in a low power state. @@ -104,7 +104,7 @@ ----------------- Usage: - pci_restore_state(dev,buffer); + pci_restore_state(dev, buffer); Description: Restore previously saved config space. (First 64 bytes only); @@ -117,7 +117,7 @@ ------------------- Usage: - pci_set_power_state(dev,state); + pci_set_power_state(dev, state); Description: Transition device to low power state using PCI PM Capabilities registers. @@ -132,7 +132,7 @@ --------------- Usage: - pci_enable_wake(dev,state,enable); + pci_enable_wake(dev, state, enable); Description: Enable device to generate PME# during low power state using PCI PM @@ -155,7 +155,7 @@ struct pci_driver: int (*save_state) (struct pci_dev *dev, u32 state); - int (*suspend)(struct pci_dev *dev, u32 state); + int (*suspend) (struct pci_dev *dev, u32 state); int (*resume) (struct pci_dev *dev); int (*enable_wake) (struct pci_dev *dev, u32 state, int enable); @@ -178,7 +178,7 @@ The driver can also interpret this function as a notification that it may be entering a sleep state in the near future. If it knows that the device cannot enter the -requested state, either because of lack of support for it, or because the devices is +requested state, either because of lack of support for it, or because the device is middle of some critical operation, then it should fail. This function should not be used to set any state in the device or the driver because diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/s390/Debugging390.txt linux-2.5/Documentation/s390/Debugging390.txt --- linux-2.5.5/Documentation/s390/Debugging390.txt Wed Feb 20 02:10:57 2002 +++ linux-2.5/Documentation/s390/Debugging390.txt Thu Dec 27 16:32:30 2001 @@ -237,9 +237,10 @@ On 390 our limitations & strengths make us slightly different. -For backward compatibility we are only allowed use 31 bits (2GB) -of our 32 bit addresses,however, we use entirely separate address -spaces for the user & kernel. +For backward compatibility ( because of the psw address hi bit which +indicates whether we are in 31 or 64 bit mode ) we are only allowed +use 31 bits (2GB) of our 32 bit addresses. However, +we use entirely separate address spaces for the user & kernel. This means we can support 2GB of non Extended RAM on s/390, & more with the Extended memory managment swap device & @@ -2123,6 +2124,12 @@ now do p/x (*(**$sp+56))&0x7fffffff & so on. + +Another good trick to look at addresses on the stack if you've somehow lost +the backchain is. +x/500xa $sp +This displays anything the name of any known functions above the stack pointer +for 500 bytes. Disassembling instructions without debug info --------------------------------------------- diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/sonypi.txt linux-2.5/Documentation/sonypi.txt --- linux-2.5.5/Documentation/sonypi.txt Wed Feb 20 02:10:54 2002 +++ linux-2.5/Documentation/sonypi.txt Tue Jan 8 01:17:10 2002 @@ -25,7 +25,8 @@ can be downloaded at: This driver supports also some ioctl commands for setting the LCD screen -brightness (some more commands may be added in the future). +brightness and querying the batteries charge information (some more +commands may be added in the future). This driver can also be used to set the camera controls on Picturebook series (brightness, contrast etc), and is used by the video4linux driver for the diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/sound/AD1816 linux-2.5/Documentation/sound/AD1816 --- linux-2.5.5/Documentation/sound/AD1816 Wed Feb 20 02:10:57 2002 +++ linux-2.5/Documentation/sound/AD1816 Mon Feb 4 22:15:16 2002 @@ -80,5 +80,5 @@ tek@rbg.informatik.tu-darmstadt.de Thorsten Knabe -Christoph Hellwig +Christoph Hellwig Last modified: 2000/09/20 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/sound/AudioExcelDSP16 linux-2.5/Documentation/sound/AudioExcelDSP16 --- linux-2.5.5/Documentation/sound/AudioExcelDSP16 Wed Feb 20 02:10:53 2002 +++ linux-2.5/Documentation/sound/AudioExcelDSP16 Mon Jan 14 22:39:44 2002 @@ -2,7 +2,7 @@ ------ Informations about Audio Excel DSP 16 driver can be found in the source -file lowlevel/aedsp16.c +file aedsp16.c Please, read the head of the source before using it. It contain useful informations. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/sound/NEWS linux-2.5/Documentation/sound/NEWS --- linux-2.5.5/Documentation/sound/NEWS Wed Feb 20 02:11:04 2002 +++ linux-2.5/Documentation/sound/NEWS Mon Feb 4 22:15:16 2002 @@ -1,6 +1,6 @@ Linux 2.4 Sound Changes 2000-September-25 -Christoph Hellwig, +Christoph Hellwig, @@ -9,9 +9,6 @@ The Linux 2.4 Kernel does have reliable in-kernel isapnp support. Some drivers (sb.o, ad1816.o awe_wave.o) do now support automatically detecting and configuring isapnp devices. -If you have a not yet supported isapnp soundcard, mail me the content -of '/proc/isapnp' on your system and some information about your card -and its driver(s) so I can try to get isapnp working for it. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/sound/OPL3-SA2 linux-2.5/Documentation/sound/OPL3-SA2 --- linux-2.5.5/Documentation/sound/OPL3-SA2 Wed Feb 20 02:10:55 2002 +++ linux-2.5/Documentation/sound/OPL3-SA2 Sun Mar 3 17:54:35 2002 @@ -65,7 +65,7 @@ ------------ In previous kernels (2.2.x), some configuration was required to -get the driver to talk to the card. Being the new millenium and +get the driver to talk to the card. Being the new millennium and all, the 2.4.x kernels now support auto-configuration if ISA PnP support is configured in. Theoretically, the driver even supports having more than one card in this case. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/sound/PAS16 linux-2.5/Documentation/sound/PAS16 --- linux-2.5.5/Documentation/sound/PAS16 Wed Feb 20 02:11:01 2002 +++ linux-2.5/Documentation/sound/PAS16 Sun Mar 3 20:43:46 2002 @@ -1,7 +1,7 @@ Pro Audio Spectrum 16 for 2.3.99 and later ========================================= -by Thomas Molina (tmolina@home.com) -last modified 3 Mar 2001 +by Thomas Molina (tmolina@cox.net) +last modified 2 Mar 2002 Acknowledgement to Axel Boldt (boldt@math.ucsb.edu) for stuff taken from Configure.help, Riccardo Facchetti for stuff from README.OSS, and others whose names I could not find. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/sound/README.OSS linux-2.5/Documentation/sound/README.OSS --- linux-2.5.5/Documentation/sound/README.OSS Wed Feb 20 02:10:54 2002 +++ linux-2.5/Documentation/sound/README.OSS Sun Mar 3 17:54:35 2002 @@ -542,7 +542,7 @@ SoftOSS keeps the samples loaded on the system's RAM so much RAM is required. SoftOSS should never be used on machines with less than 16 MB - of RAM since this is potentially dangerous (you may accidently run out + of RAM since this is potentially dangerous (you may accidentally run out of memory which probably crashes the machine). SoftOSS implements the wave table API originally designed for GUS. For diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/sysctl/vm.txt linux-2.5/Documentation/sysctl/vm.txt --- linux-2.5.5/Documentation/sysctl/vm.txt Wed Feb 20 02:11:04 2002 +++ linux-2.5/Documentation/sysctl/vm.txt Sun Mar 3 17:54:35 2002 @@ -21,6 +21,7 @@ - buffermem - freepages - kswapd +- max_map_count - overcommit_memory - page-cluster - pagecache @@ -167,6 +168,19 @@ and don't use much of it. Look at: mm/mmap.c::vm_enough_memory() for more information. + +============================================================== + +max_map_count: + +This file contains the maximum number of memory map areas a +process may have. Memory map areas are used as a side-effect +of calling malloc, directly by mmap and mprotect, and also +when loading shared libraries. + +While most applications need less than a thousand maps, +certain programs, particularly malloc debuggers, may consume +lots of them, e.g. up to one or two maps per allocation. ============================================================== diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/usb/auerswald.txt linux-2.5/Documentation/usb/auerswald.txt --- linux-2.5.5/Documentation/usb/auerswald.txt Wed Feb 20 02:11:04 2002 +++ linux-2.5/Documentation/usb/auerswald.txt Fri Mar 1 15:07:37 2002 @@ -19,9 +19,9 @@ auerswald and shipped as part of the java software. You may create the devices with: - mknod -m 666 /dev/usb/auer0 c 180 80 + mknod -m 666 /dev/usb/auer0 c 180 112 ... - mknod -m 666 /dev/usb/auer15 c 180 95 + mknod -m 666 /dev/usb/auer15 c 180 127 Future plans ============ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/usb/se401.txt linux-2.5/Documentation/usb/se401.txt --- linux-2.5.5/Documentation/usb/se401.txt Wed Feb 20 02:10:54 2002 +++ linux-2.5/Documentation/usb/se401.txt Sat Jan 12 12:32:40 2002 @@ -40,7 +40,7 @@ KNOWN PROBLEMS: The driver works fine with the usb-ohci and uhci host controller drivers, -the default settings also work with usb-uhci. But sending more then one bulk +the default settings also work with usb-uhci. But sending more than one bulk transfer at a time with usb-uhci doesn't work yet. Users of usb-ohci and uhci can safely enlarge SE401_NUMSBUF in se401.h in order to increase the throughput (and thus framerate). diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/usb/usb-serial.txt linux-2.5/Documentation/usb/usb-serial.txt --- linux-2.5.5/Documentation/usb/usb-serial.txt Wed Feb 20 02:10:55 2002 +++ linux-2.5/Documentation/usb/usb-serial.txt Fri Mar 1 15:07:37 2002 @@ -95,12 +95,13 @@ Kroah-Hartman at greg@kroah.com -Compaq iPAQ driver +Compaq iPAQ and HP Jornada driver - This driver can be used to connect to Compaq iPAQ PDAs running - Windows CE 3.0 using a USB autosync cable. It has been tested only on - the Compaq H3135. It should work with the H3600 and later models too. - It may work with other CE based handhelds as well. + This driver can be used to connect to Compaq iPAQ and HP Jornada PDAs + running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. It + has been tested only on the Compaq H3135, but is rumoured to work on + with the H3600 and later models as well as the Jornada 548 and 568. + With minor modifications, it may work for other CE based handhelds too. The driver presents a serial interface (usually on /dev/ttyUSB0) over which one may run ppp and establish a TCP/IP link to the iPAQ. Once this @@ -109,11 +110,14 @@ kbytes/sec for download/upload to the iPAQ. The driver works intermittently with the usb-uhci driver but quite - reliably with the uhci driver. Make sure you have the right driver - loaded - usb-uhci is often the default. + reliably with the uhci driver. However, performance is much better + with usb-uhci. It does not seem to work with ohci at all. You must setup hotplug to invoke pppd as soon as the iPAQ is connected. - A ppp script like the one below may be used: + A ppp script like the one below should be kept in the file + /etc/hotplug/usb/ipaq Remember to chmod +x. Make sure there are no + options in /etc/ppp/options or ~/.ppprc which conflict with the ones + given below. #!/bin/bash @@ -133,7 +137,7 @@ On connecting the cable, you should see the usual "Device Connected", "User Authenticated" messages flash by on your iPAQ. Once connected, you can use Win CE programs like ftpView, Pocket Outlook from the iPAQ - and other synce utilities from the Linux side. Remember to enable IP + and xcerdisp, synce utilities from the Linux side. Remember to enable IP forwarding. To use Pocket IE, follow the instructions given at diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/video4linux/Zoran linux-2.5/Documentation/video4linux/Zoran --- linux-2.5.5/Documentation/video4linux/Zoran Wed Feb 20 02:11:04 2002 +++ linux-2.5/Documentation/video4linux/Zoran Thu Dec 13 16:32:35 2001 @@ -160,9 +160,9 @@ set aside the necessary memory during boot time. There seem to be several versions of this patch against various kernel versions floating around in the net, you may obtain one e.g. from: - http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz You - also have to compile your driver AFTER installing that patch in order - to get it working + http://www.polyware.nl/~middelin/hob-v4l.html#bigphysarea + You also have to compile your driver AFTER installing that patch in + order to get it working or diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/video4linux/bttv/CARDLIST linux-2.5/Documentation/video4linux/bttv/CARDLIST --- linux-2.5.5/Documentation/video4linux/bttv/CARDLIST Wed Feb 20 02:10:55 2002 +++ linux-2.5/Documentation/video4linux/bttv/CARDLIST Sun Mar 3 17:54:35 2002 @@ -7,13 +7,13 @@ card=5 - Diamond DTV2000 card=6 - AVerMedia TVPhone card=7 - MATRIX-Vision MV-Delta - card=8 - Fly Video II (Bt848) - card=9 - TurboTV + card=8 - FlyVideo II (Bt848) LR26 + card=9 - IXMicro TurboTV card=10 - Hauppauge (bt878) card=11 - MIRO PCTV pro card=12 - ADS Technologies Channel Surfer TV card=13 - AVerMedia TVCapture 98 - card=14 - Aimslab VHX + card=14 - Aimslab Video Highway Xtreme (VHX) card=15 - Zoltrix TV-Max card=16 - Pixelview PlayTV (bt878) card=17 - Leadtek WinView 601 @@ -21,7 +21,7 @@ card=19 - LifeView FlyKit w/o Tuner card=20 - CEI Raffles Card card=21 - Lucky Star Image World ConferenceTV - card=22 - Phoebe Tv Master + FM + card=22 - Phoebe Tv Master + FM (CPH050) card=23 - Modular Technology MM205 PCTV, bt878 card=24 - [many vendors] CPH05X/06X (bt878) card=25 - Terratec/Vobis TV-Boostar @@ -54,12 +54,12 @@ card=52 - Pinnacle PCTV Studio Pro card=53 - Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS card=54 - Lifetec LT 9415 TV (LR90 Rev.F) - card=55 - BESTBUY Easy TV + card=55 - BESTBUY Easy TV (CPH031) card=56 - FlyVideo '98/FM - card=57 - GrandTec 'Grand Video Capture' - card=58 - Phoebe TV Master Only (No FM) - card=59 - TV Capturer - card=60 - MM100PCTV + card=57 - GrandTec 'Grand Video Capture' (Bt848) + card=58 - Phoebe TV Master Only (No FM) CPH060 + card=59 - TV Capturer (CPH03X) + card=60 - Modular Technology MM100PCTV card=61 - AG Electronics GMV1 card=62 - BESTBUY Easy TV (bt878) card=63 - ATI TV-Wonder @@ -72,6 +72,12 @@ card=70 - PV-BT878P+ card=71 - Flyvideo 98EZ (capture only) card=72 - Prolink PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM) + card=73 - Sensoray 311 + card=74 - RemoteVision MX (RV605) + card=75 - Powercolor MTV878/ MTV878R/ MTV878F + card=76 - Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP) + card=77 - GrandTec Multi Capture Card (Bt878) + card=78 - AOPEN VA1000 tuner.o type=0 - Temic PAL (4002 FH5) @@ -94,7 +100,7 @@ type=17 - Philips NTSC_M (MK2) type=18 - Temic PAL_I (4066 FY5) type=19 - Temic PAL* auto (4006 FN5) - type=20 - Temic PAL (4009 FR5) + type=20 - Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5) type=21 - Temic NTSC (4039 FR5) type=22 - Temic PAL/SECAM multi (4046 FM5) type=23 - Philips PAL_DK diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/video4linux/bttv/Cards linux-2.5/Documentation/video4linux/bttv/Cards --- linux-2.5.5/Documentation/video4linux/bttv/Cards Wed Feb 20 02:10:57 2002 +++ linux-2.5/Documentation/video4linux/bttv/Cards Sun Mar 3 17:54:35 2002 @@ -15,6 +15,10 @@ All other cards only differ by additional components as tuners, sound decoders, EEPROMs, teletext decoders ... +Unsupported Cards: +------------------ +Cards with Zoran (ZR) or Philips (SAA) or ISA are not supported by this driver. + MATRIX Vision ------------- @@ -137,20 +141,37 @@ 1851:1850 = Flyvideo 98 1851:1851 = Flyvideo 98 EZ (capture only) 2) There is a print on the PCB: - LR25 = Flyvideo (Zoran) - LR37 Rev.C = Capture only (ZR36120 + SAA7110) + LR25 = Flyvideo (Zoran ZR36120, SAA7110A) + LR26 Rev.N = Flyvideo II (Bt848) + Rev.O = Flyvideo II (Bt878) + LR37 Rev.C = Flyvideo EZ (Capture only, ZR36120 + SAA7110) + LR38 Rev.A1= Flyvideo II EZ (Bt848 capture only) LR50 Rev.Q = Flyvideo 98 (w/eeprom and PCI subsystem ID) - LR50 Rev.W = Flyvideo 98 (no eeprom) + Rev.W = Flyvideo 98 (no eeprom) LR51 Rev.E = Flyvideo 98 EZ (capture only) LR90 = Flyvideo 2000 series - LR90 Rev.F = Lifetec/Medion LT 9815 + LR91 = Stereo daughter card for LR90 LR97 = Flyvideo DVBS + LR138 Rev.C= Flyvideo 2000 (SAA7130) + or Flyvideo 3000 (SAA7134) w/Stereo TV + These exist in variations w/FM and w/Remote sometimes denoted + by suffixes "FM" and "R". + + Lifeview.com.tw states (Feb. 2002): + "The FlyVideo2000 and FlyVideo2000s product name have renamed to FlyVideo98." + Their Bt8x8 cards are listed as discontinued. + Flyvideo 2000S was probably sold as Flyvideo 3000 in some contries(Europe?). + The new Flyvideo 2000/3000 are SAA7130/SAA7134 based. + Flyvideo 2100/3100 are half-sized cards (for system integrators etc.) "Flyvideo II" had been the name for the 848 cards, nowadays (in Germany) this name is re-used for LR50 Rev.W. - The Lifeview website has even more names: Flyvideo III,2100,3000,3100. + The Lifeview website mentioned Flyvideo III at some time, but such a card + has never been seen. These cards are sold by many OEMs too. + FlyVideo A2 = LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821) + Typhoon TV card series: ----------------------- @@ -176,6 +197,7 @@ Guillemot --------- + Maxi-TV PCI (ZR36120) Maxi TV Video 2 = LR50 Rev.Q (FI1216MF, PAL BG+SECAM) Maxi TV Video 3 = CPH064 (PAL BG + SECAM) @@ -208,3 +230,163 @@ Genius/Kye ---------- Video Wonder/Genius Internet Video Kit = LR37 Rev.C + Video Wonder Pro II (848 or 878) = LR26 + +Tekram +------ + VideoCap C205 (Bt848) + VideoCap C210 (Zoran ZR36120 +Philips) + CaptureTV M200 (ISA) + CaptureTV M205 (Bt848) + +Lucky Star +---------- + Image World Conference TV = LR50 Rev. Q + +Leadtek +------- + WinView 601 (Bt848) + WinView 610 (Zoran) + WinFast2000 + +KNC One +------- + TV-Station + TV-Station SE (+Software Bundle) + TV-Station pro (+TV stereo) + TV-Station FM (+Radio) + TV-Station RDS (+RDS) + +PV951 cards: +------------ + These are sold as: + Boeder TV-FM Video Capture Card + Titanmedia Supervision TV-2400 + Provideo PV951 TF + 3DeMon PV951 + MediaForte TV-Vision PV951 + Yoko PV951 + +Highscreen +---------- + TV Karte = LR50 Rev.S + TV-Boostar = Terratec Terra TV+ Version 1.0 (Bt848, TDA9821) "ceb105.pcb" + +Zoltrix +------- + Face To Face TV MAX (Bt848) (PCB "VP-8482 Rev1.3") + Genie TV (Bt878) (PCB "VP-8790 Rev 2.1") + +AVerMedia +--------- + AVer FunTV Lite (ISA, AV3001 chipset) "M101.C" + AVerTV + AVerTV Stereo + AVerTV Studio (w/FM) + AVerMedia TV98 with Remote + AVerMedia TV/FM98 Stereo + AVerMedia TVCAM98 + TVCapture (Bt848) + TVPhone (Bt848) + TVCapture98 (="AVerMedia TV98" in USA) (Bt878) + TVPhone98 (Bt878, w/FM) + + PCB PCI-ID Model-Name Eeprom Tuner Sound Country + -------------------------------------------------------------------- + M1A8-A -- AVer TV-Phone FM1216 -- + M168-T 1461:0003 AVerTV Studio 48:17 FM1216 TDA9840T D (1) w/FM w/Remote + M168-U 1461:0004 TVCapture98 40:11 FI1216 -- D w/Remote + M168II-B 1461:0003 Medion MD9592 48:16 FM1216 TDA9873H D w/FM + + (1) Daughterboard MB68-A with TDA9820T and TDA9840T + +Aimslab +------- + Video Highway Xtreme (aka "VHX") (Bt848, FM w/ TEA5757) + +IXMicro +------- + IXTV BT848 + IXTV BT878 + TurboTV (Bt848) + +Lifetec/Medion/Tevion/Aldi +------- + LT9415/MD9415 = LR90 Rev. F + MD9592 = Avermedia TVphone98 (PCI_ID=1461:0003), PCB-Rev=M168II-B (w/TDA9873H) + +Modular Technologies (www.modulartech.com) UK +-------------------- + MM100 PCTV (Bt848) + MM205 PCTV (Bt878) + MM210 PCTV (Bt878) (Galaxy TV) + +Terratec +-------- + Terra TV+ Version 1.0 (Bt848), "ceb105.PCB" printed on the PCB, TDA9821 + Terra TV+ Version 1.1 (Bt878), "LR74 Rev.E" printed on the PCB, TDA9821 + Terra TValueRadio, "LR102 Rev.C" printed on the PCB + Terra TV/Radio+ Version 1.0, "80-CP2830100-0" TTTV3 printed on the PCB, i + "CPH010-E83" on the back, SAA6588T, TDA9873H + Terra TValue Version BT878, "80-CP2830110-0 TTTV4" printed on the PCB, + "CPH011-D83" on back + Terra TValue Version 1.0 "ceb105.PCB" (really identical to Terra TV+ Version 1.0) + + LR74 is a newer PCB revision of ceb105 (both incl. connector for Active Radio Upgrade) + + +Technisat +--------- + Mediafocus I (ZR36120/ZR36125) + Mediafocus II (SAA7146) + +Siemens +------- + Multimedia eXtension Board (MXB) (SAA7146, SAA7111) + +Stradis +------- + SDM275,SDM250,SDM026,SDM025 (SAA7146, IBMMPEG2): MPEG2 decoder only + +Powercolor +---------- + MTV878 + MTV878R w/Remote Control + MTV878F w/Remote Control w/FM radio + +Pinnacle +-------- + Mirovideo PCTV (Bt848) + Mirovideo PCTV SE (Bt848) + Mirovideo PCTV Pro (Bt848 + Daughterboard) + Studio PCTV Rave (Bt878 w/o infrared) + Studio PCTV + Studio PCTV Pro (Bt878 stereo w/ FM) + + DC1+ (ISA) + DC10 (zr36057 + zr36060 + saa7110 + adv7176) + DC10+ (zr36067 + zr36060 + saa7110 + adv7176) + DC20 + DC30 + DC30+ (zr36067 + zr36050 + zr36016 + vpx3220 + adv7176) + +Lenco +----- + MXR-9565 (=Technisat Mediafocus?) + MXR-9571 (Bt848) + MXR-9575 + MXR-9477 (Bt878) + MXTV-9578CP (= Prolink PV-BT878P+4E) + +Iomega +------ + Buz (Zoran zr36067 + zr36060 + SAA7111 + SAA7185) + +LML +--- + LML33 (zr36067 + zr36060 + bt819+ bt856) + +Grandtec +-------- + Grand Video Capture (Bt848) + Multi Capture Card (Bt878) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/video4linux/bttv/Insmod-options linux-2.5/Documentation/video4linux/bttv/Insmod-options --- linux-2.5.5/Documentation/video4linux/bttv/Insmod-options Wed Feb 20 02:10:56 2002 +++ linux-2.5/Documentation/video4linux/bttv/Insmod-options Sun Mar 3 17:54:35 2002 @@ -28,7 +28,7 @@ default is 0 (off). irq_debug=0/1 irq handler debug messages. default is 0 (off). - gbuffers=2-64 number of capture buffers for mmap'ed capture. + gbuffers=2-32 number of capture buffers for mmap'ed capture. default is 2. gbufsize= size of capture buffers. default and maximum value is 0x208000 (~2MB) @@ -38,6 +38,13 @@ push used by bttv. bttv will disable overlay by default on this hardware to avoid crashes. With this insmod option you can override this. + automute=0/1 Automatically mutes the sound if there is + no TV signal, on by default. You might try + to disable this if you have bad input signal + quality which leading to unwanted sound + dropouts. + chroma_agc=0/1 AGC of chroma signal, off by default. + adc_crush=0/1 Luminance ADC crush, on by default. bttv_gpio=0/1 gpiomask= @@ -89,6 +96,8 @@ insmod args for tda9874a: tda9874a_SIF=1/2 select sound IF input pin (1 or 2) (default is pin 1) + tda9874a_AMSEL=0/1 auto-mute select for NICAM (default=0) + Please read note 3 below! tda9874a_STD=n select TV sound standard (0..8): 0 - A2, B/G 1 - A2, M (Korea) @@ -100,11 +109,20 @@ 7 - NICAM, D/K (default) 8 - NICAM, L - Note: tda9874a is very similar to tda9874 (without 'A'-suffix), but - this driver will not work for the latter device (will not load). - Note: tda9874a and tda9875 (which is supported separately by + Note 1: tda9874a supports both tda9874h (old) and tda9874a (new) chips. + Note 2: tda9874h/a and tda9875 (which is supported separately by tda9875.o) use the same i2c address so both modules should not be used at the same time. + Note 3: Using tda9874a_AMSEL option depends on your TV card design! + AMSEL=0: auto-mute will switch between NICAM sound + and the sound on 1st carrier (i.e. FM mono or AM). + AMSEL=1: auto-mute will switch between NICAM sound + and the analog mono input (MONOIN pin). + If tda9874a decoder on your card has MONOIN pin not connected, then + use only tda9874_AMSEL=0 or don't specify this option at all. + For example: + card=65 (FlyVideo 2000S) - set AMSEL=1 or AMSEL=0 + card=72 (Prolink PV-BT878P rev.9B) - set AMSEL=0 only msp3400.o The driver for the msp34xx sound processor chips. If you have a diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/video4linux/bttv/README.freeze linux-2.5/Documentation/video4linux/bttv/README.freeze --- linux-2.5.5/Documentation/video4linux/bttv/README.freeze Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/video4linux/bttv/README.freeze Sun Mar 3 17:54:35 2002 @@ -0,0 +1,65 @@ + +If the box freezes hard with bttv ... +===================================== + +It might be a bttv driver bug. It also might be bad hardware. It also +might be something else ... + +Just mailing me "bttv freezes" isn't going to help much. This README +has a few hints how you can help to pin down the problem. + + +bttv bugs +--------- + +If some version works and another doesn't it is likely to be a driver +bug. It is very helpful if you can tell where exactly it broke +(i.e. the last working and the first broken version). + +With a hard freeze you probably doesn't find anything in the logfiles. +The only way to capture any kernel messages is to hook up a serial +console and let some terminal application log the messages. /me uses +screen. See Documentation/serial-console.txt for details on setting +up a serial console. + +Read Documentation/oops-tracing.txt to learn how to get any useful +information out of a register+stack dump printed by the kernel on +protection faults (so-called "kernel oops"). + +If you run into some kind of deadlock, you can try to dump a call trace +for each process using sysrq-t (see Documentation/sysrq.txt). ksymoops +will translate these dumps into kernel symbols too. This way it is +possible to figure where *exactly* some process in "D" state is stuck. + +I've seen reports that bttv 0.7.x crashes whereas 0.8.x works rock solid +for some people. Thus probably a small buglet left somewhere in bttv +0.7.x. I have no idea where exactly, it works stable for me and alot of +other people. But in case you have problems with the 0.7.x versions you +can give 0.8.x a try ... + + +hardware bugs +------------- + +Some hardware can't deal with PCI-PCI transfers (i.e. grabber => vga). +Sometimes problems show up with bttv just because of the high load on +the PCI bus. The bt848/878 chips have a few workarounds for known +incompatibilities, see README.quirks. + +Some mainboard have problems to deal correctly with multiple devices +doing DMA at the same time. bttv + ide seems to cause this sometimes, +if this is the case you likely see freezes only with video and hard disk +access at the same time. Updating the IDE driver to get the latest and +greatest workarounds for hardware bugs might fix these problems. + + +other +----- + +IRQ sharing is known to cause problems in some cases. It works just +fine in theory and many configurations. Neverless it might be worth a +try to shuffle around the PCI cards to give bttv another IRQ or make +it share the IRQ with some other piece of hardware. IRQ sharing with +VGA cards seems to cause trouble sometimes. I've also seen funny +effects with bttv sharing the IRQ with the ACPI bridge (and +apci-enabled kernel). diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/video4linux/bttv/Sound-FAQ linux-2.5/Documentation/video4linux/bttv/Sound-FAQ --- linux-2.5.5/Documentation/video4linux/bttv/Sound-FAQ Wed Feb 20 02:11:03 2002 +++ linux-2.5/Documentation/video4linux/bttv/Sound-FAQ Sun Mar 3 17:54:35 2002 @@ -62,7 +62,7 @@ { [ ... ] u32 gpiomask; - u32 audiomux[5]; /* audio mux: tuner, radio, external, internal, mute */ + u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */ }; gpiomask specifies which pins are used to control the audio mux chip. @@ -127,6 +127,9 @@ *_modulename - hint whenever some card needs this or that audio module loaded to work properly. has_radio - whenever this TV card has a radio tuner. +no_msp34xx - "1" disables loading of msp3400.o module +no_tda9875 - "1" disables loading of tda9875.o module +needs_tvaudio - set to "1" to load tvaudio.o module If some config item is specified both from the tvcards array and as insmod option, the insmod option takes precedence. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/video4linux/w9966.txt linux-2.5/Documentation/video4linux/w9966.txt --- linux-2.5.5/Documentation/video4linux/w9966.txt Wed Feb 20 02:11:03 2002 +++ linux-2.5/Documentation/video4linux/w9966.txt Thu Dec 13 16:32:35 2001 @@ -1,37 +1,33 @@ +W9966 Camera driver, written by Jakob Kemi (jakob.kemi@telia.com) -W9966 Camera driver, written by Jakob Kemi (jakob.kemi@post.utfors.se) +After a lot of work in softice & wdasm, reading .pdf-files and tiresome +trial-and-error work I've finally got everything to work. I needed vision for a +robotics project so I borrowed this camera from a friend and started hacking. +Anyway I've converted my original code from the AVR 8bit RISC C/ASM code into +a working Linux driver. -Ok, after a lot of work in softice, wdasm, reading pdf-files -and trial-and-error work I've finally got everything to work. -Since I needed some vision for a robotics project I borrowed -this camera from a friend and started hacking. Anyway I've -converted my original code from the AVR 8bit RISC C/asm -into a working linux driver. I would really appreciate _any_ -kind of feedback regarding this driver. - -To get it working quickly configure your kernel -to support parport, ieee1284, video4linux, experimental drivers -and w9966 +To get it working simply configure your kernel to support +parport, ieee1284, video4linux and w9966 -If w9966 is statically linked it will perform aggressive probing -for the camera. If built as a module you'll have more configuration options. +If w9966 is statically linked it will always perform aggressive probing for +the camera. If built as a module you'll have more configuration options. Options: -modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp) - + modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp) voila! you can also type 'modinfo -p w9966.o' for option usage (or checkout w9966.c) -I've only tested it with custom built testprograms -(http://hem.fyristorg.com/mogul/w9966.html) and with gqcam. -(you'll need to tweak the code to qcam a bit to make it work, -dimensions and such) +The only thing to keep in mind is that the image format is in Y-U-Y-V format +where every two pixels take 4 bytes. In SDL (www.libsdl.org) this format +is called VIDEO_PALETTE_YUV422 (16 bpp). + +A minimal test application (with source) is available from: + http://hem.fyristorg.com/mogul/w9966.html The slow framerate is due to missing DMA ECP read support in the parport drivers. I might add working EPP support later. Good luck! - - /Jakob + /Jakob Kemi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Documentation/watchdog-api.txt linux-2.5/Documentation/watchdog-api.txt --- linux-2.5.5/Documentation/watchdog-api.txt Thu Jan 1 00:00:00 1970 +++ linux-2.5/Documentation/watchdog-api.txt Sun Mar 3 17:54:35 2002 @@ -0,0 +1,365 @@ +The Linux Watchdog driver API. + +Copyright 2002 Christer Weingel + +Some parts of this document are copied verbatim from the sbc60xxwdt +driver which is (c) Copyright 2000 Jakob Oestergaard + +This document describes the state of the Linux 2.4.18 kernel. + +Introduction: + +A Watchdog Timer (WDT) is a hardware circuit that can reset the +computer system in case of a software fault. You probably knew that +already. + +Usually a userspace daemon will notify the kernel watchdog driver via the +/dev/watchdog special device file that userspace is still alive, at +regular intervals. When such a notification occurs, the driver will +usually tell the hardware watchdog that everything is in order, and +that the watchdog should wait for yet another little while to reset +the system. If userspace fails (RAM error, kernel bug, whatever), the +notifications cease to occur, and the hardware watchdog will reset the +system (causing a reboot) after the timeout occurs. + +The Linux watchdog API is a rather AD hoc construction and different +drivers implement different, and sometimes incompatible, parts of it. +This file is an attempt to document the existing usage and allow +future driver writers to use it as a reference. + +The simplest API: + +All drivers support the basic mode of operation, where the watchdog +activates as soon as /dev/watchdog is opened and will reboot unless +the watchdog is pinged within a certain time, this time is called the +timeout or margin. The simplest way to ping the watchdog is to write +some data to the device. So a very simple watchdog daemon would look +like this: + +int main(int argc, const char *argv[]) { + int fd=open("/dev/watchdog",O_WRONLY); + if (fd==-1) { + perror("watchdog"); + exit(1); + } + while(1) { + write(fd, "\0", 1); + sleep(10); + } +} + +A more advanced driver could for example check that a HTTP server is +still responding before doing the write call to ping the watchdog. + +When the device is closed, the watchdog is disabled. This is not +always such a good idea, since if there is a bug in the watchdog +daemon and it crashes the system will not reboot. Because of this, +some of the drivers support the configuration option "Disable watchdog +shutdown on close", CONFIG_WATCHDOG_NOWAYOUT. If it is set to Y when +compiling the kernel, there is no way of disabling the watchdog once +it has been started. So, if the watchdog dameon crashes, the system +will reboot after the timeout has passed. + +Some other drivers will not disable the watchdog, unless a specific +magic character 'V' has been sent /dev/watchdog just before closing +the file. If the userspace daemon closes the file without sending +this special character, the driver will assume that the daemon (and +userspace in general) died, and will stop pinging the watchdog without +disabling it first. This will then cause a reboot. + +The ioctl API: + +Some drivers also support an ioctl API. I belive this API was first +used in the Berkshire PC Watchdog driver and has been adopted by the +other drivers. + +Pinging the watchdog using an ioctl: + +All drivers that have an ioctl interface support at least one ioctl, +KEEPALIVE. This ioctl does exactly the same thing as a write to the +watchdog device, so the main loop in the above program could be +replaced with: + + while (1) { + ioctl(fd, WDIOC_KEEPALIVE, 0); + sleep(10); + } + +the argument to the ioctl is ignored. + +Setting and getting the timeout: + +For some drivers it is possible to modify the watchdog timeout on the +fly with the SETTIMEOUT ioctl, those drivers have the WDIOF_SETTIMEOUT +flag set in their option field. The argument is an integer +representing the timeout in seconds. The driver returns the real +timeout used in the same variable, and this timeout might differ from +the requested one due to limitation of the hardware. + + int timeout = 45; + ioctl(fd, WDIOC_SETTIMEOUT, &timeout); + printf("The timeout was set to %d seconds\n", timeout); + +This example might actually print "The timeout was set to 60 seconds" +if the device has a granularity of minutes for its timeout. + +Starting with the Linux 2.4.18 kernel, it is possible to query the +current timeout using the GETTIMEOUT ioctl. + + ioctl(fd, WDIOC_GETTIMEOUT, &timeout); + printf("The timeout was is %d seconds\n", timeout); + +Envinronmental monitoring: + +Some watchdog drivers can return more information about the system, +some do temperature, fan and power level monitoring, some can tell you +the reason for the last reebot of the system. The GETSUPPORT ioctl is +available to ask what the device can do: + + struct watchdog_info ident; + ioctl(fd, WDIOC_GETSUPPORT, &ident); + +the fields returned in the ident struct are: + + identity a string identifying the watchdog driver + firmware_version the firmware version of the card if available + options a flags describing what the device supports + +the options field can have the following bits set, and describes what +kind of information that the GET_STATUS and GET_BOOT_STATUS ioctls can +return. [FIXME -- Is this correct?] + + WDIOF_OVERHEAT Reset due to CPU overheat + WDIOF_FANFAULT Fan failed + WDIOF_EXTERN1 External relay 1 + WDIOF_EXTERN2 External relay 2 + WDIOF_POWERUNDER Power bad/power fault + WDIOF_CARDRESET Card previously reset the CPU + WDIOF_POWEROVER Power over voltage + WDIOF_KEEPALIVEPING Keep alive ping reply + WDIOF_SETTIMEOUT Can set/get the timeout + +[FIXME -- Can somebody explain what the flags mean in more detail, +especially KEEPALIVEPING?] + +For those drivers that return any bits set in the option field, the +GETSTATUS and GETBOOTSTATUS ioctls can be used to ask for the current +status, and the status at the last reboot, respectively. + + int flags; + ioctl(fd, WDIOC_GETSTATUS, &flags); + + or + + ioctl(fd, WDIOC_GETBOOTSTATUS, &flags); + +Note that not all devices support these two calls, and some only +support the GETBOOTSTATUS call. + +Some drivers can measure the temperature using the GETTEMP ioctl. The +returned value is the temperature in degrees farenheit. + + int temperature; + ioctl(fd, WDIOC_GETTEMP, &temperature); + +Finally the SETOPTIONS ioctl can be used to control some aspects of +the cards operation; right now the pcwd driver is the only one +supporting thiss ioctl. + + int options = 0; + ioctl(fd, WDIOC_SETOPTIONS, options); + +The following options are available: + + WDIOS_DISABLECARD Turn off the watchdog timer + WDIOS_ENABLECARD Turn on the watchdog timer + WDIOS_TEMPPANIC Kernel panic on temperature trip + +[FIXME -- better explanations] + +Implementations in the current drivers in the kernel tree: + +Here I have tried to summarize what the different drivers support and +where they do strange things compared to the other drivers. + +acquirewdt.c -- Acquire Single Board Computer + + This driver has a hardcoded timeout of 1 minute + + Supports CONFIG_WATCHDOG_NOWAYOUT + + GETSUPPORT returns KEEPALIVEPING. GETSTATUS will return 1 if + the device is open, 0 if not. [FIXME -- isn't this rather + silly? To be able to use the ioctl, the device must be open + and so GETSTATUS will always return 1]. + +advantechwdt.c -- Advantech Single Board Computer + + Timeout that defaults to 60 seconds, supports SETTIMEOUT. + + Supports CONFIG_WATCHDOG_NOWAYOUT + + GETSUPPORT returns WDIOF_KEEPALIVEPING and WDIOF_SETTIMEOUT. + The GETSTATUS call returns if the device is open or not. + [FIXME -- silliness again?] + +eurotechwdt.c -- Eurotech CPU-1220/1410 + + The timeout can be set using the SETTIMEOUT ioctl and defaults + to 60 seconds. + + Also has a module parameter "ev", event type which controls + what should happen on a timeout, the string "int" or anything + else that causes a reboot. [FIXME -- better description] + + Supports CONFIG_WATCHDOG_NOWAYOUT + + GETSUPPORT returns CARDRESET and WDIOF_SETTIMEOUT but + GETSTATUS is not supported and GETBOOTSTATUS just returns 0. + +i810-tco.c -- Intel 810 chipset + + Also has support for a lot of other i810 stuff, but the + watchdog is one of the things. + + The timeout is set using the module parameter "i810_margin", + which is in steps of 0.6 seconds where 2 -W: http://www.computone.com/ -W: http://www.wittsend.com/computone.html -L: linux-computone@lazuli.wittsend.com -S: Supported +P: Michael H. Warfield +M: Michael H. Warfield +W: http://www.computone.com/ +W: http://www.wittsend.com/computone.html +L: linux-computone@lazuli.wittsend.com +S: Supported COMX/MULTIGATE SYNC SERIAL DRIVERS P: Gergely Madarasz @@ -330,15 +346,6 @@ W: http://kbuild.sourceforge.net S: Maintained -CONFIGURE.HELP -P: Steven P. Cole -M: Steven P. Cole -P: Eric S. Raymond -M: Eric S. Raymond -L: kbuild-devel@lists.sourceforge.net -W: http://kbuild.sourceforge.net -S: Maintained - COSA/SRP SYNC SERIAL DRIVER P: Jan "Yenya" Kasprzak M: kas@fi.muni.cz @@ -428,9 +435,9 @@ DIGI INTL. EPCA DRIVER P: Chad Schwartz -M: support@dgii.com -L: digilnux@dgii.com -S: Maintained +M: support@dgii.com +L: digilnux@dgii.com +S: Maintained DIGI RIGHTSWITCH NETWORK DRIVER P: Rick Richardson @@ -452,12 +459,12 @@ S: Supported DISK GEOMETRY AND PARTITION HANDLING -P: Andries Brouwer -M: aeb@cwi.nl -W: http://www.win.tue.nl/~aeb/linux/Large-Disk.html -W: http://www.win.tue.nl/~aeb/linux/zip/zip-1.html -W: http://www.win.tue.nl/~aeb/partitions/partition_types-1.html -S: Maintained +P: Andries Brouwer +M: aeb@cwi.nl +W: http://www.win.tue.nl/~aeb/linux/Large-Disk.html +W: http://www.win.tue.nl/~aeb/linux/zip/zip-1.html +W: http://www.win.tue.nl/~aeb/partitions/partition_types-1.html +S: Maintained DISKQUOTA: P: Marco van Wieringen @@ -532,9 +539,9 @@ S: Maintained ETHERTEAM 16I DRIVER -P: Mika Kuoppala -M: miku@iki.fi -S: Maintained +P: Mika Kuoppala +M: miku@iki.fi +S: Maintained EXT2 FILE SYSTEM P: Remy Card @@ -575,7 +582,7 @@ FREEVXFS FILESYSTEM P: Christoph Hellwig -M: hch@caldera.de +M: hch@infradead.org W: ftp://ftp.openlinux.org/pub/people/hch/vxfs S: Maintained @@ -613,10 +620,10 @@ S: Maintained HFS FILESYSTEM -P: Adrian Sun -M: asun@cobaltnet.com -L: linux-kernel@vger.kernel.org -S: Maintained +P: Adrian Sun +M: asun@cobaltnet.com +L: linux-kernel@vger.kernel.org +S: Maintained HGA FRAMEBUFFER DRIVER P: Ferenc Bakonyi @@ -649,6 +656,11 @@ W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi S: Maintained +HPUSBSCSI +P: Oliver Neukum +M: drivers@neukum.org +S: Maintained + I2C DRIVERS P: Simon Vogl M: simon@tk.uni-linz.ac.at @@ -691,10 +703,10 @@ S: Maintained IBM ServeRAID RAID DRIVER -P: Keith Mitchell -M: ipslinux@us.ibm.com -W: http://www.developer.ibm.com/welcome/netfinity/serveraid.html -S: Supported +P: Keith Mitchell +M: ipslinux@us.ibm.com +W: http://www.developer.ibm.com/welcome/netfinity/serveraid.html +S: Supported IDE DRIVER [GENERAL] P: Andre Hedrick @@ -777,12 +789,25 @@ M: tigran@veritas.com S: Maintained +INTEL PRO/1000 GIGABIT ETHERNET SUPPORT +P: Chris Leech +M: christopher.leech@intel.com +P: Scott Feldman +M: scott.feldman@intel.com +S: Supported + INTERMEZZO FILE SYSTEM P: Peter J. Braam -M: braam@clusterfs.com -W: http://www.inter-mezzo.org/ -L: intermezzo-discuss@lists.sourceforge.net -S: Maintained +M: braam@clusterfs.com +W: http://www.inter-mezzo.org/ +L: intermezzo-discuss@lists.sourceforge.net +S: Maintained + +IOC3 DRIVER +P: Ralf Baechle +M: ralf@oss.sgi.com +L: linux-mips@oss.sgi.com +S: Maintained IP MASQUERADING: P: Juanjo Ciarlante @@ -796,11 +821,11 @@ S: Maintained IRDA SUBSYSTEM -P: Dag Brattli -M: Dag Brattli -L: linux-irda@pasta.cs.uit.no -W: http://irda.sourceforge.net/ -S: Maintained +P: Dag Brattli +M: Dag Brattli +L: linux-irda@pasta.cs.uit.no +W: http://irda.sourceforge.net/ +S: Maintained ISAPNP P: Jaroslav Kysela @@ -837,6 +862,13 @@ W: http://sources.redhat.com/jffs2/ S: Maintained +JFS FILESYSTEM +P: Dave Kleikamp +M: shaggy@austin.ibm.com +L: jfs-discussion@oss.software.ibm.com +W: http://oss.software.ibm.com/jfs/ +S: Supported + JOYSTICK DRIVER P: Vojtech Pavlik M: vojtech@suse.cz @@ -875,10 +907,10 @@ S: Maintained LANMEDIA WAN CARD DRIVER -P: Andrew Stanley-Jones -M: asj@lanmedia.com -W: http://www.lanmedia.com/ -S: Supported +P: Andrew Stanley-Jones +M: asj@lanmedia.com +W: http://www.lanmedia.com/ +S: Supported LAPB module P: Henner Eisen @@ -919,10 +951,10 @@ S: Maintained LOGICAL VOLUME MANAGER -P: Heinz Mauelshagen -L: linux-LVM@sistina.com -W: http://www.sistina.com/lvm -S: Maintained +P: Heinz Mauelshagen +L: linux-LVM@sistina.com +W: http://www.sistina.com/lvm +S: Maintained LSILOGIC/SYMBIOS/NCR 53C8XX and 53C1010 PCI-SCSI drivers P: Gerard Roudier @@ -969,10 +1001,9 @@ S: Maintained MICROTEK X6 SCANNER -P: Oliver Neukum -M: drivers@neukum.org -W: http://fachschaft.cup.uni-muenchen.de/~neukum/scanner.html -S: Maintained +P: Oliver Neukum +M: drivers@neukum.org +S: Maintained MIPS P: Ralf Baechle @@ -1015,9 +1046,9 @@ S: Maintained NATSEMI ETHERNET DRIVER (DP8381x) -P: Tim Hockin -M: thockin@hockin.org -S: Maintained +P: Tim Hockin +M: thockin@hockin.org +S: Maintained NCP FILESYSTEM P: Petr Vandrovec @@ -1088,17 +1119,17 @@ S: Maintained NFS CLIENT -P: Trond Myklebust -M: trond.myklebust@fys.uio.no -L: linux-kernel@vger.kernel.org -S: Maintained +P: Trond Myklebust +M: trond.myklebust@fys.uio.no +L: linux-kernel@vger.kernel.org +S: Maintained NI5010 NETWORK DRIVER -P: Jan-Pascal van Best and Andreas Mohr -M: Jan-Pascal van Best -M: Andreas Mohr <100.30936@germany.net> -L: linux-net@vger.kernel.org -S: Maintained +P: Jan-Pascal van Best and Andreas Mohr +M: Jan-Pascal van Best +M: Andreas Mohr <100.30936@germany.net> +L: linux-net@vger.kernel.org +S: Maintained NINJA SCSI-3 / NINJA SCSI-32Bi PCMCIA SCSI HOST ADAPTER DRIVER P: YOKOTA Hiroshi @@ -1127,7 +1158,7 @@ OLYMPIC NETWORK DRIVER P: Peter De Shrijver -M: p2@ace.ulyssis.student.ac.be +M: p2@ace.ulyssis.student.kuleuven.ac.be P: Mike Phillips M: mikep@linuxtr.net L: linux-net@vger.kernel.org @@ -1170,9 +1201,9 @@ PERSONALITY HANDLING P: Christoph Hellwig -M: hch@caldera.de +M: hch@infradead.org L: linux-abi-devel@lists.sourceforge.net -S: Supported +S: Maintained PCI ID DATABASE P: Jens Maurer @@ -1216,6 +1247,20 @@ L: linux-net@vger.kernel.org S: Maintained +PHILIPS NINO PALM PC +P: Steven Hill +M: sjhill@realitydiluted.com +L: linux-mips@oss.sgi.com +W: http://www.realitydiluted.com/projects/nino +S: Maintained + +PERMEDIA 3 FRAMEBUFFER DRIVER +P: Romain Dolbeau +M: dolbeau@irisa.fr +L: linux-fbdev-devel@lists.sourceforge.net +W: http://www.irisa.fr/prive/dolbeau/pm3fb/pm3fb.html +S: Maintained + PNP SUPPORT P: Tom Lees M: tom@lpsg.demon.co.uk @@ -1261,6 +1306,12 @@ W: http://www.alarsen.net/linux/qnx4fs/ S: Maintained +RADEON FRAMEBUFFER DISPLAY DRIVER +P: Ani Joshi +M: ajoshi@shell.unixbox.com +L: linux-fbdev-devel@lists.sourceforge.net +S: Maintained + RAGE128 FRAMEBUFFER DISPLAY DRIVER P: Ani Joshi M: ajoshi@shell.unixbox.com @@ -1280,11 +1331,11 @@ S: Maintained REISERFS FILE SYSTEM -P: Hans Reiser -M: reiserfs-dev@namesys.com -L: reiserfs-list@namesys.com -W: http://www.namesys.com -S: Supported +P: Hans Reiser +M: reiserfs-dev@namesys.com +L: reiserfs-list@namesys.com +W: http://www.namesys.com +S: Supported ROSE NETWORK LAYER P: Jean-Paul Roubelat @@ -1470,7 +1521,7 @@ SYSV FILESYSTEM P: Christoph Hellwig -M: hch@caldera.de +M: hch@infradead.org S: Maintained TLAN NETWORK DRIVER @@ -1498,10 +1549,10 @@ S: Maintained TRIDENT 4DWAVE/SIS 7018 PCI AUDIO CORE -P: Ollie Lho -M: ollie@sis.com.tw +P: Ollie Lho +M: ollie@sis.com.tw L: linux-kernel@vger.kernel.org -S: Supported +S: Supported TMS380 TOKEN-RING NETWORK DRIVER P: Adam Fritzler @@ -1613,12 +1664,12 @@ S: Maintained USB OV511 DRIVER -P: Mark McClelland -M: mmcclell@bigfoot.com -L: linux-usb-users@lists.sourceforge.net -L: linux-usb-devel@lists.sourceforge.net -W: http://alpha.dyndns.org/ov511/ -S: Maintained +P: Mark McClelland +M: mmcclell@bigfoot.com +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +W: http://alpha.dyndns.org/ov511/ +S: Maintained USB PEGASUS DRIVER P: Petko Manolov @@ -1728,17 +1779,17 @@ S: Maintained VIDEO FOR LINUX -P: Alan Cox -M: Alan.Cox@linux.org +P: Gerd Knorr +M: kraxel@bytesex.org W: http://roadrunner.swansea.linux.org.uk/v4l.shtml -S: Maintained for 2.2 only +S: Maintained WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) -P: Nenad Corbic -M: ncorbic@sangoma.com -M: dm@sangoma.com -W: http://www.sangoma.com -S: Supported +P: Nenad Corbic +M: ncorbic@sangoma.com +M: dm@sangoma.com +W: http://www.sangoma.com +S: Supported WAVELAN NETWORK DRIVER & WIRELESS EXTENSIONS P: Jean Tourrilhes diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Makefile linux-2.5/Makefile --- linux-2.5.5/Makefile Wed Feb 20 02:10:55 2002 +++ linux-2.5/Makefile Sun Mar 3 19:45:01 2002 @@ -1,12 +1,12 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 5 -EXTRAVERSION = +EXTRAVERSION =-dj3 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) -KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//") +KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g") CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ @@ -17,7 +17,7 @@ FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net HOSTCC = gcc -HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +HOSTCFLAGS = -Wshadow -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer CROSS_COMPILE = @@ -121,7 +121,7 @@ CORE_FILES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o NETWORKS =net/network.o -LIBS =$(TOPDIR)/lib/lib.a +LIBS =$(TOPDIR)/lib/lib.o SUBDIRS =kernel lib drivers mm fs net ipc sound DRIVERS-n := @@ -245,14 +245,14 @@ include arch/$(ARCH)/Makefile -export CPPFLAGS CFLAGS AFLAGS +export CPPFLAGS CFLAGS CFLAGS_KERNEL AFLAGS AFLAGS_KERNEL export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS .S.s: - $(CPP) $(AFLAGS) -traditional -o $*.s $< + $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -o $*.s $< .S.o: - $(CC) $(AFLAGS) -traditional -c -o $*.o $< + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -c -o $*.o $< Version: dummy @rm -f include/linux/compile.h @@ -341,7 +341,7 @@ $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $*.o $< init/do_mounts.o: init/do_mounts.c include/config/MARKER - $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -c -o $*.o $< + $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $*.o $< fs lib mm ipc kernel drivers net sound: dummy $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/Rules.make linux-2.5/Rules.make --- linux-2.5.5/Rules.make Wed Feb 20 02:11:00 2002 +++ linux-2.5/Rules.make Mon Mar 4 02:07:09 2002 @@ -50,10 +50,10 @@ # %.s: %.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -S $< -o $@ + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -S $< -o $@ %.i: %.c - $(CPP) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) $< > $@ + $(CPP) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) $< > $@ %.o: %.c $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -c -o $@ $< diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/alpha/Makefile linux-2.5/arch/alpha/Makefile --- linux-2.5.5/arch/alpha/Makefile Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/alpha/Makefile Tue Feb 26 21:24:48 2002 @@ -25,6 +25,11 @@ have_mcpu_ev67 := $(shell if $(CC) -mcpu=ev67 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi) +have_msmall_data := $(shell if $(CC) -msmall-data -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi) +ifeq ($(have_msmall_data),y) + CFLAGS := $(CFLAGS) -msmall-data +endif + # Turn on the proper cpu optimizations. ifeq ($(have_mcpu),y) # If GENERIC, make sure to turn off any instruction set extensions that @@ -40,20 +45,20 @@ CFLAGS := $(CFLAGS) -mcpu=pca56 mcpu_done := y endif - ifeq ($(mcpu_done)$(CONFIG_ALPHA_PYXIS),ny) - CFLAGS := $(CFLAGS) -mcpu=ev56 - mcpu_done := y - endif - ifeq ($(mcpu_done)$(CONFIG_ALPHA_POLARIS),ny) - ifeq ($(have_mcpu_pca56),y) - CFLAGS := $(CFLAGS) -mcpu=pca56 - else - CFLAGS := $(CFLAGS) -mcpu=ev56 - endif + ifeq ($(mcpu_done)$(CONFIG_ALPHA_POLARIS)$(have_mcpu_pca56),nyy) + CFLAGS := $(CFLAGS) -mcpu=pca56 mcpu_done := y endif ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV4),ny) CFLAGS := $(CFLAGS) -mcpu=ev4 + mcpu_done := y + endif + ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV56),ny) + CFLAGS := $(CFLAGS) -mcpu=ev56 + mcpu_done := y + endif + ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV5),ny) + CFLAGS := $(CFLAGS) -mcpu=ev5 mcpu_done := y endif ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV67)$(have_mcpu_ev67),nyy) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/alpha/config.in linux-2.5/arch/alpha/config.in --- linux-2.5.5/arch/alpha/config.in Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/alpha/config.in Mon Feb 25 22:20:45 2002 @@ -88,19 +88,44 @@ then define_bool CONFIG_ALPHA_EB64P y fi -if [ "$CONFIG_ALPHA_EB164" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ - -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_TAKARA" = "y" ] +if [ "$CONFIG_ALPHA_ALCOR" = "y" ] then define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_CIA y + bool 'EV56 CPU (speed >= 366MHz)?' CONFIG_ALPHA_EV56 fi -if [ "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ] +if [ "$CONFIG_ALPHA_EB164" = "y" ] +then + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_CIA y +fi +if [ "$CONFIG_ALPHA_PC164" = "y" -o "$CONFIG_ALPHA_TAKARA" = "y" ] +then + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_EV56 y + define_bool CONFIG_ALPHA_CIA y +fi +if [ "$CONFIG_ALPHA_MIKASA" = "y" ] then bool 'EV5 CPU daughtercard (model 5/xxx)?' CONFIG_ALPHA_PRIMO if [ "$CONFIG_ALPHA_PRIMO" = "y" ] then define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_CIA y + bool 'EV56 CPU (speed >= 333MHz)?' CONFIG_ALPHA_EV56 + else + define_bool CONFIG_ALPHA_EV4 y + define_bool CONFIG_ALPHA_APECS y + fi +fi +if [ "$CONFIG_ALPHA_NORITAKE" = "y" ] +then + bool 'EV5 CPU (model 5/xxx)?' CONFIG_ALPHA_PRIMO + if [ "$CONFIG_ALPHA_PRIMO" = "y" ] + then + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_CIA y + bool 'EV56 CPU (speed >= 333MHz)?' CONFIG_ALPHA_EV56 else define_bool CONFIG_ALPHA_EV4 y define_bool CONFIG_ALPHA_APECS y @@ -121,6 +146,7 @@ -o "$CONFIG_ALPHA_SX164" = "y" -o "$CONFIG_ALPHA_RUFFIAN" = "y" ] then define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_EV56 y define_bool CONFIG_ALPHA_CIA y define_bool CONFIG_ALPHA_PYXIS y fi @@ -145,10 +171,12 @@ then define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_MCPCIA y + bool 'EV56 CPU (speed >= 400MHz)?' CONFIG_ALPHA_EV56 fi if [ "$CONFIG_ALPHA_RX164" = "y" ] then define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_EV56 y define_bool CONFIG_ALPHA_POLARIS y fi if [ "$CONFIG_ALPHA_JENSEN" = "y" ] @@ -316,6 +344,8 @@ fi endmenu +source drivers/input/Config.in + source drivers/char/Config.in #source drivers/misc/Config.in @@ -351,7 +381,6 @@ endmenu source drivers/usb/Config.in -source drivers/input/Config.in if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then source net/bluetooth/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/alpha/kernel/alpha_ksyms.c linux-2.5/arch/alpha/kernel/alpha_ksyms.c --- linux-2.5.5/arch/alpha/kernel/alpha_ksyms.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/alpha/kernel/alpha_ksyms.c Mon Feb 18 21:47:02 2002 @@ -103,7 +103,6 @@ EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strrchr); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/alpha/kernel/core_titan.c linux-2.5/arch/alpha/kernel/core_titan.c --- linux-2.5.5/arch/alpha/kernel/core_titan.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/alpha/kernel/core_titan.c Tue Feb 26 21:24:48 2002 @@ -279,7 +279,6 @@ titan_init_one_pachip_port(titan_pachip_port *port, int index) { struct pci_controller *hose; - unsigned long sg_size; hose = alloc_pci_controller(); if (index == 0) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/alpha/kernel/entry.S linux-2.5/arch/alpha/kernel/entry.S --- linux-2.5.5/arch/alpha/kernel/entry.S Wed Feb 20 02:10:52 2002 +++ linux-2.5/arch/alpha/kernel/entry.S Tue Feb 26 21:24:48 2002 @@ -489,22 +489,22 @@ .prologue 0 bsr $1,do_switch_stack call_pal PAL_swpctx - unop - bsr $1,undo_switch_stack lda $8,0x3fff - mov $17,$0 + bsr $1,undo_switch_stack bic $30,$8,$8 ret $31,($26),1 .end alpha_switch_to +#ifdef CONFIG_SMP .globl ret_from_fork .align 3 .ent ret_from_fork ret_from_fork: lda $26,ret_from_sys_call - mov $0,$16 + mov $17,$16 jmp $31,schedule_tail .end ret_from_fork +#endif /* * Oh, well.. Disassembling OSF/1 binaries to find out how the diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/alpha/kernel/pci_iommu.c linux-2.5/arch/alpha/kernel/pci_iommu.c --- linux-2.5.5/arch/alpha/kernel/pci_iommu.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/alpha/kernel/pci_iommu.c Mon Feb 25 22:20:45 2002 @@ -30,6 +30,10 @@ #define DEBUG_NODIRECT 0 #define DEBUG_FORCEDAC 0 +/* Most Alphas support 32-bit ISA DMA. Exceptions are XL, Ruffian and + Nautilus (see asm/dma.h for details). */ +#define ISA_DMA_MASK (MAX_DMA_ADDRESS - IDENT_ADDR - 1 < 0xffffffff ? \ + MAX_DMA_ADDRESS - IDENT_ADDR - 1 : 0xffffffff) static inline unsigned long mk_iommu_pte(unsigned long paddr) @@ -181,7 +185,7 @@ int dac_allowed) { struct pci_controller *hose = pdev ? pdev->sysdata : pci_isa_hose; - dma_addr_t max_dma = pdev ? pdev->dma_mask : 0x00ffffff; + dma_addr_t max_dma = pdev ? pdev->dma_mask : ISA_DMA_MASK; struct pci_iommu_arena *arena; long npages, dma_ofs, i; unsigned long paddr; @@ -213,18 +217,15 @@ } /* If the machine doesn't define a pci_tbi routine, we have to - assume it doesn't support sg mapping. */ + assume it doesn't support sg mapping, and, since we tried to + use direct_map above, it now must be considered an error. */ if (! alpha_mv.mv_pci_tbi) { - static int been_here = 0; + static int been_here = 0; /* Only print the message once. */ if (!been_here) { - printk(KERN_WARNING "pci_map_single: no hw sg, using " - "direct map when possible\n"); + printk(KERN_WARNING "pci_map_single: no HW sg\n"); been_here = 1; } - if (paddr + size <= __direct_map_size) - return (paddr + __direct_map_base); - else - return 0; + return 0; } arena = hose->sg_pci; @@ -588,7 +589,7 @@ /* Second, figure out where we're going to map things. */ if (alpha_mv.mv_pci_tbi) { hose = pdev ? pdev->sysdata : pci_isa_hose; - max_dma = pdev ? pdev->dma_mask : 0x00ffffff; + max_dma = pdev ? pdev->dma_mask : ISA_DMA_MASK; arena = hose->sg_pci; if (!arena || arena->dma_base + arena->size - 1 > max_dma) arena = hose->sg_isa; @@ -651,7 +652,7 @@ return; hose = pdev ? pdev->sysdata : pci_isa_hose; - max_dma = pdev ? pdev->dma_mask : 0x00ffffff; + max_dma = pdev ? pdev->dma_mask : ISA_DMA_MASK; arena = hose->sg_pci; if (!arena || arena->dma_base + arena->size - 1 > max_dma) arena = hose->sg_isa; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/alpha/kernel/process.c linux-2.5/arch/alpha/kernel/process.c --- linux-2.5.5/arch/alpha/kernel/process.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/alpha/kernel/process.c Tue Feb 26 21:24:48 2002 @@ -283,6 +283,7 @@ unsigned long unused, struct task_struct * p, struct pt_regs * regs) { + extern void ret_from_sys_call(void); extern void ret_from_fork(void); struct thread_info *childti = p->thread_info; @@ -304,7 +305,11 @@ stack = ((struct switch_stack *) regs) - 1; childstack = ((struct switch_stack *) childregs) - 1; *childstack = *stack; +#ifdef CONFIG_SMP childstack->r26 = (unsigned long) ret_from_fork; +#else + childstack->r26 = (unsigned long) ret_from_sys_call; +#endif childti->pcb.usp = usp; childti->pcb.ksp = (unsigned long) childstack; childti->pcb.flags = 1; /* set FEN, clear everything else */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/alpha/kernel/proto.h linux-2.5/arch/alpha/kernel/proto.h --- linux-2.5.5/arch/alpha/kernel/proto.h Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/alpha/kernel/proto.h Tue Feb 26 21:24:48 2002 @@ -106,7 +106,7 @@ extern void SMC93x_Init(void); /* smc37c669.c */ -extern void SMC669_Init(int); +extern int SMC669_Init(int); /* es1888.c */ extern void es1888_init(void); @@ -162,9 +162,9 @@ unsigned char extra; } __mcheck_info; -#define mcheck_expected(cpu) (__mcheck_info.expected) -#define mcheck_taken(cpu) (__mcheck_info.taken) -#define mcheck_extra(cpu) (__mcheck_info.extra) +#define mcheck_expected(cpu) ((void)(cpu), __mcheck_info.expected) +#define mcheck_taken(cpu) ((void)(cpu), __mcheck_info.taken) +#define mcheck_extra(cpu) ((void)(cpu), __mcheck_info.extra) #endif #define DEBUG_MCHECK 0 /* 0 = minimal, 1 = debug, 2 = debug+dump. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/alpha/kernel/setup.c linux-2.5/arch/alpha/kernel/setup.c --- linux-2.5.5/arch/alpha/kernel/setup.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/alpha/kernel/setup.c Thu Feb 21 02:25:24 2002 @@ -472,6 +472,7 @@ struct percpu_struct *cpu; char *type_name, *var_name, *p; void *kernel_end = _end; /* end of kernel */ + char *args = command_line; hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr); boot_cpuid = hard_smp_processor_id(); @@ -509,7 +510,8 @@ /* * Process command-line arguments. */ - for (p = strtok(command_line, " \t"); p ; p = strtok(NULL, " \t")) { + while ((p = strsep(&args, " \t")) != NULL) { + if (!*p) continue; if (strncmp(p, "alpha_mv=", 9) == 0) { vec = get_sysvec_byname(p+9); continue; @@ -528,7 +530,7 @@ } } - /* Replace the command line, now that we've killed it with strtok. */ + /* Replace the command line, now that we've killed it with strsep. */ strcpy(command_line, saved_command_line); /* If we want SRM console printk echoing early, do it now. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/alpha/kernel/smc37c669.c linux-2.5/arch/alpha/kernel/smc37c669.c --- linux-2.5.5/arch/alpha/kernel/smc37c669.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/alpha/kernel/smc37c669.c Wed Jan 16 18:27:10 2002 @@ -2528,7 +2528,7 @@ * * RETURNS: * - * Nothing + * 1 if the chip found, 0 otherwise * * ARGUMENTS: * @@ -2539,7 +2539,7 @@ * None * */ -void __init SMC669_Init ( int index ) +int __init SMC669_Init ( int index ) { SMC37c669_CONFIG_REGS *SMC_base; unsigned long flags; @@ -2602,11 +2602,13 @@ __restore_flags(flags); printk( "SMC37c669 Super I/O Controller found @ 0x%lx\n", (unsigned long) SMC_base ); + return 1; } else { __restore_flags(flags); #if SMC_DEBUG printk( "No SMC37c669 Super I/O Controller found\n" ); #endif + return 0; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/alpha/kernel/smp.c linux-2.5/arch/alpha/kernel/smp.c --- linux-2.5.5/arch/alpha/kernel/smp.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/alpha/kernel/smp.c Mon Mar 4 01:29:41 2002 @@ -181,9 +181,23 @@ calibrate_delay. */ wait_boot_cpu_to_stop(cpuid); mb(); +try_again: calibrate_delay(); smp_store_cpu_info(cpuid); + + { +#define LPJ(c) ((long)cpu_data[c].loops_per_jiffy) + static int tries = 3; + long diff = LPJ(boot_cpuid) - LPJ(cpuid); + if (diff < 0) diff = -diff; + + if (diff > LPJ(boot_cpuid)/10 && --tries) { + printk("Bogus BogoMIPS for cpu %d - retrying...\n", cpuid); + goto try_again; + } + } + /* Allow master to continue only after we written loops_per_jiffy. */ wmb(); smp_secondary_alive = 1; @@ -460,7 +474,7 @@ if (fork_by_hand() < 0) panic("failed fork for CPU %d", cpuid); - idle = init_task.prev_task; + idle = LAST_TASK; if (!idle) panic("No idle process for CPU %d", cpuid); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/alpha/kernel/sys_miata.c linux-2.5/arch/alpha/kernel/sys_miata.c --- linux-2.5.5/arch/alpha/kernel/sys_miata.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/alpha/kernel/sys_miata.c Wed Jan 16 18:27:10 2002 @@ -230,7 +230,15 @@ miata_init_pci(void) { cia_init_pci(); - SMC669_Init(0); /* it might be a GL (fails harmlessly if not) */ + /* The PYXIS has data corruption problem with scatter/gather + burst DMA reads crossing 8K boundary. It had been fixed + with off-chip logic on all PYXIS systems except first + MIATAs, so disable SG DMA on such machines. */ + if (!SMC669_Init(0)) { /* MIATA GL has SMC37c669 Super I/O */ + alpha_mv.mv_pci_tbi = NULL; + printk(KERN_INFO "pci: pyxis 8K boundary dma bug - " + "sg dma disabled\n"); + } es1888_init(); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/alpha/kernel/sys_titan.c linux-2.5/arch/alpha/kernel/sys_titan.c --- linux-2.5.5/arch/alpha/kernel/sys_titan.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/alpha/kernel/sys_titan.c Tue Feb 26 21:24:48 2002 @@ -84,8 +84,8 @@ *dim3; #else volatile unsigned long *dimB; - if (bcpu == 0) dimB = &cchip->dim0.csr; - else if (bcpu == 1) dimB = &cchip->dim1.csr; + dimB = &cchip->dim0.csr; + if (bcpu == 1) dimB = &cchip->dim1.csr; else if (bcpu == 2) dimB = &cchip->dim2.csr; else if (bcpu == 3) dimB = &cchip->dim3.csr; @@ -190,9 +190,6 @@ static void __init privateer_init_irq(void) { - extern asmlinkage void entInt(void); - int cpu; - outb(0, DMA1_RESET_REG); outb(0, DMA2_RESET_REG); outb(DMA_MODE_CASCADE, DMA2_MODE_REG); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/Config.help linux-2.5/arch/arm/Config.help --- linux-2.5.5/arch/arm/Config.help Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/Config.help Fri Mar 1 15:07:37 2002 @@ -116,6 +116,16 @@ information about which PCI hardware does work under Linux and which doesn't. +CONFIG_PREEMPT + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + This allows applications to run more reliably even when the system is + under load. + + Say Y here if you are building a kernel for a desktop, embedded + or real-time system. Say N if you are unsure. + CONFIG_MCA MicroChannel Architecture is found in some IBM PS/2 machines and laptops. It is a bus system similar to PCI or ISA. See @@ -521,6 +531,10 @@ Saying N will reduce the size of the Footbridge kernel. +CONFIG_ARCH_IQ80310 + Say Y here if you want to run your kernel on the Intel IQ80310 + evaluation kit for the IOP310 chipset. + CONFIG_ARCH_L7200 Say Y here if you intend to run this kernel on a LinkUp Systems L7200 Software Development Board which uses an ARM720T processor. @@ -558,6 +572,13 @@ If you have any questions or comments about the Compaq Personal Server, send e-mail to skiff@crl.dec.com. +CONFIG_PLD_HOTSWAP + This enables support for the dynamic loading and configuration of + compatible drivers when the contents of the PLD are changed. This + is still experimental and requires configuration tools which are + not yet generally available. Say N here. You must enable the kernel + module loader for this feature to work. + CONFIG_SA1100_ASSABET Say Y here if you are using the Intel(R) StrongARM(R) SA-1110 Microprocessor Development Board (also known as the Assabet). @@ -567,28 +588,14 @@ Microprocessor Development Board (Assabet) with the SA-1111 Development Board (Nepon). -CONFIG_SA1100_H3600 - Say Y here if you intend to run this kernel on the Compaq iPAQ - H3600 handheld computer. Information about this machine and the - Linux port to this machine can be found at: - - - +CONFIG_SA1100_BADGE4 + Say Y here if you want to build a kernel for the HP Laboratories + BadgePAD 4. CONFIG_SA1100_BRUTUS Say Y here if you are using the Intel(R) StrongARM(R) SA-1100 Microprocessor Development Board (also known as the Brutus). -CONFIG_SA1100_LART - Say Y here if you are using the Linux Advanced Radio Terminal - (also known as the LART). See for - information on the LART. - -CONFIG_SA1100_GRAPHICSCLIENT - Say Y here if you are using an Applied Data Systems Intel(R) - StrongARM(R) SA-1100 based Graphics Client SBC. See - for information on this system. - CONFIG_SA1100_CERF The Intrinsyc CerfBoard is based on the StrongARM 1110. More information is available at: @@ -602,6 +609,24 @@ handheld instruments. Information about this machine can be found at: . +CONFIG_SA1100_GRAPHICSCLIENT + Say Y here if you are using an Applied Data Systems Intel(R) + StrongARM(R) SA-1100 based Graphics Client SBC. See + for information on this system. + +CONFIG_SA1100_H3600 + Say Y here if you intend to run this kernel on the Compaq iPAQ + H3600 handheld computer. Information about this machine and the + Linux port to this machine can be found at: + + + + +CONFIG_SA1100_LART + Say Y here if you are using the Linux Advanced Radio Terminal + (also known as the LART). See for + information on the LART. + CONFIG_SA1100_NANOENGINE The nanoEngine is a StrongARM 1110-based single board computer from Bright Star Engineering. More information is available at: @@ -619,6 +644,23 @@ Say Y if configuring for a Pangolin. Say N otherwise. +CONFIG_SA1100_PFS168 + The Radisys Corp. PFS-168 (aka Tulsa) is an Intel® StrongArm® SA-1110 based + computer which includes the SA-1111 Microprocessor Companion Chip and other + custom I/O designed to add connectivity and multimedia features for vending + and business machine applications. Say Y here if you require support for + this target. + +CONFIG_SA1100_SHANNON + The Shannon (also known as a Tuxscreen, and also as a IS2630) was a + limited edition webphone produced by Philips. The Shannon is a SA1100 + platform with a 640x480 LCD, touchscreen, CIR keyboard, PCMCIA slots, + and a telco interface. + +CONFIG_SA1100_STORK + Say Y here if you intend to run this kernel on the Stork + handheld computer. + CONFIG_SA1100_VICTOR Say Y here if you are using a Visu Aide Intel(R) StrongARM(R) SA-1100 based Victor Digital Talking Book Reader. See @@ -656,6 +698,31 @@ Say Y if you want support for the ARM920T processor. Otherwise, say N. +CONFIG_CPU_ARM922T + The ARM922T is a version of the ARM920T, but with smaller + instruction and data caches. It is used in Altera's + Excalibur XA device family. + + Say Y if you want support for the ARM922T processor. + Otherwise, say N. + +CONFIG_CPU_ARM922_CPU_IDLE + Saying Y here will allow the processor to enter a low power + mode whilst waiting for an interrupt in idle. If you're unsure + say Y. + +CONFIG_CPU_ARM922_I_CACHE_ON + Say Y here to enable the processor instruction cache. Unless + you have a reason not to, say Y. + +CONFIG_CPU_ARM922_D_CACHE_ON + Say Y here to enable the processor data cache. Unless + you have a reason not to, say Y. + +CONFIG_CPU_ARM922_WRITETHROUGH + Say Y here to use the data cache in writethough mode. Unless you + specifically require this, say N. + CONFIG_CPU_ARM1020 The ARM1020 is the cached version of the ARM10 processor, with an addition of a floating-point unit. @@ -688,16 +755,14 @@ CONFIG_FPE_FASTFPE Say Y here to include the FAST floating point emulator in the kernel. - This is an experimental much faster emulator which has only 32 bit + This is an experimental much faster emulator which now also has full precision for the mantissa. It does not support any exceptions. - This makes it very simple, it is approximately 4-8 times faster than - NWFPE. + It is very simple, and approximately 3-6 times faster than NWFPE. - It should be sufficient for most programs. It is definitely not - suitable if you do scientific calculations that need double - precision for iteration formulas that sum up lots of very small - numbers. If you do not feel you need a faster FP emulation you - should better choose NWFPE. + It should be sufficient for most programs. It may be not suitable + for scientific calculations, but you have to check this for yourself. + If you do not feel you need a faster FP emulation you should better + choose NWFPE. It is also possible to say M to build the emulator as a module (fastfpe.o). But keep in mind that you should only load the FP diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/Makefile linux-2.5/arch/arm/Makefile --- linux-2.5.5/arch/arm/Makefile Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/arm/Makefile Fri Mar 1 15:07:37 2002 @@ -134,6 +134,10 @@ MACHINE = clps711x endif +ifeq ($(CONFIG_ARCH_FORTUNET),y) +TEXTADDR = 0xc0008000 +endif + ifeq ($(CONFIG_ARCH_ANAKIN),y) MACHINE = anakin endif @@ -215,6 +219,7 @@ arch/arm/vmlinux.lds MRPROPER_FILES += \ + arch/arm/tools/constants.h* \ include/asm-arm/arch \ include/asm-arm/proc \ include/asm-arm/constants.h* \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/boot/Makefile linux-2.5/arch/arm/boot/Makefile --- linux-2.5.5/arch/arm/boot/Makefile Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/boot/Makefile Fri Mar 1 15:07:37 2002 @@ -54,6 +54,10 @@ INITRD_VIRT = 0xc0800000 endif +ifeq ($(CONFIG_ARCH_CAMELOT),y) +ZTEXTADDR = 0x00008000 +endif + ifeq ($(CONFIG_ARCH_NEXUSPCI),y) ZTEXTADDR = 0x40008000 endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/boot/compressed/Makefile linux-2.5/arch/arm/boot/compressed/Makefile --- linux-2.5.5/arch/arm/boot/compressed/Makefile Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/boot/compressed/Makefile Fri Mar 1 15:07:37 2002 @@ -33,6 +33,10 @@ OBJS += head-integrator.o endif +ifeq ($(CONFIG_ARCH_CAMELOT),y) +OBJS += head-epxa10db.o +endif + ifeq ($(CONFIG_ARCH_FTVPCI),y) OBJS += head-ftvpci.o endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/boot/compressed/head-epxa10db.S linux-2.5/arch/arm/boot/compressed/head-epxa10db.S --- linux-2.5.5/arch/arm/boot/compressed/head-epxa10db.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/boot/compressed/head-epxa10db.S Fri Mar 1 15:07:37 2002 @@ -0,0 +1,5 @@ +#include +#include + + .section ".start", #alloc, #execinstr + mov r7, #MACH_TYPE_CAMELOT diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/boot/compressed/misc.c linux-2.5/arch/arm/boot/compressed/misc.c --- linux-2.5.5/arch/arm/boot/compressed/misc.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/boot/compressed/misc.c Fri Mar 1 15:07:37 2002 @@ -18,6 +18,8 @@ unsigned int __machine_arch_type; +#include + #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/boot/compressed/ofw-shark.c linux-2.5/arch/arm/boot/compressed/ofw-shark.c --- linux-2.5.5/arch/arm/boot/compressed/ofw-shark.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/boot/compressed/ofw-shark.c Tue Feb 26 21:24:48 2002 @@ -19,7 +19,7 @@ asmlinkage void create_params (unsigned long *buffer) { - /* Is there a better address? Also change in mach-shark/arch.c */ + /* Is there a better address? Also change in mach-shark/core.c */ struct tag *tag = (struct tag *) 0x08003000; int j,i,m,k,nr_banks,size; unsigned char *c; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/config.in linux-2.5/arch/arm/config.in --- linux-2.5.5/arch/arm/config.in Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/arm/config.in Fri Mar 1 15:07:37 2002 @@ -91,6 +91,7 @@ dep_bool ' FreeBird-v1.1' CONFIG_SA1100_FREEBIRD $CONFIG_ARCH_SA1100 dep_bool ' GraphicsClient Plus' CONFIG_SA1100_GRAPHICSCLIENT $CONFIG_ARCH_SA1100 dep_bool ' GraphicsMaster' CONFIG_SA1100_GRAPHICSMASTER $CONFIG_ARCH_SA1100 +dep_bool ' HP Labs BadgePAD 4' CONFIG_SA1100_BADGE4 $CONFIG_ARCH_SA1100 dep_bool ' HP Jornada 720' CONFIG_SA1100_JORNADA720 $CONFIG_ARCH_SA1100 dep_bool ' HuW WebPanel' CONFIG_SA1100_HUW_WEBPANEL $CONFIG_ARCH_SA1100 dep_bool ' Itsy' CONFIG_SA1100_ITSY $CONFIG_ARCH_SA1100 @@ -107,6 +108,7 @@ dep_bool ' Victor' CONFIG_SA1100_VICTOR $CONFIG_ARCH_SA1100 dep_bool ' XP860' CONFIG_SA1100_XP860 $CONFIG_ARCH_SA1100 dep_bool ' Yopy' CONFIG_SA1100_YOPY $CONFIG_ARCH_SA1100 +dep_bool ' Stork' CONFIG_SA1100_STORK $CONFIG_ARCH_SA1100 # Determine if SA1111 support is required if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \ @@ -115,7 +117,8 @@ "$CONFIG_SA1100_XP860" = "y" -o \ "$CONFIG_SA1100_GRAPHICSMASTER" = "y" -o \ "$CONFIG_SA1100_PT_SYSTEM3" = "y" -o \ - "$CONFIG_SA1100_ADSBITSY" = "y" ]; then + "$CONFIG_SA1100_ADSBITSY" = "y" -o \ + "$CONFIG_SA1100_BADGE4" = "y" ]; then define_bool CONFIG_SA1111 y define_int CONFIG_FORCE_MAX_ZONEORDER 9 fi @@ -134,6 +137,7 @@ dep_bool ' CLEP7312' CONFIG_ARCH_CLEP7312 $CONFIG_ARCH_CLPS711X dep_bool ' EDB7211' CONFIG_ARCH_EDB7211 $CONFIG_ARCH_CLPS711X dep_bool ' P720T' CONFIG_ARCH_P720T $CONFIG_ARCH_CLPS711X +dep_bool ' FORTUNET' CONFIG_ARCH_FORTUNET $CONFIG_ARCH_CLPS711X # XXX Maybe these should indicate register compatibility # instead of being mutually exclusive. @@ -464,6 +468,7 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'Power Management support' CONFIG_PM +dep_bool 'Preemptible Kernel (experimental)' CONFIG_PREEMPT $CONFIG_CPU_32 $CONFIG_EXPERIMENTAL dep_tristate 'Advanced Power Management Emulation' CONFIG_APM $CONFIG_PM dep_tristate 'RISC OS personality' CONFIG_ARTHUR $CONFIG_CPU_32 @@ -591,9 +596,6 @@ fi endmenu -# -# input before char - char/joystick depends on it. As does USB. -# source drivers/input/Config.in source drivers/char/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/def-configs/badge4 linux-2.5/arch/arm/def-configs/badge4 --- linux-2.5.5/arch/arm/def-configs/badge4 Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/def-configs/badge4 Fri Mar 1 15:07:37 2002 @@ -0,0 +1,923 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# + +# +# Footbridge Implementations +# + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +CONFIG_SA1100_BADGE4=y +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +CONFIG_SA1111=y +CONFIG_FORCE_MAX_ZONEORDER=9 +CONFIG_SA1100_USB=m +CONFIG_SA1100_USB_NETLINK=m +CONFIG_SA1100_USB_CHAR=m + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set + +# +# Processor Type +# +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +CONFIG_CPU_SA1100=y +# CONFIG_ARM_THUMB is not set +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +CONFIG_CPU_FREQ=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +CONFIG_PCMCIA_PROBE=y +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +CONFIG_PCMCIA_SA1100=y +CONFIG_NET=y +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +CONFIG_FPE_FASTFPE=m +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=m +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +# CONFIG_PM is not set +CONFIG_ARTHUR=m +CONFIG_CMDLINE="init=/linuxrc root=/dev/mtdblock3" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_BOOTLDR_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_CFI_B1 is not set +CONFIG_MTD_CFI_B2=y +# CONFIG_MTD_CFI_B4 is not set +CONFIG_MTD_CFI_I1=y +# CONFIG_MTD_CFI_I2 is not set +# CONFIG_MTD_CFI_I4 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +CONFIG_MTD_RAM=y +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +CONFIG_MTD_SA1100=y +# CONFIG_MTD_IQ80310 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTD_BLKMTD=m + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=y + +# +# Wireless Pcmcia cards support +# +CONFIG_PCMCIA_HERMES=y +CONFIG_AIRO_CS=m +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=y +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=y +CONFIG_PCMCIA_AXNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_NET_PCMCIA_RADIO=y +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_WAVELAN=m + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=y + +# +# IrDA protocols +# +CONFIG_IRLAN=y +CONFIG_IRCOMM=y +CONFIG_IRDA_ULTRA=y +# CONFIG_IRDA_OPTIONS is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +# CONFIG_IRTTY_SIR is not set +# CONFIG_IRPORT_SIR is not set + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +CONFIG_SA1100_FIR=y + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +CONFIG_BLK_DEV_IDESCSI=m + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx_sync is not set +# CONFIG_SCSI_NCR53C7xx_FAST is not set +# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_SCSI_PCMCIA is not set + +# +# I2O device support +# +CONFIG_I2O=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_LAN=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +CONFIG_INPUT=m +CONFIG_INPUT_KEYBDEV=m +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=115200 +# CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ELV=m +CONFIG_I2C_VELLEMAN=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ELEKTOR=m +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_PROC=m + +# +# L3 serial bus support +# +CONFIG_L3=m + +# +# Other L3 adapters +# +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_SERIO is not set + +# +# Joysticks +# +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_SOFT_WATCHDOG=m +# CONFIG_WDT is not set +# CONFIG_WDTPCI is not set +# CONFIG_PCWATCHDOG is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +CONFIG_SA1100_WATCHDOG=m +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_I810_TCO is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_60XX_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_MACHZ_WDT is not set +# CONFIG_NVRAM is not set +CONFIG_RTC=m +CONFIG_SA1100_RTC=m +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_CRAMFS=m +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +CONFIG_MINIX_FS=m +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=m +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_NFSD is not set +CONFIG_SUNRPC=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_NCP_FS is not set +# CONFIG_ZISOFS_FS is not set +CONFIG_ZLIB_FS_INFLATE=m + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 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_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +CONFIG_SOUND_SA1100=y +CONFIG_SOUND_UDA1341=m +CONFIG_SOUND_SA1111_UDA1341=m +CONFIG_SOUND_SA1100SSP=m +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set + +# +# USB support +# +CONFIG_USB=y +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +CONFIG_USB_OHCI_SA1111=y + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=y +CONFIG_USB_BLUETOOTH=m +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DEBUG=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +# CONFIG_USB_HIDDEV is not set +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +CONFIG_USB_WACOM=m + +# +# USB Imaging devices +# +CONFIG_USB_DC2XX=m +CONFIG_USB_MDC800=m +CONFIG_USB_SCANNER=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +CONFIG_USB_PEGASUS=m +CONFIG_USB_KAWETH=m +CONFIG_USB_CATC=m +CONFIG_USB_CDCETHER=m +CONFIG_USB_USBNET=m + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m + +# +# USB Miscellaneous drivers +# +CONFIG_USB_RIO500=m + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m + +# +# Bluetooth device drivers +# +CONFIG_BLUEZ_HCIUSB=m +CONFIG_BLUEZ_HCIUART=m +CONFIG_BLUEZ_HCIVHCI=m + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_SER3=y diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/def-configs/epxa10db linux-2.5/arch/arm/def-configs/epxa10db --- linux-2.5.5/arch/arm/def-configs/epxa10db Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/def-configs/epxa10db Fri Mar 1 15:07:37 2002 @@ -8,6 +8,8 @@ CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set # # Code maturity level options @@ -25,6 +27,7 @@ # # System Type # +# CONFIG_ARCH_ADIFCC is not set # CONFIG_ARCH_ANAKIN is not set # CONFIG_ARCH_ARCA5K is not set # CONFIG_ARCH_CLPS7500 is not set @@ -34,6 +37,7 @@ CONFIG_ARCH_CAMELOT=y # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP310 is not set # CONFIG_ARCH_L7200 is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set @@ -62,12 +66,16 @@ # CONFIG_SA1100_ADSBITSY is not set # CONFIG_SA1100_BRUTUS is not set # CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set # CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set # CONFIG_SA1100_EXTENEX1 is not set # CONFIG_SA1100_FLEXANET is not set # CONFIG_SA1100_FREEBIRD is not set # CONFIG_SA1100_GRAPHICSCLIENT is not set # CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_BADGE4 is not set # CONFIG_SA1100_JORNADA720 is not set # CONFIG_SA1100_HUW_WEBPANEL is not set # CONFIG_SA1100_ITSY is not set @@ -76,20 +84,28 @@ # CONFIG_SA1100_OMNIMETER is not set # CONFIG_SA1100_PANGOLIN is not set # CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set # CONFIG_SA1100_SHERMAN is not set # CONFIG_SA1100_SIMPAD is not set # CONFIG_SA1100_PFS168 is not set # CONFIG_SA1100_VICTOR is not set # CONFIG_SA1100_XP860 is not set # CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_H3600_SLEEVE is not set # # CLPS711X/EP721X Implementations # +# CONFIG_ARCH_AUTCPU12 is not set # CONFIG_ARCH_CDB89712 is not set # CONFIG_ARCH_CLEP7312 is not set # CONFIG_ARCH_EDB7211 is not set # CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_FORTUNET is not set # CONFIG_ARCH_EP7211 is not set # CONFIG_ARCH_EP7212 is not set # CONFIG_ARCH_ACORN is not set @@ -103,14 +119,17 @@ # CONFIG_CPU_ARM610 is not set # CONFIG_CPU_ARM710 is not set # CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set CONFIG_CPU_ARM922T=y -CONFIG_CPU_ARM92X_CPU_IDLE=y -CONFIG_CPU_ARM92X_I_CACHE_ON=y -CONFIG_CPU_ARM92X_D_CACHE_ON=y -# CONFIG_CPU_ARM92X_WRITETHROUGH is not set +CONFIG_CPU_ARM922_CPU_IDLE=y +CONFIG_CPU_ARM922_I_CACHE_ON=y +CONFIG_CPU_ARM922_D_CACHE_ON=y +# CONFIG_CPU_ARM922_WRITETHROUGH is not set +# CONFIG_CPU_ARM926T is not set # CONFIG_CPU_ARM1020 is not set # CONFIG_CPU_SA110 is not set # CONFIG_CPU_SA1100 is not set +# CONFIG_XSCALE_PMU is not set # CONFIG_ARM_THUMB is not set # CONFIG_DISCONTIGMEM is not set @@ -120,6 +139,7 @@ # CONFIG_PCI is not set # CONFIG_ISA is not set # CONFIG_ISA_DMA is not set +# CONFIG_FIQ is not set # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set CONFIG_NET=y @@ -134,6 +154,7 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_PM is not set +# CONFIG_APM is not set # CONFIG_ARTHUR is not set CONFIG_CMDLINE="console=ttyUA0,38400 root=/dev/mtdblock0 rw" CONFIG_ALIGNMENT_TRAP=y @@ -171,42 +192,28 @@ # CONFIG_MTD_ROM is not set # CONFIG_MTD_ABSENT is not set # CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set # # Mapping drivers for chip access # # CONFIG_MTD_PHYSMAP is not set -# CONFIG_MTD_SUN_UFLASH is not set # CONFIG_MTD_NORA is not set -# CONFIG_MTD_PNC2000 is not set -# CONFIG_MTD_RPXLITE is not set -# CONFIG_MTD_TQM8XXL is not set -# CONFIG_MTD_SC520CDP is not set -# CONFIG_MTD_NETSC520 is not set -# CONFIG_MTD_SBC_GXX is not set -# CONFIG_MTD_ELAN_104NC is not set -# CONFIG_MTD_DBOX2 is not set -# CONFIG_MTD_CSTM_MIPS_IXX is not set -CONFIG_MTD_EPXA10DB=y -# CONFIG_MTD_CFI_FLAGADM is not set -# CONFIG_MTD_SOLUTIONENGINE is not set -# CONFIG_MTD_MIXMEM is not set -# CONFIG_MTD_OCTAGON is not set -# CONFIG_MTD_VMAX is not set -# CONFIG_MTD_OCELOT is not set -# CONFIG_MTD_L440GX is not set # CONFIG_MTD_ARM_INTEGRATOR is not set # CONFIG_MTD_CDB89712 is not set # CONFIG_MTD_SA1100 is not set # CONFIG_MTD_DC21285 is not set # CONFIG_MTD_IQ80310 is not set +CONFIG_MTD_EPXA10DB=y +# CONFIG_MTD_PCI is not set # # Self-contained MTD device drivers # # CONFIG_MTD_PMC551 is not set # CONFIG_MTD_SLRAM is not set -# CONFIG_MTD_LART is not set # CONFIG_MTD_MTDRAM is not set # CONFIG_MTD_BLKMTD is not set # CONFIG_MTD_DOC1000 is not set @@ -224,7 +231,6 @@ # # CONFIG_PNP is not set # CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set # # Block devices @@ -234,6 +240,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set @@ -250,6 +257,7 @@ # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_LVM is not set # @@ -275,6 +283,7 @@ # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set @@ -311,7 +320,8 @@ # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y -CONFIG_ETHER00=y +# CONFIG_ARM_AM79C961A is not set +CONFIG_ETHER00=m # CONFIG_SUNLANCE is not set # CONFIG_SUNBMAC is not set # CONFIG_SUNQE is not set @@ -343,8 +353,8 @@ # CONFIG_PPP_FILTER is not set CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_BSDCOMP=y +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set # CONFIG_PPPOE is not set # CONFIG_SLIP is not set @@ -437,12 +447,14 @@ # CONFIG_SERIAL_SA1100_CONSOLE is not set # CONFIG_SERIAL_8250 is not set # CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_ATOMWIDE_SERIAL is not set +# CONFIG_DUALSP_SERIAL is not set # CONFIG_SERIAL_8250_EXTENDED is not set # CONFIG_SERIAL_8250_MANY_PORTS is not set # CONFIG_SERIAL_8250_SHARE_IRQ is not set # CONFIG_SERIAL_8250_DETECT_IRQ is not set # CONFIG_SERIAL_8250_MULTIPORT is not set -# CONFIG_SERIAL_8250_HUB6 is not set +# CONFIG_SERIAL_8250_RSA is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y @@ -460,7 +472,6 @@ # CONFIG_L3_ALGOBIT is not set # CONFIG_L3_BIT_SA1100_GPIO is not set # CONFIG_L3_SA1111 is not set -# CONFIG_L3_DRV_UDA1341 is not set # CONFIG_BIT_SA1100_GPIO is not set # @@ -485,7 +496,6 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -513,7 +523,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_JBD_DEBUG is not set @@ -522,16 +531,17 @@ # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set -CONFIG_JFFS_FS=y -CONFIG_JFFS_FS_VERBOSE=0 -# CONFIG_JFFS2_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 # CONFIG_CRAMFS is not set -# CONFIG_TMPFS is not set -# CONFIG_RAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -572,6 +582,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -582,9 +594,19 @@ # CONFIG_NLS is not set # +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# # USB support # # CONFIG_USB is not set +# CONFIG_USB_EHCI_HCD is not set # CONFIG_USB_UHCI is not set # CONFIG_USB_UHCI_ALT is not set # CONFIG_USB_OHCI is not set @@ -596,10 +618,10 @@ # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set # CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_STORAGE_DPCM is not set # CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set # CONFIG_USB_DC2XX is not set @@ -607,8 +629,6 @@ # CONFIG_USB_SCANNER is not set # CONFIG_USB_MICROTEK is not set # CONFIG_USB_HPUSBSCSI is not set -# CONFIG_USB_DABUSB is not set -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -627,21 +647,27 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set +# CONFIG_USB_AUERSWALD is not set # # Bluetooth support @@ -652,11 +678,21 @@ # Kernel hacking # # CONFIG_NO_FRAME_POINTER is not set -CONFIG_DEBUG_ERRORS=y -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_INFO=y -CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set # CONFIG_NO_PGT_CACHE is not set -CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_LL is not set # CONFIG_DEBUG_DC21285_PORT is not set # CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/def-configs/fortunet linux-2.5/arch/arm/def-configs/fortunet --- linux-2.5.5/arch/arm/def-configs/fortunet Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/def-configs/fortunet Fri Mar 1 15:07:37 2002 @@ -0,0 +1,593 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +CONFIG_ARCH_CLPS711X=y +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_H3600_SLEEVE is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +CONFIG_ARCH_FORTUNET=y +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +CONFIG_CPU_ARM720T=y +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_ARM_THUMB is not set +# CONFIG_DISCONTIGMEM is not set + +# +# General setup +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_FPE_NWFPE is not set +CONFIG_FPE_FASTFPE=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 +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_PARTITIONS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_BOOTLDR_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +CONFIG_MTD_FORTUNET=y +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +# CONFIG_INET is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET_AUNUDP is not set +# CONFIG_ECONET_NATIVE is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +# CONFIG_NETDEVICES is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Synchronous Serial Interface +# +# CONFIG_SSI is not set +# CONFIG_SSI_CLPS711X is not set +# CONFIG_SSI_JUNO is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +CONFIG_SERIAL_CLPS711X=y +CONFIG_SERIAL_CLPS711X_CONSOLE=y +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG 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_EFS_FS is not set +CONFIG_JFFS_FS=y +CONFIG_JFFS_FS_VERBOSE=0 +# CONFIG_JFFS_PROC_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +# CONFIG_USB_OHCI_SA1111 is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set +# CONFIG_DEBUG_LL_SER3 is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/def-configs/shark linux-2.5/arch/arm/def-configs/shark --- linux-2.5.5/arch/arm/def-configs/shark Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/arm/def-configs/shark Fri Mar 1 15:07:37 2002 @@ -9,6 +9,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set # # Code maturity level options @@ -26,14 +27,17 @@ # # System Type # +# CONFIG_ARCH_ADIFCC is not set # CONFIG_ARCH_ANAKIN is not set # CONFIG_ARCH_ARCA5K is not set # CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP310 is not set # CONFIG_ARCH_L7200 is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set @@ -66,12 +70,16 @@ # CONFIG_SA1100_ADSBITSY is not set # CONFIG_SA1100_BRUTUS is not set # CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set # CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set # CONFIG_SA1100_EXTENEX1 is not set # CONFIG_SA1100_FLEXANET is not set # CONFIG_SA1100_FREEBIRD is not set # CONFIG_SA1100_GRAPHICSCLIENT is not set # CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_BADGE4 is not set # CONFIG_SA1100_JORNADA720 is not set # CONFIG_SA1100_HUW_WEBPANEL is not set # CONFIG_SA1100_ITSY is not set @@ -80,20 +88,28 @@ # CONFIG_SA1100_OMNIMETER is not set # CONFIG_SA1100_PANGOLIN is not set # CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set # CONFIG_SA1100_SHERMAN is not set # CONFIG_SA1100_SIMPAD is not set # CONFIG_SA1100_PFS168 is not set # CONFIG_SA1100_VICTOR is not set # CONFIG_SA1100_XP860 is not set # CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_H3600_SLEEVE is not set # # CLPS711X/EP721X Implementations # +# CONFIG_ARCH_AUTCPU12 is not set # CONFIG_ARCH_CDB89712 is not set # CONFIG_ARCH_CLEP7312 is not set # CONFIG_ARCH_EDB7211 is not set # CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_FORTUNET is not set # CONFIG_ARCH_EP7211 is not set # CONFIG_ARCH_EP7212 is not set # CONFIG_ARCH_ACORN is not set @@ -112,9 +128,12 @@ # CONFIG_CPU_ARM710 is not set # CONFIG_CPU_ARM720T is not set # CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set # CONFIG_CPU_ARM1020 is not set CONFIG_CPU_SA110=y # CONFIG_CPU_SA1100 is not set +# CONFIG_XSCALE_PMU is not set # CONFIG_ARM_THUMB is not set # CONFIG_DISCONTIGMEM is not set @@ -122,8 +141,11 @@ # General setup # CONFIG_PCI=y +# CONFIG_PCI_HOST_PLX90X0 is not set +CONFIG_PCI_HOST_VIA82C505=y CONFIG_ISA=y CONFIG_ISA_DMA=y +# CONFIG_FIQ is not set # CONFIG_PCI_NAMES is not set # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set @@ -143,6 +165,7 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_PM is not set +# CONFIG_APM is not set # CONFIG_ARTHUR is not set CONFIG_LEDS=y CONFIG_LEDS_TIMER=y @@ -172,7 +195,6 @@ # # CONFIG_PNP is not set # CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set # # Block devices @@ -182,6 +204,7 @@ # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set @@ -204,10 +227,11 @@ # # Networking options # -# CONFIG_PACKET is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK is not set # CONFIG_NETFILTER is not set -# CONFIG_FILTER is not set +CONFIG_FILTER=y CONFIG_UNIX=y CONFIG_INET=y # CONFIG_IP_MULTICAST is not set @@ -220,6 +244,7 @@ # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # # @@ -260,6 +285,7 @@ # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_SUNLANCE is not set # CONFIG_HAPPYMEAL is not set # CONFIG_SUNBMAC is not set @@ -280,6 +306,7 @@ # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set CONFIG_CS89x0=y +# CONFIG_DE2104X is not set # CONFIG_TULIP is not set # CONFIG_DE4X5 is not set # CONFIG_DGRS is not set @@ -291,6 +318,7 @@ # CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set +# CONFIG_8139CP is not set # CONFIG_8139TOO is not set # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set @@ -300,6 +328,7 @@ # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set # CONFIG_WINBOND_840 is not set # CONFIG_NET_POCKET is not set @@ -416,7 +445,6 @@ # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # -# CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set @@ -453,6 +481,7 @@ # CONFIG_SCSI_IMM is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set # CONFIG_SCSI_PAS16 is not set @@ -521,16 +550,20 @@ # CONFIG_SERIAL_21285 is not set # CONFIG_SERIAL_21285_OLD is not set # CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set # CONFIG_SERIAL_SA1100 is not set # CONFIG_SERIAL_SA1100_CONSOLE is not set # CONFIG_SERIAL_8250 is not set # CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_ATOMWIDE_SERIAL is not set +# CONFIG_DUALSP_SERIAL is not set # CONFIG_SERIAL_8250_EXTENDED is not set # CONFIG_SERIAL_8250_MANY_PORTS is not set # CONFIG_SERIAL_8250_SHARE_IRQ is not set # CONFIG_SERIAL_8250_DETECT_IRQ is not set # CONFIG_SERIAL_8250_MULTIPORT is not set -# CONFIG_SERIAL_8250_HUB6 is not set +# CONFIG_SERIAL_8250_RSA is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 CONFIG_PRINTER=m @@ -588,7 +621,6 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -596,7 +628,6 @@ # CONFIG_FTAPE is not set # CONFIG_AGP is not set # CONFIG_DRM is not set -# CONFIG_MWAVE is not set # # Multimedia devices @@ -617,7 +648,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_CMS_FS is not set CONFIG_EXT3_FS=y CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set @@ -630,12 +660,12 @@ # CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set # CONFIG_TMPFS is not set -# CONFIG_RAMFS is not set +CONFIG_RAMFS=y CONFIG_ISO9660_FS=y CONFIG_JOLIET=y # CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_FREEVXFS_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -807,7 +837,7 @@ # CONFIG_SOUND_DMAP is not set # CONFIG_SOUND_AD1816 is not set # CONFIG_SOUND_SGALAXY is not set -# CONFIG_SOUND_ADLIB is not set +CONFIG_SOUND_ADLIB=m # CONFIG_SOUND_ACI_MIXER is not set # CONFIG_SOUND_CS4232 is not set # CONFIG_SOUND_SSCAPE is not set @@ -850,8 +880,9 @@ # CONFIG_USB is not set # -# USB Controllers +# USB Host Controller Drivers # +# CONFIG_USB_EHCI_HCD is not set # CONFIG_USB_UHCI is not set # CONFIG_USB_UHCI_ALT is not set # CONFIG_USB_OHCI is not set @@ -867,10 +898,10 @@ # CONFIG_USB_STORAGE_DATAFAB is not set # CONFIG_USB_STORAGE_FREECOM is not set # CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_STORAGE_DPCM is not set # CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -898,12 +929,10 @@ # # Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_DABUSB is not set # # USB Network adaptors # -# CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set @@ -926,27 +955,31 @@ # CONFIG_USB_SERIAL_EMPEG is not set # CONFIG_USB_SERIAL_FTDI_SIO is not set # CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set # CONFIG_USB_SERIAL_IR is not set # CONFIG_USB_SERIAL_EDGEPORT is not set # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set # CONFIG_USB_SERIAL_PL2303 is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set # CONFIG_USB_SERIAL_OMNINET is not set # -# Miscellaneous USB drivers +# USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set -# CONFIG_USB_ID75 is not set +# CONFIG_USB_AUERSWALD is not set # # Bluetooth support @@ -957,11 +990,21 @@ # Kernel hacking # CONFIG_NO_FRAME_POINTER=y -CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set -# CONFIG_MAGIC_SYSRQ is not set # CONFIG_NO_PGT_CACHE is not set -CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_LL is not set # CONFIG_DEBUG_DC21285_PORT is not set # CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +CONFIG_CRC32=y diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/def-configs/stork linux-2.5/arch/arm/def-configs/stork --- linux-2.5.5/arch/arm/def-configs/stork Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/def-configs/stork Fri Mar 1 15:07:37 2002 @@ -0,0 +1,976 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP310 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +CONFIG_SA1100_H3600=y +# CONFIG_SA1100_H3800 is not set +CONFIG_SA1100_H3XXX=y +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +CONFIG_SA1100_USB=m +CONFIG_SA1100_USB_NETLINK=m +# CONFIG_SA1100_USB_CHAR is not set +CONFIG_H3600_SLEEVE=m + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set + +# +# Processor Type +# +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +CONFIG_CPU_SA1100=y +# CONFIG_XSCALE_PMU is not set +# CONFIG_ARM_THUMB is not set +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +# CONFIG_FIQ is not set +CONFIG_CPU_FREQ=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +CONFIG_PCMCIA_PROBE=y +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +CONFIG_PCMCIA_SA1100=m +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=m +CONFIG_FPE_FASTFPE=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_PM=y +# CONFIG_APM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="N" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_REDBOOT_PARTS=y +CONFIG_MTD_BOOTLDR_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_GEOMETRY is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +CONFIG_MTD_SA1100=y +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +# CONFIG_MTD_EPXA10DB is not set +# CONFIG_MTD_PCI is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +CONFIG_WAVELAN=m +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=m + +# +# Wireless Pcmcia cards support +# +CONFIG_PCMCIA_HERMES=m +# CONFIG_AIRO_CS is not set +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=m +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +CONFIG_PCMCIA_XIRC2PS=m +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=115200 +CONFIG_SERIAL_8250=m +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_ATOMWIDE_SERIAL is not set +# CONFIG_DUALSP_SERIAL is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_RSA is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +CONFIG_L3=y +CONFIG_L3_ALGOBIT=y +CONFIG_L3_BIT_SA1100_GPIO=y + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +CONFIG_BIT_SA1100_GPIO=y + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=m +# CONFIG_PSMOUSE is not set +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_SA1100_RTC=m +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_PCMCIA_SERIAL_CS is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_CRAMFS=y +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +CONFIG_ZLIB_FS_INFLATE=y + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 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_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +CONFIG_FB_SA1100=y +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +# CONFIG_FBCON_CFB8 is not set +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_SA1100=y +CONFIG_SOUND_UDA1341=m +# CONFIG_SOUND_ASSABET_UDA1341 is not set +CONFIG_SOUND_H3600_UDA1341=m +# CONFIG_SOUND_PANGOLIN_UDA1341 is not set +# CONFIG_SOUND_SA1111_UDA1341 is not set +# CONFIG_SOUND_SA1100SSP is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_WAVEARTIST is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +# CONFIG_USB_OHCI_SA1111 is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# SCSI support is needed for USB Storage +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/armksyms.c linux-2.5/arch/arm/kernel/armksyms.c --- linux-2.5.5/arch/arm/kernel/armksyms.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/arm/kernel/armksyms.c Fri Mar 1 15:07:37 2002 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -123,6 +124,7 @@ EXPORT_SYMBOL(__readwrite_bug); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(set_irq_type); EXPORT_SYMBOL(pm_idle); EXPORT_SYMBOL(pm_power_off); @@ -182,7 +184,7 @@ EXPORT_SYMBOL_NOVERS(strlen); EXPORT_SYMBOL_NOVERS(strnlen); EXPORT_SYMBOL_NOVERS(strpbrk); -EXPORT_SYMBOL_NOVERS(strtok); +EXPORT_SYMBOL_NOVERS(strsep); EXPORT_SYMBOL_NOVERS(strrchr); EXPORT_SYMBOL_NOVERS(strstr); EXPORT_SYMBOL_NOVERS(memset); @@ -273,3 +275,7 @@ EXPORT_SYMBOL_NOVERS(__up_wakeup); EXPORT_SYMBOL(get_wchan); + +#ifdef CONFIG_PREEMPT +EXPORT_SYMBOL(kernel_flag); +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/calls.S linux-2.5/arch/arm/kernel/calls.S --- linux-2.5.5/arch/arm/kernel/calls.S Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/kernel/calls.S Tue Feb 26 21:24:48 2002 @@ -21,13 +21,13 @@ .long SYMBOL_NAME(sys_write) /* 5 */ .long SYMBOL_NAME(sys_open) .long SYMBOL_NAME(sys_close) - .long SYMBOL_NAME(sys_waitpid) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_waitpid */ .long SYMBOL_NAME(sys_creat) .long SYMBOL_NAME(sys_link) /* 10 */ .long SYMBOL_NAME(sys_unlink) .long SYMBOL_NAME(sys_execve_wrapper) .long SYMBOL_NAME(sys_chdir) - .long SYMBOL_NAME(sys_time) + .long SYMBOL_NAME(sys_time) /* used by libc4 */ .long SYMBOL_NAME(sys_mknod) /* 15 */ .long SYMBOL_NAME(sys_chmod) .long SYMBOL_NAME(sys_lchown16) @@ -36,15 +36,15 @@ .long SYMBOL_NAME(sys_lseek) /* 20 */ .long SYMBOL_NAME(sys_getpid) .long SYMBOL_NAME(sys_mount) - .long SYMBOL_NAME(sys_oldumount) + .long SYMBOL_NAME(sys_oldumount) /* used by libc4 */ .long SYMBOL_NAME(sys_setuid16) .long SYMBOL_NAME(sys_getuid16) /* 25 */ .long SYMBOL_NAME(sys_stime) .long SYMBOL_NAME(sys_ptrace) - .long SYMBOL_NAME(sys_alarm) + .long SYMBOL_NAME(sys_alarm) /* used by libc4 */ .long SYMBOL_NAME(sys_ni_syscall) /* was sys_fstat */ .long SYMBOL_NAME(sys_pause) -/* 30 */ .long SYMBOL_NAME(sys_utime) +/* 30 */ .long SYMBOL_NAME(sys_utime) /* used by libc4 */ .long SYMBOL_NAME(sys_ni_syscall) /* was sys_stty */ .long SYMBOL_NAME(sys_ni_syscall) /* was sys_getty */ .long SYMBOL_NAME(sys_access) @@ -62,7 +62,7 @@ /* 45 */ .long SYMBOL_NAME(sys_brk) .long SYMBOL_NAME(sys_setgid16) .long SYMBOL_NAME(sys_getgid16) - .long SYMBOL_NAME(sys_signal) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_signal */ .long SYMBOL_NAME(sys_geteuid16) /* 50 */ .long SYMBOL_NAME(sys_getegid16) .long SYMBOL_NAME(sys_acct) @@ -82,29 +82,29 @@ /* 65 */ .long SYMBOL_NAME(sys_getpgrp) .long SYMBOL_NAME(sys_setsid) .long SYMBOL_NAME(sys_sigaction) - .long SYMBOL_NAME(sys_sgetmask) - .long SYMBOL_NAME(sys_ssetmask) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_sgetmask */ + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_ssetmask */ /* 70 */ .long SYMBOL_NAME(sys_setreuid16) .long SYMBOL_NAME(sys_setregid16) .long SYMBOL_NAME(sys_sigsuspend_wrapper) .long SYMBOL_NAME(sys_sigpending) .long SYMBOL_NAME(sys_sethostname) /* 75 */ .long SYMBOL_NAME(sys_setrlimit) - .long SYMBOL_NAME(sys_old_getrlimit) + .long SYMBOL_NAME(sys_old_getrlimit) /* used by libc4 */ .long SYMBOL_NAME(sys_getrusage) .long SYMBOL_NAME(sys_gettimeofday) .long SYMBOL_NAME(sys_settimeofday) /* 80 */ .long SYMBOL_NAME(sys_getgroups16) .long SYMBOL_NAME(sys_setgroups16) - .long SYMBOL_NAME(old_select) + .long SYMBOL_NAME(old_select) /* used by libc4 */ .long SYMBOL_NAME(sys_symlink) .long SYMBOL_NAME(sys_ni_syscall) /* was sys_lstat */ /* 85 */ .long SYMBOL_NAME(sys_readlink) .long SYMBOL_NAME(sys_uselib) .long SYMBOL_NAME(sys_swapon) .long SYMBOL_NAME(sys_reboot) - .long SYMBOL_NAME(old_readdir) -/* 90 */ .long SYMBOL_NAME(old_mmap) + .long SYMBOL_NAME(old_readdir) /* used by libc4 */ +/* 90 */ .long SYMBOL_NAME(old_mmap) /* used by libc4 */ .long SYMBOL_NAME(sys_munmap) .long SYMBOL_NAME(sys_truncate) .long SYMBOL_NAME(sys_ftruncate) @@ -236,7 +236,22 @@ .long SYMBOL_NAME(sys_mincore) /* 220 */ .long SYMBOL_NAME(sys_madvise) .long SYMBOL_NAME(sys_fcntl64) + .long SYMBOL_NAME(sys_ni_syscall) /* TUX */ + .long SYMBOL_NAME(sys_ni_syscall) /* Security */ .long SYMBOL_NAME(sys_gettid) +/* 225 */ .long SYMBOL_NAME(sys_readahead) + .long SYMBOL_NAME(sys_setxattr) + .long SYMBOL_NAME(sys_lsetxattr) + .long SYMBOL_NAME(sys_fsetxattr) + .long SYMBOL_NAME(sys_getxattr) +/* 230 */ .long SYMBOL_NAME(sys_lgetxattr) + .long SYMBOL_NAME(sys_fgetxattr) + .long SYMBOL_NAME(sys_listxattr) + .long SYMBOL_NAME(sys_llistxattr) + .long SYMBOL_NAME(sys_flistxattr) +/* 235 */ .long SYMBOL_NAME(sys_removexattr) + .long SYMBOL_NAME(sys_lremovexattr) + .long SYMBOL_NAME(sys_fremovexattr) .long SYMBOL_NAME(sys_tkill) __syscall_end: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/debug.S linux-2.5/arch/arm/kernel/debug.S --- linux-2.5.5/arch/arm/kernel/debug.S Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/kernel/debug.S Fri Mar 1 15:07:37 2002 @@ -164,28 +164,49 @@ .endm #elif defined(CONFIG_ARCH_SA1100) + .macro addruart,rx mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x80000000 @ physical base address movne \rx, #0xf8000000 @ virtual address - @add \rx, \rx, #0x00050000 @ Ser3 - add \rx, \rx, #0x00010000 @ Ser1 + + @ We probe for the active serial port here, coherently with + @ the comment in include/asm-arm/arch-sa1100/uncompress.h. + @ We assume r1 can be clobbered. + + @ see if Ser3 is active + add \rx, \rx, #0x00050000 + ldr r1, [\rx, #UTCR3] + tst r1, #UTCR3_TXE + + @ if Ser3 is inactive, then try Ser1 + addeq \rx, \rx, #(0x00010000 - 0x00050000) + ldreq r1, [\rx, #UTCR3] + tsteq r1, #UTCR3_TXE + + @ if Ser1 is inactive, then try Ser2 + addeq \rx, \rx, #(0x00030000 - 0x00010000) + ldreq r1, [\rx, #UTCR3] + tsteq r1, #UTCR3_TXE + + @ if all ports are inactive, then there is nothing we can do + moveq pc, lr .endm .macro senduart,rd,rx - str \rd, [\rx, #0x14] @ UTDR + str \rd, [\rx, #UTDR] .endm .macro waituart,rd,rx -1001: ldr \rd, [\rx, #0x20] @ UTSR1 - tst \rd, #1 << 2 @ UTSR1_TNF +1001: ldr \rd, [\rx, #UTSR1] + tst \rd, #UTSR1_TNF beq 1001b .endm .macro busyuart,rd,rx -1001: ldr \rd, [\rx, #0x20] @ UTSR1 - tst \rd, #1 << 0 @ UTSR1_TBY +1001: ldr \rd, [\rx, #UTSR1] + tst \rd, #UTSR1_TBY bne 1001b .endm diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/ecard.c linux-2.5/arch/arm/kernel/ecard.c --- linux-2.5.5/arch/arm/kernel/ecard.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/arm/kernel/ecard.c Fri Mar 1 15:07:37 2002 @@ -91,17 +91,8 @@ ecard_loader_reset(volatile unsigned char *pa, loader_t loader); asmlinkage extern int ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader); -extern int setup_arm_irq(int, struct irqaction *); -extern void do_ecard_IRQ(int, struct pt_regs *); -static void -ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs); - -static struct irqaction irqexpansioncard = { - ecard_irq_noexpmask, SA_INTERRUPT, 0, "expansion cards", NULL, NULL -}; - static inline unsigned short ecard_getu16(unsigned char *v) { @@ -558,7 +549,7 @@ * * They are not meant to be called directly, but via enable/disable_irq. */ -static void ecard_enableirq(unsigned int irqnr) +static void ecard_irq_mask(unsigned int irqnr) { ecard_t *ec = slot_to_ecard(irqnr - 32); @@ -574,7 +565,7 @@ } } -static void ecard_disableirq(unsigned int irqnr) +static void ecard_irq_unmask(unsigned int irqnr) { ecard_t *ec = slot_to_ecard(irqnr - 32); @@ -587,6 +578,12 @@ } } +static struct irqchip ecard_chip = { + ack: ecard_irq_mask, + mask: ecard_irq_mask, + unmask: ecard_irq_unmask, +}; + void ecard_enablefiq(unsigned int fiqnr) { ecard_t *ec = slot_to_ecard(fiqnr); @@ -632,8 +629,7 @@ ec->irqaddr, ec->irqmask, *ec->irqaddr); } -static void -ecard_check_lockup(void) +static void ecard_check_lockup(struct irqdesc *desc) { static int last, lockup; ecard_t *ec; @@ -653,7 +649,7 @@ printk(KERN_ERR "\nInterrupt lockup detected - " "disabling all expansion card interrupts\n"); - disable_irq(IRQ_EXPANSIONCARD); + desc->chip->mask(IRQ_EXPANSIONCARD); printk("Expansion card IRQ state:\n"); @@ -674,11 +670,12 @@ } static void -ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs) +ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) { ecard_t *ec; int called = 0; + desc->chip->mask(irq); for (ec = cards; ec; ec = ec->next) { int pending; @@ -691,14 +688,15 @@ pending = ecard_default_ops.irqpending(ec); if (pending) { - do_ecard_IRQ(ec->irq, regs); + struct irqdesc *d = irq_desc + ec->irq; + d->handle(ec->irq, d, regs); called ++; } } - cli(); + desc->chip->unmask(irq); if (called == 0) - ecard_check_lockup(); + ecard_check_lockup(desc); } #ifdef HAS_EXPMASK @@ -714,20 +712,18 @@ }; static void -ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs) +ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) { const unsigned int statusmask = 15; unsigned int status; status = __raw_readb(EXPMASK_STATUS) & statusmask; if (status) { - unsigned int slot; - ecard_t *ec; -again: - slot = first_set[status]; - ec = slot_to_ecard(slot); + unsigned int slot = first_set[status]; + ecard_t *ec = slot_to_ecard(slot); + if (ec->claimed) { - unsigned int oldexpmask; + struct irqdesc *d = irqdesc + ec->irq; /* * this ugly code is so that we can operate a * prioritorising system: @@ -740,17 +736,7 @@ * Serial cards should go in 0/1, ethernet/scsi in 2/3 * otherwise you will lose serial data at high speeds! */ - oldexpmask = have_expmask; - have_expmask &= priority_masks[slot]; - __raw_writeb(have_expmask, EXPMASK_ENABLE); - sti(); - do_ecard_IRQ(ec->irq, regs); - cli(); - have_expmask = oldexpmask; - __raw_writeb(have_expmask, EXPMASK_ENABLE); - status = __raw_readb(EXPMASK_STATUS) & statusmask; - if (status) - goto again; + d->handle(ec->irq, d, regs); } else { printk(KERN_WARNING "card%d: interrupt from unclaimed " "card???\n", slot); @@ -761,8 +747,7 @@ printk(KERN_WARNING "Wild interrupt from backplane (masks)\n"); } -static void __init -ecard_probeirqhw(void) +static int __init ecard_probeirqhw(void) { ecard_t *ec; int found; @@ -772,24 +757,24 @@ found = (__raw_readb(EXPMASK_STATUS) & 15) == 0; __raw_writeb(0xff, EXPMASK_ENABLE); - if (!found) - return; - - printk(KERN_DEBUG "Expansion card interrupt " - "management hardware found\n"); + if (found) { + printk(KERN_DEBUG "Expansion card interrupt " + "management hardware found\n"); - irqexpansioncard.handler = ecard_irq_expmask; + /* for each card present, set a bit to '1' */ + have_expmask = 0x80000000; - /* for each card present, set a bit to '1' */ - have_expmask = 0x80000000; + for (ec = cards; ec; ec = ec->next) + have_expmask |= 1 << ec->slot_no; - for (ec = cards; ec; ec = ec->next) - have_expmask |= 1 << ec->slot_no; + __raw_writeb(have_expmask, EXPMASK_ENABLE); + } - __raw_writeb(have_expmask, EXPMASK_ENABLE); + return found; } #else -#define ecard_probeirqhw() +#define ecard_irqexp_handler NULL +#define ecard_probeirqhw() (0) #endif #ifndef IO_EC_MEMC8_BASE @@ -977,10 +962,9 @@ * hook the interrupt handlers */ if (ec->irq != 0 && ec->irq >= 32) { - irq_desc[ec->irq].mask_ack = ecard_disableirq; - irq_desc[ec->irq].mask = ecard_disableirq; - irq_desc[ec->irq].unmask = ecard_enableirq; - irq_desc[ec->irq].valid = 1; + set_irq_chip(ec->irq, &ecard_chip); + set_irq_handler(ec->irq, do_level_IRQ); + set_irq_flags(ec->irq, IRQF_VALID); } #ifdef CONFIG_ARCH_RPC @@ -1042,21 +1026,6 @@ return finding_pos; } -static void __init ecard_free_all(void) -{ - ecard_t *ec, *ecn; - - for (ec = cards; ec; ec = ecn) { - ecn = ec->next; - - kfree(ec); - } - - cards = NULL; - - memset(slot_to_expcard, 0, sizeof(slot_to_expcard)); -} - /* * Initialise the expansion card system. * Locate all hardware - interrupt management and @@ -1064,7 +1033,7 @@ */ void __init ecard_init(void) { - int slot; + int slot, irqhw; /* * Register our reboot notifier @@ -1086,13 +1055,10 @@ ecard_probe(8, ECARD_IOC); #endif - ecard_probeirqhw(); + irqhw = ecard_probeirqhw(); - if (setup_arm_irq(IRQ_EXPANSIONCARD, &irqexpansioncard)) { - printk(KERN_ERR "Unable to claim IRQ%d for expansion cards\n", - IRQ_EXPANSIONCARD); - ecard_free_all(); - } + set_irq_chained_handler(IRQ_EXPANSIONCARD, + irqhw ? ecard_irqexp_handler : ecard_irq_handler); ecard_proc_init(); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/entry-armo.S linux-2.5/arch/arm/kernel/entry-armo.S --- linux-2.5.5/arch/arm/kernel/entry-armo.S Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/arm/kernel/entry-armo.S Fri Mar 1 15:07:37 2002 @@ -354,7 +354,7 @@ @ adr lr, 1b orr lr, lr, #0x08000003 @ Force SVC - bne do_IRQ + bne asm_do_IRQ mov why, #0 get_current_task r5 @@ -377,7 +377,7 @@ @ adr lr, 1b orr lr, lr, #0x08000003 @ Force SVC - bne do_IRQ @ Returns to 1b + bne asm_do_IRQ @ Returns to 1b SVC_RESTORE_ALL __irq_invalid: mov r0, sp diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/entry-armv.S linux-2.5/arch/arm/kernel/entry-armv.S --- linux-2.5.5/arch/arm/kernel/entry-armv.S Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/kernel/entry-armv.S Fri Mar 1 15:07:37 2002 @@ -15,6 +15,7 @@ */ #include #include "entry-header.S" +#include #ifdef IOC_BASE @@ -690,8 +691,7 @@ msr cpsr_c, r9 mov r2, sp bl SYMBOL_NAME(do_DataAbort) - mov r0, #PSR_I_BIT | MODE_SVC - msr cpsr_c, r0 + set_cpsr_c r0, #PSR_I_BIT | MODE_SVC ldr r0, [sp, #S_PSR] msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr @@ -705,17 +705,53 @@ add r4, sp, #S_SP mov r6, lr stmia r4, {r5, r6, r7, r8, r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro +#ifdef CONFIG_PREEMPT + get_thread_info r8 + ldr r9, [r8, #TI_PREEMPT] @ get preempt count + add r7, r9, #1 @ increment it + str r7, [r8, #TI_PREEMPT] +#endif 1: get_irqnr_and_base r0, r6, r5, lr movne r1, sp @ @ routine called with r0 = irq number, r1 = struct pt_regs * @ adrsvc ne, lr, 1b - bne do_IRQ + bne asm_do_IRQ +#ifdef CONFIG_PREEMPT + ldr r0, [r8, #TI_FLAGS] @ get flags + tst r0, #_TIF_NEED_RESCHED + ldrne r6, .LCirq_stat + blne svc_preempt +preempt_return: + ldr r0, [r8, #TI_PREEMPT] @ read preempt value + teq r0, r7 + strne r0, [r0, -r0] @ bug() + str r9, [r8, #TI_PREEMPT] @ restore preempt count +#endif ldr r0, [sp, #S_PSR] @ irqs are already disabled msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr +#ifdef CONFIG_PREEMPT +svc_preempt: teq r9, #0 @ was preempt count = 0 + movne pc, lr @ no + ldr r0, [r6, #4] @ local_irq_count + ldr r1, [r6, #8] @ local_bh_count + adds r0, r0, r1 + movne pc, lr + ldr r1, [r8, #TI_TASK] + set_cpsr_c r2, #MODE_SVC @ enable IRQs + str r0, [r1, #0] @ current->state = TASK_RUNNING +1: bl SYMBOL_NAME(schedule) + set_cpsr_c r0, #PSR_I_BIT | MODE_SVC @ disable IRQs + ldr r0, [r8, #TI_FLAGS] + tst r0, #_TIF_NEED_RESCHED + beq preempt_return + set_cpsr_c r0, #MODE_SVC @ enable IRQs + b 1b +#endif + .align 5 __und_svc: sub sp, sp, #S_FRAME_SIZE stmia sp, {r0 - r12} @ save r0 - r12 @@ -733,8 +769,7 @@ mov r1, sp @ struct pt_regs *regs bl SYMBOL_NAME(do_undefinstr) -1: mov r0, #PSR_I_BIT | MODE_SVC - msr cpsr_c, r0 +1: set_cpsr_c r0, #PSR_I_BIT | MODE_SVC ldr lr, [sp, #S_PSR] @ Get SVC cpsr msr spsr, lr ldmia sp, {r0 - pc}^ @ Restore SVC registers @@ -755,8 +790,7 @@ mov r0, r2 @ address (pc) mov r1, sp @ regs bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler - mov r0, #PSR_I_BIT | MODE_SVC - msr cpsr_c, r0 + set_cpsr_c r0, #PSR_I_BIT | MODE_SVC ldr r0, [sp, #S_PSR] msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr @@ -769,6 +803,9 @@ .LCprocfns: .word SYMBOL_NAME(processor) #endif .LCfp: .word SYMBOL_NAME(fp_enter) +#ifdef CONFIG_PREEMPT +.LCirq_stat: .word SYMBOL_NAME(irq_stat) +#endif irq_prio_table @@ -793,8 +830,7 @@ #else bl cpu_data_abort #endif - mov r2, #MODE_SVC - msr cpsr_c, r2 @ Enable interrupts + set_cpsr_c r2, #MODE_SVC @ Enable interrupts mov r2, sp adrsvc al, lr, ret_from_exception b SYMBOL_NAME(do_DataAbort) @@ -809,15 +845,29 @@ stmdb r8, {sp, lr}^ alignment_trap r4, r7, __temp_irq zero_fp +#ifdef CONFIG_PREEMPT + get_thread_info r8 + ldr r9, [r8, #TI_PREEMPT] @ get preempt count + add r7, r9, #1 @ increment it + str r7, [r8, #TI_PREEMPT] +#endif 1: get_irqnr_and_base r0, r6, r5, lr movne r1, sp adrsvc ne, lr, 1b @ @ routine called with r0 = irq number, r1 = struct pt_regs * @ - bne do_IRQ + bne asm_do_IRQ +#ifdef CONFIG_PREEMPT + ldr r0, [r8, #TI_PREEMPT] + teq r0, r7 + strne r0, [r0, -r0] + str r9, [r8, #TI_PREEMPT] + mov tsk, r8 +#else + get_thread_info tsk +#endif mov why, #0 - get_current_task tsk b ret_to_user .align 5 @@ -833,15 +883,15 @@ adrsvc al, r9, ret_from_exception @ r9 = normal FP return adrsvc al, lr, fpundefinstr @ lr = undefined instr return -call_fpe: get_current_task r10 +call_fpe: get_thread_info r10 @ get current thread + ldr r4, [r10, #TI_TASK] @ get current task mov r8, #1 - strb r8, [r10, #TSK_USED_MATH] @ set current->used_math + strb r8, [r4, #TSK_USED_MATH] @ set current->used_math ldr r4, .LCfp - add r10, r10, #TSS_FPESAVE @ r10 = workspace + add r10, r10, #TI_FPSTATE @ r10 = workspace ldr pc, [r4] @ Call FP module USR entry point -fpundefinstr: mov r0, #MODE_SVC - msr cpsr_c, r0 @ Enable interrupts +fpundefinstr: set_cpsr_c r0, #MODE_SVC @ Enable interrupts mov r0, lr mov r1, sp adrsvc al, lr, ret_from_exception @@ -857,8 +907,7 @@ stmdb r8, {sp, lr}^ @ Save sp_usr lr_usr alignment_trap r4, r7, __temp_abt zero_fp - mov r0, #MODE_SVC - msr cpsr_c, r0 @ Enable interrupts + set_cpsr_c r0, #MODE_SVC @ Enable interrupts mov r0, r5 @ address (pc) mov r1, sp @ regs bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler @@ -867,7 +916,7 @@ * This is the return code to user mode for abort handlers */ ENTRY(ret_from_exception) - get_current_task tsk + get_thread_info tsk mov why, #0 b ret_to_user @@ -877,16 +926,16 @@ .text /* * Register switch for ARMv3 and ARMv4 processors - * r0 = previous, r1 = next, return previous. + * r0 = previous thread_info, r1 = next thread_info, return previous. * previous and next are guaranteed not to be the same. */ ENTRY(__switch_to) stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack mrs ip, cpsr str ip, [sp, #-4]! @ Save cpsr_SVC - str sp, [r0, #TSS_SAVE] @ Save sp_SVC - ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC - ldr r2, [r1, #TSS_DOMAIN] + str sp, [r0, #TI_CPU_SAVE] @ Save sp_SVC + ldr sp, [r1, #TI_CPU_SAVE] @ Get saved sp_SVC + ldr r2, [r1, #TI_CPU_DOMAIN] ldr ip, [sp], #4 mcr p15, 0, r2, c3, c0 @ Set domain register msr spsr, ip @ Save tasks CPSR into SPSR for this return diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/entry-common.S linux-2.5/arch/arm/kernel/entry-common.S --- linux-2.5.5/arch/arm/kernel/entry-common.S Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/kernel/entry-common.S Fri Mar 1 15:07:37 2002 @@ -9,6 +9,7 @@ */ #include #include "entry-header.S" +#include /* * We rely on the fact that R0 is at the bottom of the stack (due to @@ -34,55 +35,55 @@ * stack. */ ret_fast_syscall: -#error ldr r1, [tsk, #TSK_NEED_RESCHED] -#error ldr r2, [tsk, #TSK_SIGPENDING] - teq r1, #0 @ need_resched || sigpending - teqeq r2, #0 - bne slow + set_cpsr_c r1, #PSR_I_BIT | MODE_SVC @ disable interrupts + ldr r1, [tsk, #TI_FLAGS] + tst r1, #_TIF_WORK_MASK + bne ret_fast_work fast_restore_user_regs /* * Ok, we need to do extra processing, enter the slow path. */ -slow: str r0, [sp, #S_R0+S_OFF]! @ returned r0 - b 1f +ret_fast_work: + str r0, [sp, #S_R0+S_OFF]! @ returned r0 + b work_pending +work_resched: + bl SYMBOL_NAME(schedule) /* * "slow" syscall return path. "why" tells us if this was a real syscall. */ -reschedule: - bl SYMBOL_NAME(schedule) ENTRY(ret_to_user) ret_slow_syscall: -#error ldr r1, [tsk, #TSK_NEED_RESCHED] -#error ldr r2, [tsk, #TSK_SIGPENDING] -1: teq r1, #0 @ need_resched => schedule() - bne reschedule - teq r2, #0 @ sigpending => do_signal() - blne __do_signal + set_cpsr_c r1, #PSR_I_BIT | MODE_SVC @ disable interrupts + ldr r1, [tsk, #TI_FLAGS] + tst r1, #_TIF_WORK_MASK + beq no_work_pending +work_pending: + tst r1, #_TIF_NEED_RESCHED + bne work_resched + tst r1, #_TIF_NOTIFY_RESUME | _TIF_SIGPENDING + blne __do_notify_resume +no_work_pending: restore_user_regs -__do_signal: - mov r0, #0 @ NULL 'oldset' - mov r1, sp @ 'regs' +__do_notify_resume: + mov r0, sp @ 'regs' mov r2, why @ 'syscall' -#error b SYMBOL_NAME(do_signal) @ note the bl above sets lr + b SYMBOL_NAME(do_notify_resume) @ note the bl above sets lr /* - * This is how we return from a fork. __switch_to will be calling us - * with r0 pointing at the previous task that was running (ready for - * calling schedule_tail). + * This is how we return from a fork. */ ENTRY(ret_from_fork) - bl SYMBOL_NAME(schedule_tail) - get_current_task tsk - ldr ip, [tsk, #TSK_PTRACE] @ check for syscall tracing + get_thread_info tsk + ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing mov why, #1 - tst ip, #PT_TRACESYS @ are we tracing syscalls? + tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? beq ret_slow_syscall mov r1, sp mov r0, #1 @ trace exit [IP = 1] -#error bl SYMBOL_NAME(syscall_trace) + bl SYMBOL_NAME(syscall_trace) b ret_slow_syscall @@ -134,12 +135,12 @@ str r4, [sp, #-S_OFF]! @ push fifth arg - get_current_task tsk - ldr ip, [tsk, #TSK_PTRACE] @ check for syscall tracing + get_thread_info tsk + ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing bic scno, scno, #0xff000000 @ mask off SWI op-code eor scno, scno, #OS_NUMBER << 20 @ check OS number adr tbl, sys_call_table @ load syscall table pointer - tst ip, #PT_TRACESYS @ are we tracing syscalls? + tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? bne __sys_trace adrsvc al, lr, ret_fast_syscall @ return address @@ -160,7 +161,7 @@ __sys_trace: add r1, sp, #S_OFF mov r0, #0 @ trace entry [IP = 0] -#error bl SYMBOL_NAME(syscall_trace) + bl SYMBOL_NAME(syscall_trace) adrsvc al, lr, __sys_trace_return @ return address add r1, sp, #S_R0 + S_OFF @ pointer to regs @@ -173,7 +174,7 @@ str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 mov r1, sp mov r0, #1 @ trace exit [IP = 1] -#error bl SYMBOL_NAME(syscall_trace) + bl SYMBOL_NAME(syscall_trace) b ret_slow_syscall .align 5 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/entry-header.S linux-2.5/arch/arm/kernel/entry-header.S --- linux-2.5.5/arch/arm/kernel/entry-header.S Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/arm/kernel/entry-header.S Tue Feb 26 21:24:48 2002 @@ -113,7 +113,7 @@ msr cpsr_c, \temp .endm - .macro get_current_task, rd + .macro get_thread_info, rd mov \rd, sp, lsr #13 mov \rd, \rd, lsl #13 .endm @@ -171,7 +171,7 @@ .macro initialise_traps_extra .endm - .macro get_current_task, rd + .macro get_thread_info, rd mov \rd, sp, lsr #13 mov \rd, \rd, lsl #13 .endm @@ -197,10 +197,10 @@ * * We must set at least "tsk" and "why" when calling ret_with_reschedule. */ -scno .req r7 @ syscall number -tbl .req r8 @ syscall table pointer -why .req r8 @ Linux syscall (!= 0) -tsk .req r9 @ current task +scno .req r7 @ syscall number +tbl .req r8 @ syscall table pointer +why .req r8 @ Linux syscall (!= 0) +tsk .req r9 @ current thread_info /* * Get the system call number. @@ -214,6 +214,15 @@ #else mask_pc lr, lr ldr scno, [lr, #-4] @ get SWI instruction +#endif + .endm + + .macro set_cpsr_c, reg, mode +#if 1 + mov \reg, \mode + msr cpsr_c, \reg +#else + msr cpsr_c, \mode #endif .endm diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/head.S linux-2.5/arch/arm/kernel/head.S --- linux-2.5.5/arch/arm/kernel/head.S Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/kernel/head.S Fri Mar 1 15:07:37 2002 @@ -14,6 +14,7 @@ #include #include +#include #include #define K(a,b,c) ((a) << 24 | (b) << 12 | (c)) @@ -126,7 +127,7 @@ mov r1, #MACH_TYPE_L7200 #endif - mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode + mov r0, #PSR_F_BIT | PSR_I_BIT | MODE_SVC @ make sure svc mode msr cpsr_c, r0 @ and all irqs disabled bl __lookup_processor_type teq r10, #0 @ invalid processor? @@ -149,7 +150,7 @@ .long SYMBOL_NAME(processor_id) .long SYMBOL_NAME(__machine_arch_type) .long SYMBOL_NAME(cr_alignment) - .long SYMBOL_NAME(init_task_union)+8192 + .long SYMBOL_NAME(init_thread_union)+8192 .type __ret, %function __ret: ldr lr, __switch_data @@ -374,7 +375,7 @@ and r6, r6, r9 @ mask wanted bits teq r5, r6 moveq pc, lr - add r10, r10, #36 @ sizeof(proc_info_list) + add r10, r10, #PROC_INFO_SZ @ sizeof(proc_info_list) cmp r10, r7 blt 1b mov r10, #0 @ unknown processor diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/init_task.c linux-2.5/arch/arm/kernel/init_task.c --- linux-2.5.5/arch/arm/kernel/init_task.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/arm/kernel/init_task.c Tue Feb 26 21:24:48 2002 @@ -16,7 +16,7 @@ struct mm_struct init_mm = INIT_MM(init_mm); /* - * Initial task structure. + * Initial thread structure. * * We need to make sure that this is 8192-byte aligned due to the * way process stacks are handled. This is done by making sure @@ -25,5 +25,13 @@ * * The things we do for performance.. */ -union task_union init_task_union __attribute__((__section__(".init.task"))) = - { INIT_TASK(init_task_union.task) }; +union thread_union init_thread_union + __attribute__((__section__(".init.task"))) = + { INIT_THREAD_INFO(init_task) }; + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +struct task_struct init_task = INIT_TASK(init_task); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/irq.c linux-2.5/arch/arm/kernel/irq.c --- linux-2.5.5/arch/arm/kernel/irq.c Wed Feb 20 02:10:52 2002 +++ linux-2.5/arch/arm/kernel/irq.c Fri Mar 1 15:07:37 2002 @@ -34,8 +34,6 @@ #include #include -#include /* pick up fixup_irq definition */ - /* * Maximum IRQ count. Currently, this is arbitary. However, it should * not be set too low to prevent false triggering. Conversely, if it @@ -54,25 +52,44 @@ /* * Dummy mask/unmask handler */ -static void dummy_mask_unmask_irq(unsigned int irq) +void dummy_mask_unmask_irq(unsigned int irq) { } +void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + irq_err_count += 1; + printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); +} + +static struct irqchip bad_chip = { + ack: dummy_mask_unmask_irq, + mask: dummy_mask_unmask_irq, + unmask: dummy_mask_unmask_irq, +}; + +static struct irqdesc bad_irq_desc = { + chip: &bad_chip, + handle: do_bad_IRQ, + depth: 1, +}; + /** * disable_irq - disable an irq and wait for completion * @irq: Interrupt to disable * - * Disable the selected interrupt line. + * Disable the selected interrupt line. We do this lazily. * - * This function may be called - with care - from IRQ context. + * This function may be called from IRQ context. */ void disable_irq(unsigned int irq) { + struct irqdesc *desc = irq_desc + irq; unsigned long flags; spin_lock_irqsave(&irq_controller_lock, flags); - irq_desc[irq].enabled = 0; - irq_desc[irq].mask(irq); + if (!desc->depth++) + desc->enabled = 0; spin_unlock_irqrestore(&irq_controller_lock, flags); } @@ -80,19 +97,35 @@ * enable_irq - enable interrupt handling on an irq * @irq: Interrupt to enable * - * Re-enables the processing of interrupts on this IRQ line + * Re-enables the processing of interrupts on this IRQ line. + * Note that this may call the interrupt handler, so you may + * get unexpected results if you hold IRQs disabled. * * This function may be called from IRQ context. */ void enable_irq(unsigned int irq) { + struct irqdesc *desc = irq_desc + irq; unsigned long flags; + int pending = 0; spin_lock_irqsave(&irq_controller_lock, flags); - irq_desc[irq].probing = 0; - irq_desc[irq].triggered = 0; - irq_desc[irq].enabled = 1; - irq_desc[irq].unmask(irq); + if (unlikely(!desc->depth)) { + printk("enable_irq(%u) unbalanced from %p\n", irq, + __builtin_return_address(0)); + } else if (!--desc->depth) { + desc->probing = 0; + desc->enabled = 1; + desc->chip->unmask(irq); + pending = desc->pending; + desc->pending = 0; + /* + * If the interrupt was waiting to be processed, + * retrigger it. + */ + if (pending) + desc->chip->rerun(irq); + } spin_unlock_irqrestore(&irq_controller_lock, flags); } @@ -128,7 +161,7 @@ * a large number if IRQs to appear in the same jiffie with the * same instruction pointer (or within 2 instructions). */ -static void check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs) +static int check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs) { unsigned long instr_ptr = instruction_pointer(regs); @@ -138,123 +171,283 @@ if (desc->lck_cnt > MAX_IRQ_CNT) { printk(KERN_ERR "IRQ LOCK: IRQ%d is locking the system, disabled\n", irq); - disable_irq(irq); + return 1; } } else { desc->lck_cnt = 0; desc->lck_pc = instruction_pointer(regs); desc->lck_jif = jiffies; } + return 0; +} + +static void +__do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) +{ + unsigned int status; + + spin_unlock(&irq_controller_lock); + + if (!(action->flags & SA_INTERRUPT)) + __sti(); + + status = 0; + do { + status |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + + __cli(); + spin_lock(&irq_controller_lock); } /* - * do_IRQ handles all normal device IRQ's + * This is for software-decoded IRQs. The caller is expected to + * handle the ack, clear, mask and unmask issues. */ -asmlinkage void do_IRQ(int irq, struct pt_regs * regs) +void +do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) { - struct irqdesc * desc; - struct irqaction * action; - int cpu; + struct irqaction *action; + const int cpu = smp_processor_id(); + + desc->triggered = 1; + + irq_enter(cpu, irq); + kstat.irqs[cpu][irq]++; + + action = desc->action; + if (action) + __do_irq(irq, desc->action, regs); + + irq_exit(cpu, irq); +} + +/* + * Most edge-triggered IRQ implementations seem to take a broken + * approach to this. Hence the complexity. + */ +void +do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + const int cpu = smp_processor_id(); - irq = fixup_irq(irq); + desc->triggered = 1; /* - * Some hardware gives randomly wrong interrupts. Rather - * than crashing, do something sensible. + * If we're currently running this IRQ, or its disabled, + * we shouldn't process the IRQ. Instead, turn on the + * hardware masks. */ - if (irq >= NR_IRQS) - goto bad_irq; + if (unlikely(desc->running || !desc->enabled)) + goto running; - desc = irq_desc + irq; + /* + * Acknowledge and clear the IRQ, but don't mask it. + */ + desc->chip->ack(irq); - spin_lock(&irq_controller_lock); - desc->mask_ack(irq); - spin_unlock(&irq_controller_lock); + /* + * Mark the IRQ currently in progress. + */ + desc->running = 1; - cpu = smp_processor_id(); irq_enter(cpu, irq); kstat.irqs[cpu][irq]++; - desc->triggered = 1; - /* Return with this interrupt masked if no action */ - action = desc->action; + do { + struct irqaction *action; - if (action) { - int status = 0; + action = desc->action; + if (!action) + break; - if (desc->nomask) { - spin_lock(&irq_controller_lock); - desc->unmask(irq); - spin_unlock(&irq_controller_lock); + if (desc->pending && desc->enabled) { + desc->pending = 0; + desc->chip->unmask(irq); } - if (!(action->flags & SA_INTERRUPT)) - __sti(); + __do_irq(irq, action, regs); + } while (desc->pending); - do { - status |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - - if (status & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - __cli(); - - if (!desc->nomask && desc->enabled) { - spin_lock(&irq_controller_lock); - desc->unmask(irq); - spin_unlock(&irq_controller_lock); + irq_exit(cpu, irq); + + desc->running = 0; + + /* + * If we were disabled or freed, shut down the handler. + */ + if (likely(desc->action && !check_irq_lock(desc, irq, regs))) + return; + + running: + /* + * We got another IRQ while this one was masked or + * currently running. Delay it. + */ + desc->pending = 1; + desc->chip->mask(irq); + desc->chip->ack(irq); +} + +/* + * Level-based IRQ handler. Nice and simple. + */ +void +do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + struct irqaction *action; + const int cpu = smp_processor_id(); + + desc->triggered = 1; + + /* + * Acknowledge, clear _AND_ disable the interrupt. + */ + desc->chip->ack(irq); + + if (likely(desc->enabled)) { + irq_enter(cpu, irq); + kstat.irqs[cpu][irq]++; + + /* + * Return with this interrupt masked if no action + */ + action = desc->action; + if (action) { + __do_irq(irq, desc->action, regs); + + if (likely(desc->enabled && + !check_irq_lock(desc, irq, regs))) + desc->chip->unmask(irq); } } + irq_exit(cpu, irq); +} + +/* + * do_IRQ handles all hardware IRQ's. Decoded IRQs should not + * come via this function. Instead, they should provide their + * own 'handler' + */ +asmlinkage void asm_do_IRQ(int irq, struct pt_regs *regs) +{ + struct irqdesc *desc = irq_desc + irq; + /* - * Debug measure - hopefully we can continue if an - * IRQ lockup problem occurs... + * Some hardware gives randomly wrong interrupts. Rather + * than crashing, do something sensible. */ - check_irq_lock(desc, irq, regs); + if (irq >= NR_IRQS) + desc = &bad_irq_desc; - irq_exit(cpu, irq); + spin_lock(&irq_controller_lock); + desc->handle(irq, desc, regs); + spin_unlock(&irq_controller_lock); - if (softirq_pending(cpu)) + if (softirq_pending(smp_processor_id())) do_softirq(); - return; +} -bad_irq: - irq_err_count += 1; - printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); - return; +void __set_irq_handler(unsigned int irq, irq_handler_t handle, int is_chained) +{ + struct irqdesc *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to install handler for IRQ%d\n", irq); + return; + } + + if (handle == NULL) + handle = do_bad_IRQ; + + desc = irq_desc + irq; + + if (is_chained && desc->chip == &bad_chip) + printk(KERN_WARNING "Trying to install chained handler for IRQ%d\n", irq); + + spin_lock_irqsave(&irq_controller_lock, flags); + if (handle == do_bad_IRQ) { + desc->chip->mask(irq); + desc->chip->ack(irq); + desc->depth = 1; + desc->enabled = 0; + } + desc->handle = handle; + if (handle != do_bad_IRQ && is_chained) { + desc->valid = 0; + desc->probe_ok = 0; + desc->depth = 0; + desc->chip->unmask(irq); + } + spin_unlock_irqrestore(&irq_controller_lock, flags); } -#ifdef CONFIG_ARCH_ACORN -void do_ecard_IRQ(int irq, struct pt_regs *regs) +void set_irq_chip(unsigned int irq, struct irqchip *chip) { - struct irqdesc * desc; - struct irqaction * action; - int cpu; + struct irqdesc *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq); + return; + } + + if (chip == NULL) + chip = &bad_chip; desc = irq_desc + irq; + spin_lock_irqsave(&irq_controller_lock, flags); + desc->chip = chip; + spin_unlock_irqrestore(&irq_controller_lock, flags); +} - cpu = smp_processor_id(); - kstat.irqs[cpu][irq]++; - desc->triggered = 1; +int set_irq_type(unsigned int irq, unsigned int type) +{ + struct irqdesc *desc; + unsigned long flags; + int ret = -ENXIO; - action = desc->action; + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq); + return -ENODEV; + } - if (action) { - do { - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - } else { - spin_lock(&irq_controller_lock); - desc->mask(irq); - spin_unlock(&irq_controller_lock); + desc = irq_desc + irq; + if (desc->chip->type) { + spin_lock_irqsave(&irq_controller_lock, flags); + ret = desc->chip->type(irq, type); + spin_unlock_irqrestore(&irq_controller_lock, flags); } + + return ret; +} + +void set_irq_flags(unsigned int irq, unsigned int iflags) +{ + struct irqdesc *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq); + return; + } + + desc = irq_desc + irq; + spin_lock_irqsave(&irq_controller_lock, flags); + desc->valid = (iflags & IRQF_VALID) != 0; + desc->probe_ok = (iflags & IRQF_PROBE) != 0; + desc->noautoenable = (iflags & IRQF_NOAUTOEN) != 0; + spin_unlock_irqrestore(&irq_controller_lock, flags); } -#endif -int setup_arm_irq(int irq, struct irqaction * new) +int setup_irq(unsigned int irq, struct irqaction *new) { int shared = 0; struct irqaction *old, **p; @@ -302,11 +495,14 @@ *p = new; if (!shared) { - desc->nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0; - desc->probing = 0; + desc->probing = 0; + desc->running = 0; + desc->pending = 0; + desc->depth = 1; if (!desc->noautoenable) { + desc->depth = 0; desc->enabled = 1; - desc->unmask(irq); + desc->chip->unmask(irq); } } @@ -366,7 +562,7 @@ action->next = NULL; action->dev_id = dev_id; - retval = setup_arm_irq(irq, action); + retval = setup_irq(irq, action); if (retval) kfree(action); @@ -433,14 +629,12 @@ */ spin_lock_irq(&irq_controller_lock); for (i = 0; i < NR_IRQS; i++) { - if (!irq_desc[i].valid || - !irq_desc[i].probe_ok || - irq_desc[i].action) + if (!irq_desc[i].probe_ok || irq_desc[i].action) continue; irq_desc[i].probing = 1; irq_desc[i].triggered = 0; - irq_desc[i].unmask(i); + irq_desc[i].chip->unmask(i); irqs += 1; } spin_unlock_irq(&irq_controller_lock); @@ -456,15 +650,13 @@ */ spin_lock_irq(&irq_controller_lock); for (i = 0; i < NR_IRQS; i++) { - if (irq_desc[i].probing && - irq_desc[i].triggered) { + if (irq_desc[i].probing && irq_desc[i].triggered) { irq_desc[i].probing = 0; irqs -= 1; } } spin_unlock_irq(&irq_controller_lock); - /* now filter out any obviously spurious interrupts */ return irqs; } @@ -508,17 +700,12 @@ void __init init_IRQ(void) { + struct irqdesc *desc; extern void init_dma(void); int irq; - for (irq = 0; irq < NR_IRQS; irq++) { - irq_desc[irq].probe_ok = 0; - irq_desc[irq].valid = 0; - irq_desc[irq].noautoenable = 0; - irq_desc[irq].mask_ack = dummy_mask_unmask_irq; - irq_desc[irq].mask = dummy_mask_unmask_irq; - irq_desc[irq].unmask = dummy_mask_unmask_irq; - } + for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) + *desc = bad_irq_desc; init_arch_irq(); init_dma(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/process.c linux-2.5/arch/arm/kernel/process.c --- linux-2.5.5/arch/arm/kernel/process.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/arm/kernel/process.c Tue Feb 26 21:24:48 2002 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include /* @@ -83,9 +85,7 @@ void cpu_idle(void) { /* endless idle loop with no priority at all */ - init_idle(); - current->nice = 20; - + preempt_disable(); while (1) { void (*idle)(void) = pm_idle; if (!idle) @@ -228,51 +228,61 @@ /* * Task structure and kernel stack allocation. */ -static struct task_struct *task_struct_head; -static unsigned int nr_task_struct; +static unsigned long *thread_info_head; +static unsigned int nr_thread_info; #ifdef CONFIG_CPU_32 #define EXTRA_TASK_STRUCT 4 +#define ll_alloc_task_struct() ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) +#define ll_free_task_struct(p) free_pages((unsigned long)(p),1) #else +extern unsigned long get_page_8k(int priority); +extern void free_page_8k(unsigned long page); + #define EXTRA_TASK_STRUCT 0 +#define ll_alloc_task_struct() ((struct task_struct *)get_page_8k(GFP_KERNEL)) +#define ll_free_task_struct(p) free_page_8k((unsigned long)(p)) #endif -struct task_struct *alloc_task_struct(void) +struct thread_info *alloc_thread_info(void) { - struct task_struct *tsk; + struct thread_info *thread = NULL; - if (EXTRA_TASK_STRUCT) - tsk = task_struct_head; - else - tsk = NULL; - - if (tsk) { - task_struct_head = tsk->next_task; - nr_task_struct -= 1; - } else - tsk = ll_alloc_task_struct(); + if (EXTRA_TASK_STRUCT) { + unsigned long *p = thread_info_head; + + if (p) { + thread_info_head = (unsigned long *)p[0]; + nr_thread_info -= 1; + } + thread = (struct thread_info *)p; + } + + if (!thread) + thread = ll_alloc_task_struct(); #ifdef CONFIG_SYSRQ /* * The stack must be cleared if you want SYSRQ-T to * give sensible stack usage information */ - if (tsk) { - char *p = (char *)tsk; + if (thread) { + char *p = (char *)thread; memzero(p+KERNEL_STACK_SIZE, KERNEL_STACK_SIZE); } #endif - return tsk; + return thread; } -void __free_task_struct(struct task_struct *p) +void free_thread_info(struct thread_info *thread) { - if (EXTRA_TASK_STRUCT && nr_task_struct < EXTRA_TASK_STRUCT) { - p->next_task = task_struct_head; - task_struct_head = p; - nr_task_struct += 1; + if (EXTRA_TASK_STRUCT && nr_thread_info < EXTRA_TASK_STRUCT) { + unsigned long *p = (unsigned long *)thread; + p[0] = (unsigned long)thread_info_head; + thread_info_head = p; + nr_thread_info += 1; } else - ll_free_task_struct(p); + ll_free_task_struct(thread); } /* @@ -284,10 +294,13 @@ void flush_thread(void) { - memset(¤t->thread.debug, 0, sizeof(struct debug_info)); - memset(¤t->thread.fpstate, 0, sizeof(union fp_state)); + struct thread_info *thread = current_thread_info(); + struct task_struct *tsk = current; + + memset(&tsk->thread.debug, 0, sizeof(struct debug_info)); + memset(&thread->fpstate, 0, sizeof(union fp_state)); + current->used_math = 0; - current->flags &= ~PF_USEDFPU; } void release_thread(struct task_struct *dead_task) @@ -300,21 +313,19 @@ unsigned long unused, struct task_struct * p, struct pt_regs * regs) { - struct pt_regs * childregs; - struct context_save_struct * save; - - atomic_set(&p->thread.refcount, 1); + struct pt_regs *childregs; + struct cpu_context_save *save; - childregs = ((struct pt_regs *)((unsigned long)p + 8192)) - 1; + childregs = ((struct pt_regs *)((unsigned long)p->thread_info + THREAD_SIZE)) - 1; *childregs = *regs; childregs->ARM_r0 = 0; childregs->ARM_sp = esp; - save = ((struct context_save_struct *)(childregs)) - 1; + save = ((struct cpu_context_save *)(childregs)) - 1; *save = INIT_CSS; save->pc |= (unsigned long)ret_from_fork; - p->thread.save = save; + p->thread_info->cpu_context = save; return 0; } @@ -324,10 +335,13 @@ */ int dump_fpu (struct pt_regs *regs, struct user_fp *fp) { - if (current->used_math) - memcpy(fp, ¤t->thread.fpstate.soft, sizeof (*fp)); + struct thread_info *thread = current_thread_info(); + int used_math = current->used_math; + + if (used_math) + memcpy(fp, &thread->fpstate.soft, sizeof (*fp)); - return current->used_math; + return used_math; } /* @@ -405,7 +419,7 @@ return 0; stack_page = 4096 + (unsigned long)p; - fp = get_css_fp(&p->thread); + fp = thread_saved_fp(p); do { if (fp < stack_page || fp > 4092+stack_page) return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/ptrace.c linux-2.5/arch/arm/kernel/ptrace.c --- linux-2.5.5/arch/arm/kernel/ptrace.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/arm/kernel/ptrace.c Fri Mar 1 15:07:37 2002 @@ -9,6 +9,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include #include #include #include @@ -33,7 +34,7 @@ /* * Breakpoint SWI instruction: SWI &9F0001 */ -#define BREAKINST 0xef9f0001 +#define BREAKINST_ARM 0xef9f0001 /* * Get the address of the live pt_regs for the specified task. @@ -72,7 +73,7 @@ newregs = *regs; newregs.uregs[offset] = data; - + if (valid_user_regs(&newregs)) { regs->uregs[offset] = data; ret = 0; @@ -182,6 +183,20 @@ return val; } +#define OP_MASK 0x01e00000 +#define OP_AND 0x00000000 +#define OP_EOR 0x00200000 +#define OP_SUB 0x00400000 +#define OP_RSB 0x00600000 +#define OP_ADD 0x00800000 +#define OP_ADC 0x00a00000 +#define OP_SBC 0x00c00000 +#define OP_RSC 0x00e00000 +#define OP_ORR 0x01800000 +#define OP_MOV 0x01a00000 +#define OP_BIC 0x01c00000 +#define OP_MVN 0x01e00000 + static unsigned long get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn) { @@ -200,21 +215,21 @@ aluop1 = ptrace_getrn(child, insn); aluop2 = ptrace_getaluop2(child, insn); - ccbit = get_stack_long(child, REG_PSR) & CC_C_BIT ? 1 : 0; + ccbit = get_stack_long(child, REG_PSR) & PSR_C_BIT ? 1 : 0; - switch (insn & 0x01e00000) { - case 0x00000000: alt = aluop1 & aluop2; break; - case 0x00200000: alt = aluop1 ^ aluop2; break; - case 0x00400000: alt = aluop1 - aluop2; break; - case 0x00600000: alt = aluop2 - aluop1; break; - case 0x00800000: alt = aluop1 + aluop2; break; - case 0x00a00000: alt = aluop1 + aluop2 + ccbit; break; - case 0x00c00000: alt = aluop1 - aluop2 + ccbit; break; - case 0x00e00000: alt = aluop2 - aluop1 + ccbit; break; - case 0x01800000: alt = aluop1 | aluop2; break; - case 0x01a00000: alt = aluop2; break; - case 0x01c00000: alt = aluop1 & ~aluop2; break; - case 0x01e00000: alt = ~aluop2; break; + switch (insn & OP_MASK) { + case OP_AND: alt = aluop1 & aluop2; break; + case OP_EOR: alt = aluop1 ^ aluop2; break; + case OP_SUB: alt = aluop1 - aluop2; break; + case OP_RSB: alt = aluop2 - aluop1; break; + case OP_ADD: alt = aluop1 + aluop2; break; + case OP_ADC: alt = aluop1 + aluop2 + ccbit; break; + case OP_SBC: alt = aluop1 - aluop2 + ccbit; break; + case OP_RSC: alt = aluop2 - aluop1 + ccbit; break; + case OP_ORR: alt = aluop1 | aluop2; break; + case OP_MOV: alt = aluop2; break; + case OP_BIC: alt = aluop1 & ~aluop2; break; + case OP_MVN: alt = ~aluop2; break; } break; } @@ -275,7 +290,7 @@ base = ptrace_getrn(child, insn); if (read_tsk_long(child, base + nr_regs, &alt) == 0) - alt = pc_pointer (alt); + alt = pc_pointer(alt); break; } break; @@ -312,7 +327,7 @@ if (nr < 2) { res = read_tsk_long(child, addr, &dbg->bp[nr].insn); if (res == 0) - res = write_tsk_long(child, addr, BREAKINST); + res = write_tsk_long(child, addr, BREAKINST_ARM); if (res == 0) { dbg->bp[nr].address = addr; @@ -381,7 +396,7 @@ read_tsk_long(child, dbg->bp[i].address, &tmp); write_tsk_long(child, dbg->bp[i].address, dbg->bp[i].insn); - if (tmp != BREAKINST) + if (tmp != BREAKINST_ARM) printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n"); } } @@ -455,9 +470,9 @@ if ((unsigned long) data > _NSIG) break; if (request == PTRACE_SYSCALL) - child->ptrace |= PT_TRACESYS; + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); else - child->ptrace &= ~PT_TRACESYS; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; /* make sure single-step breakpoint is gone. */ __ptrace_cancel_bpt(child); @@ -490,7 +505,7 @@ if ((unsigned long) data > _NSIG) break; child->thread.debug.nsaved = -1; - child->ptrace &= ~PT_TRACESYS; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; /* give it a chance to run. */ wake_up_process(child); @@ -547,7 +562,7 @@ break; /* we should check child->used_math here */ - ret = __copy_to_user((void *)data, &child->thread.fpstate, + ret = __copy_to_user((void *)data, &child->thread_info->fpstate, sizeof(struct user_fp)) ? -EFAULT : 0; break; @@ -560,7 +575,7 @@ break; child->used_math = 1; - ret = __copy_from_user(&child->thread.fpstate, (void *)data, + ret = __copy_from_user(&child->thread_info->fpstate, (void *)data, sizeof(struct user_fp)) ? -EFAULT : 0; break; @@ -616,7 +631,7 @@ ret = do_ptrace(request, child, addr, data); out_tsk: - free_task_struct(child); + put_task_struct(child); out: unlock_kernel(); return ret; @@ -626,8 +641,9 @@ { unsigned long ip; - if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) - != (PT_PTRACED|PT_TRACESYS)) + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) return; /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/setup.c linux-2.5/arch/arm/kernel/setup.c --- linux-2.5.5/arch/arm/kernel/setup.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/kernel/setup.c Fri Mar 1 15:07:37 2002 @@ -38,6 +38,10 @@ #define CONFIG_CMDLINE "" #endif +#ifdef CONFIG_PREEMPT +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; +#endif + #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE) char fpe_type[8]; @@ -69,6 +73,9 @@ #ifdef MULTI_CPU struct processor processor; #endif +#ifdef MULTI_TLB +struct cpu_tlb_fns cpu_tlb; +#endif unsigned char aux_device_present; char elf_platform[ELF_PLATFORM_SIZE]; @@ -176,7 +183,7 @@ static inline void dump_cache(const char *prefix, unsigned int cache) { - unsigned int mult = 2 + CACHE_M(cache) ? 1 : 0; + unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0); printk("%s size %dK associativity %d line length %d sets %d\n", prefix, @@ -238,6 +245,9 @@ #ifdef MULTI_CPU processor = *list->proc; #endif +#ifdef MULTI_TLB + cpu_tlb = *list->tlb; +#endif printk("Processor: %s %s revision %d\n", proc_info.manufacturer, proc_info.cpu_name, @@ -661,7 +671,7 @@ static void c_show_cache(struct seq_file *m, const char *type, unsigned int cache) { - unsigned int mult = 2 + CACHE_M(cache) ? 1 : 0; + unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0); seq_printf(m, "%s size\t\t: %d\n" "%s assoc\t\t: %d\n" @@ -734,7 +744,7 @@ cache_types[CACHE_TYPE(cache_info)], cache_clean[CACHE_TYPE(cache_info)], cache_lockdown[CACHE_TYPE(cache_info)], - CACHE_S(cache_info) ? "separate I,D" : "unified"); + CACHE_S(cache_info) ? "Harvard" : "Unified"); if (CACHE_S(cache_info)) { c_show_cache(m, "I", CACHE_ISIZE(cache_info)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/signal.c linux-2.5/arch/arm/kernel/signal.c --- linux-2.5.5/arch/arm/kernel/signal.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/arch/arm/kernel/signal.c Fri Mar 1 15:07:37 2002 @@ -396,8 +396,12 @@ if (__put_user(retcodes[idx], rc)) return 1; - flush_icache_range((unsigned long)rc, - (unsigned long)(rc + 1)); + /* + * Ensure that the instruction cache sees + * the return code written onto the stack. + */ + cpu_icache_invalidate_range((unsigned long)rc, + (unsigned long)(rc + 1)); retcode = ((unsigned long)rc) + thumb; } @@ -480,6 +484,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { + struct thread_info *thread = current_thread_info(); struct task_struct *tsk = current; int usig = sig; int ret; @@ -487,8 +492,8 @@ /* * translate the signal */ - if (usig < 32 && tsk->exec_domain && tsk->exec_domain->signal_invmap) - usig = tsk->exec_domain->signal_invmap[usig]; + if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap) + usig = thread->exec_domain->signal_invmap[usig]; /* * Set up the stack frame @@ -532,7 +537,7 @@ * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) +int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) { struct k_sigaction *ka; siginfo_t info; @@ -677,4 +682,11 @@ if (single_stepping) ptrace_set_bpt(current); return 0; +} + +asmlinkage void +do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) +{ + if (thread_flags & _TIF_SIGPENDING) + do_signal(NULL, regs, syscall); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/time.c linux-2.5/arch/arm/kernel/time.c --- linux-2.5.5/arch/arm/kernel/time.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/arm/kernel/time.c Fri Mar 1 15:07:37 2002 @@ -31,9 +31,15 @@ #include #include -extern int setup_arm_irq(int, struct irqaction *); extern rwlock_t xtime_lock; extern unsigned long wall_jiffies; + +/* this needs a better home */ +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; + +#ifdef CONFIG_SA1100_RTC_MODULE +EXPORT_SYMBOL(rtc_lock); +#endif /* change this if you have some constant time drift */ #define USECS_PER_JIFFY (1000000/HZ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/traps.c linux-2.5/arch/arm/kernel/traps.c --- linux-2.5.5/arch/arm/kernel/traps.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/arm/kernel/traps.c Fri Mar 1 15:07:37 2002 @@ -95,7 +95,7 @@ int i; printk("Code: "); - for (i = -2; i < 3; i++) { + for (i = -4; i < 1; i++) { unsigned int val, bad; if (thumb) @@ -115,7 +115,7 @@ static void dump_stack(struct task_struct *tsk, unsigned long sp) { - dump_mem("Stack: ", sp - 16, 8192+(unsigned long)tsk); + dump_mem("Stack: ", sp - 16, 8192+(unsigned long)tsk->thread_info); } static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) @@ -146,7 +146,7 @@ void show_trace_task(struct task_struct *tsk) { if (tsk != current) { - unsigned int fp = tsk->thread.save->fp; + unsigned int fp = thread_saved_fp(tsk); c_backtrace(fp, 0x10); } } @@ -304,16 +304,17 @@ static int bad_syscall(int n, struct pt_regs *regs) { + struct thread_info *thread = current_thread_info(); siginfo_t info; /* You might think just testing `handler' would be enough, but PER_LINUX * points it to no_lcall7 to catch undercover SVr4 binaries. Gutted. */ - if (current->personality != PER_LINUX && current->exec_domain->handler) { + if (current->personality != PER_LINUX && thread->exec_domain->handler) { /* Hand it off to iBCS. The extra parameter and consequent type * forcing is necessary because of the weird ARM calling convention. */ - current->exec_domain->handler(n, regs); + thread->exec_domain->handler(n, regs); return regs->ARM_r0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/kernel/via82c505.c linux-2.5/arch/arm/kernel/via82c505.c --- linux-2.5.5/arch/arm/kernel/via82c505.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/kernel/via82c505.c Fri Mar 1 15:07:37 2002 @@ -74,85 +74,7 @@ via82c505_write_config_dword, }; -#ifdef CONFIG_ARCH_SHARK - -static char size_wanted; - -static int -dummy_read_config_byte(struct pci_dev *dev, int where, u8 *value) -{ - *value=0; - return PCIBIOS_SUCCESSFUL; -} - -static int -dummy_read_config_word(struct pci_dev *dev, int where, u16 *value) -{ - *value=0; - return PCIBIOS_SUCCESSFUL; -} - -static int -dummy_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - if (dev->devfn != 0) *value = 0; - else - switch(where) { - case PCI_VENDOR_ID: - *value = PCI_VENDOR_ID_INTERG | PCI_DEVICE_ID_INTERG_2010 << 16; - break; - case PCI_CLASS_REVISION: - *value = PCI_CLASS_DISPLAY_VGA << 16; - break; - case PCI_BASE_ADDRESS_0: - if (size_wanted) { - /* 0x00900000 bytes long (0xff700000) */ - *value = 0xff000000; - size_wanted = 0; - } else { - *value = FB_START; - } - break; - case PCI_INTERRUPT_LINE: - *value = 6; - break; - default: - *value = 0; - } - return PCIBIOS_SUCCESSFUL; -} - -static int -dummy_write_config_byte(struct pci_dev *dev, int where, u8 value) -{ - return PCIBIOS_SUCCESSFUL; -} - -static int -dummy_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - return PCIBIOS_SUCCESSFUL; -} - -static int -dummy_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - if ((dev->devfn == 0) && (where == PCI_BASE_ADDRESS_0) && (value == 0xffffffff)) - size_wanted = 1; - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops dummy_ops = { - dummy_read_config_byte, - dummy_read_config_word, - dummy_read_config_dword, - dummy_write_config_byte, - dummy_write_config_word, - dummy_write_config_dword, -}; -#endif - -void __init via82c505_init(void *sysdata) +void __init via82c505_preinit(void *sysdata) { struct pci_bus *bus; @@ -166,13 +88,17 @@ outb(0x93,0xA8); outb(0xd0,0xA9); - pci_scan_bus(0, &via82c505_ops, sysdata); +} + +int __init via82c505_setup(int nr, struct pci_sys_data *sys) +{ + return (nr == 0); +} + +struct pci_bus * __init via82c505_scan_bus(int nr, struct pci_sys_data *sysdata) +{ + if (nr == 0) + return pci_scan_bus(0, &via82c505_ops, sysdata); -#ifdef CONFIG_ARCH_SHARK - /* - * Initialize a fake pci-bus number 1 for the CyberPro - * on the vlbus - */ - bus = pci_scan_bus(1, &dummy_ops, sysdata); -#endif + return NULL; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/lib/Makefile linux-2.5/arch/arm/lib/Makefile --- linux-2.5.5/arch/arm/lib/Makefile Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/arm/lib/Makefile Fri Mar 1 15:07:37 2002 @@ -44,8 +44,6 @@ obj-y += io-writesl.o obj-$(CONFIG_CPU_26) += uaccess-armo.o -obj-$(CONFIG_CPU_32) += copy_page-armv3.o copy_page-armv4.o copy_page-armv4mc.o -obj-$(CONFIG_CPU_32v5) += copy_page-armv5te.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/lib/copy_page-armv3.S linux-2.5/arch/arm/lib/copy_page-armv3.S --- linux-2.5.5/arch/arm/lib/copy_page-armv3.S Wed Feb 20 02:10:54 2002 +++ linux-2.5/arch/arm/lib/copy_page-armv3.S Thu Jan 1 00:00:00 1970 @@ -1,59 +0,0 @@ -/* - * linux/arch/arm/lib/copypage.S - * - * Copyright (C) 1995-1999 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * ASM optimised string functions - */ -#include -#include -#include - - .text - .align 5 -/* - * ARMv3 optimised copy_user_page - * - * FIXME: do we need to handle cache stuff... - */ -ENTRY(armv3_copy_user_page) - stmfd sp!, {r4, lr} @ 2 - mov r2, #PAGE_SZ/64 @ 1 - ldmia r1!, {r3, r4, ip, lr} @ 4+1 -1: stmia r0!, {r3, r4, ip, lr} @ 4 - ldmia r1!, {r3, r4, ip, lr} @ 4+1 - stmia r0!, {r3, r4, ip, lr} @ 4 - ldmia r1!, {r3, r4, ip, lr} @ 4+1 - stmia r0!, {r3, r4, ip, lr} @ 4 - ldmia r1!, {r3, r4, ip, lr} @ 4 - subs r2, r2, #1 @ 1 - stmia r0!, {r3, r4, ip, lr} @ 4 - ldmneia r1!, {r3, r4, ip, lr} @ 4 - bne 1b @ 1 - LOADREGS(fd, sp!, {r4, pc}) @ 3 - - .align 5 -/* - * ARMv3 optimised clear_user_page - * - * FIXME: do we need to handle cache stuff... - */ -ENTRY(armv3_clear_user_page) - str lr, [sp, #-4]! - mov r1, #PAGE_SZ/64 @ 1 - mov r2, #0 @ 1 - mov r3, #0 @ 1 - mov ip, #0 @ 1 - mov lr, #0 @ 1 -1: stmia r0!, {r2, r3, ip, lr} @ 4 - stmia r0!, {r2, r3, ip, lr} @ 4 - stmia r0!, {r2, r3, ip, lr} @ 4 - stmia r0!, {r2, r3, ip, lr} @ 4 - subs r1, r1, #1 @ 1 - bne 1b @ 1 - ldr pc, [sp], #4 - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/lib/copy_page-armv4.S linux-2.5/arch/arm/lib/copy_page-armv4.S --- linux-2.5.5/arch/arm/lib/copy_page-armv4.S Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/lib/copy_page-armv4.S Thu Jan 1 00:00:00 1970 @@ -1,70 +0,0 @@ -/* - * linux/arch/arm/lib/copypage.S - * - * Copyright (C) 1995-1999 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * ASM optimised string functions - */ -#include -#include - - .text - .align 5 -/* - * ARMv4 optimised copy_user_page - * - * We flush the destination cache lines just before we write the data into the - * corresponding address. Since the Dcache is read-allocate, this removes the - * Dcache aliasing issue. The writes will be forwarded to the write buffer, - * and merged as appropriate. - * - * Note: We rely on all ARMv4 processors implementing the "invalidate D line" - * instruction. If your processor does not supply this, you have to write your - * own copy_user_page that does the right thing. - */ -ENTRY(armv4_copy_user_page) - stmfd sp!, {r4, lr} @ 2 - mov r2, #PAGE_SZ/64 @ 1 - ldmia r1!, {r3, r4, ip, lr} @ 4 -1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line - stmia r0!, {r3, r4, ip, lr} @ 4 - ldmia r1!, {r3, r4, ip, lr} @ 4+1 - stmia r0!, {r3, r4, ip, lr} @ 4 - ldmia r1!, {r3, r4, ip, lr} @ 4 - mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line - stmia r0!, {r3, r4, ip, lr} @ 4 - ldmia r1!, {r3, r4, ip, lr} @ 4 - subs r2, r2, #1 @ 1 - stmia r0!, {r3, r4, ip, lr} @ 4 - ldmneia r1!, {r3, r4, ip, lr} @ 4 - bne 1b @ 1 - mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB - ldmfd sp!, {r4, pc} @ 3 - - .align 5 -/* - * ARMv4 optimised clear_user_page - * - * Same story as above. - */ -ENTRY(armv4_clear_user_page) - str lr, [sp, #-4]! - mov r1, #PAGE_SZ/64 @ 1 - mov r2, #0 @ 1 - mov r3, #0 @ 1 - mov ip, #0 @ 1 - mov lr, #0 @ 1 -1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line - stmia r0!, {r2, r3, ip, lr} @ 4 - stmia r0!, {r2, r3, ip, lr} @ 4 - mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line - stmia r0!, {r2, r3, ip, lr} @ 4 - stmia r0!, {r2, r3, ip, lr} @ 4 - subs r1, r1, #1 @ 1 - bne 1b @ 1 - mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB - ldr pc, [sp], #4 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/lib/copy_page-armv4mc.S linux-2.5/arch/arm/lib/copy_page-armv4mc.S --- linux-2.5.5/arch/arm/lib/copy_page-armv4mc.S Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/lib/copy_page-armv4mc.S Thu Jan 1 00:00:00 1970 @@ -1,71 +0,0 @@ -/* - * linux/arch/arm/lib/copy_page-armv4mc.S - * - * Copyright (C) 1995-2001 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * ASM optimised string functions - */ -#include -#include - - .text - .align 5 -/* - * ARMv4 mini-dcache optimised copy_user_page - * - * We flush the destination cache lines just before we write the data into the - * corresponding address. Since the Dcache is read-allocate, this removes the - * Dcache aliasing issue. The writes will be forwarded to the write buffer, - * and merged as appropriate. - * - * Note: We rely on all ARMv4 processors implementing the "invalidate D line" - * instruction. If your processor does not supply this, you have to write your - * own copy_user_page that does the right thing. - */ -ENTRY(armv4_mc_copy_user_page) - stmfd sp!, {r4, lr} @ 2 - mov r4, r0 - mov r0, r1 - bl map_page_minicache - mov r1, #PAGE_SZ/64 @ 1 - ldmia r0!, {r2, r3, ip, lr} @ 4 -1: mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line - stmia r4!, {r2, r3, ip, lr} @ 4 - ldmia r0!, {r2, r3, ip, lr} @ 4+1 - stmia r4!, {r2, r3, ip, lr} @ 4 - ldmia r0!, {r2, r3, ip, lr} @ 4 - mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line - stmia r4!, {r2, r3, ip, lr} @ 4 - ldmia r0!, {r2, r3, ip, lr} @ 4 - subs r1, r1, #1 @ 1 - stmia r4!, {r2, r3, ip, lr} @ 4 - ldmneia r0!, {r2, r3, ip, lr} @ 4 - bne 1b @ 1 - ldmfd sp!, {r4, pc} @ 3 - - .align 5 -/* - * ARMv4 optimised clear_user_page - * - * Same story as above. - */ -ENTRY(armv4_mc_clear_user_page) - str lr, [sp, #-4]! - mov r1, #PAGE_SZ/64 @ 1 - mov r2, #0 @ 1 - mov r3, #0 @ 1 - mov ip, #0 @ 1 - mov lr, #0 @ 1 -1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line - stmia r0!, {r2, r3, ip, lr} @ 4 - stmia r0!, {r2, r3, ip, lr} @ 4 - mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line - stmia r0!, {r2, r3, ip, lr} @ 4 - stmia r0!, {r2, r3, ip, lr} @ 4 - subs r1, r1, #1 @ 1 - bne 1b @ 1 - ldr pc, [sp], #4 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/lib/copy_page-armv5te.S linux-2.5/arch/arm/lib/copy_page-armv5te.S --- linux-2.5.5/arch/arm/lib/copy_page-armv5te.S Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/lib/copy_page-armv5te.S Thu Jan 1 00:00:00 1970 @@ -1,79 +0,0 @@ -/* - * linux/arch/arm/lib/copypage-armv5te.S - * - * Copyright (C) 2001 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include - -/* - * General note: - * We don't really want write-allocate cache behaviour for these functions - * since that will just eat through 8K of the cache. - */ - - .text - .align 5 -/* - * ARMv5TE optimised copy_user_page - * r0 = destination - * r1 = source - * r2 = virtual user address of ultimate destination page - * - * The source page may have some clean entries in the cache already, but we - * can safely ignore them - break_cow() will flush them out of the cache - * if we eventually end up using our copied page. - * - * What we could do is use the mini-cache to buffer reads from the source - * page. We rely on the mini-cache being smaller than one page, so we'll - * cycle through the complete cache anyway. - */ -ENTRY(armv5te_copy_user_page) - stmfd sp!, {r4, r5, lr} - mov r5, r0 - mov r0, r1 - bl map_page_minicache - mov r1, r5 - mov lr, #PAGE_SZ/32 - -1: mov ip, r1 - ldrd r2, [r0], #8 - ldrd r4, [r0], #8 - strd r2, [r1], #8 - ldrd r2, [r0], #8 - strd r4, [r1], #8 - ldrd r4, [r0], #8 - strd r2, [r1], #8 - strd r4, [r1], #8 - mcr p15, 0, ip, c7, c10, 1 @ clean D line - mcr p15, 0, ip, c7, c6, 1 @ invalidate D line - subs lr, lr, #1 - bne 1b - - ldmfd sp!, {r4, r5, pc} - - .align 5 -/* - * ARMv5TE optimised clear_user_page - * r0 = destination - * r1 = virtual user address of ultimate destination page - */ -ENTRY(armv5te_clear_user_page) - str lr, [sp, #-4]! - mov r1, #PAGE_SZ/32 - mov r2, #0 - mov r3, #0 -1: mov ip, r0 - strd r2, [r0], #8 - strd r2, [r0], #8 - strd r2, [r0], #8 - strd r2, [r0], #8 - mcr p15, 0, ip, c7, c10, 1 @ clean D line - mcr p15, 0, ip, c7, c6, 1 @ invalidate D line - subs r1, r1, #1 - bne 1b - ldr pc, [sp], #4 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/lib/csumpartial.S linux-2.5/arch/arm/lib/csumpartial.S --- linux-2.5.5/arch/arm/lib/csumpartial.S Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/lib/csumpartial.S Tue Feb 26 21:24:48 2002 @@ -41,7 +41,7 @@ tst buf, #1 @ odd address? ldrneb td0, [buf], #1 subne len, len, #1 - adcnes sum, sum, td0, lsl #8 + adcnes sum, sum, td0, lsl #byte(1) .less4: tst len, #6 beq .less8_byte @@ -56,7 +56,11 @@ ldrb td0, [buf], #1 ldrb td3, [buf], #1 sub len, len, #2 +#ifndef __ARMEB__ orr td0, td0, td3, lsl #8 +#else + orr td0, td3, td0, lsl #8 +#endif #endif adcs sum, sum, td0 tst len, #6 @@ -64,7 +68,7 @@ .less8_byte: tst len, #1 @ odd number of bytes ldrneb td0, [buf], #1 @ include last byte - adcnes sum, sum, td0 @ update checksum + adcnes sum, sum, td0, lsl #byte(0) @ update checksum .done: adc r0, sum, #0 @ collect up the last carry ldr td0, [sp], #4 @@ -76,7 +80,7 @@ .not_aligned: tst buf, #1 @ odd address ldrneb td0, [buf], #1 @ make even subne len, len, #1 - adcnes sum, sum, td0, lsl #8 @ update checksum + adcnes sum, sum, td0, lsl #byte(1) @ update checksum tst buf, #2 @ 32-bit aligned? #ifdef __ARM_ARCH_4__ @@ -86,7 +90,11 @@ ldrneb td0, [buf], #1 ldrneb ip, [buf], #1 subne len, len, #2 +#ifndef __ARMEB__ orrne td0, td0, ip, lsl #8 +#else + orrne td0, ip, td0, lsl #8 +#endif #endif adcnes sum, sum, td0 @ update checksum mov pc, lr diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/lib/csumpartialcopygeneric.S linux-2.5/arch/arm/lib/csumpartialcopygeneric.S --- linux-2.5.5/arch/arm/lib/csumpartialcopygeneric.S Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/lib/csumpartialcopygeneric.S Tue Feb 26 21:24:48 2002 @@ -36,16 +36,16 @@ load1b ip sub len, len, #1 - adcs sum, sum, ip, lsl #8 @ update checksum + adcs sum, sum, ip, lsl #byte(1) @ update checksum strb ip, [dst], #1 tst dst, #2 moveq pc, lr @ dst is now 32bit aligned .dst_16bit: load2b r8, ip sub len, len, #2 - adcs sum, sum, r8 + adcs sum, sum, r8, lsl #byte(0) strb r8, [dst], #1 - adcs sum, sum, ip, lsl #8 + adcs sum, sum, ip, lsl #byte(1) strb ip, [dst], #1 mov pc, lr @ dst is now 32bit aligned @@ -63,16 +63,16 @@ /* Align dst */ load1b ip sub len, len, #1 - adcs sum, sum, ip, lsl #8 @ update checksum + adcs sum, sum, ip, lsl #byte(1) @ update checksum strb ip, [dst], #1 tst len, #6 beq .less8_byteonly 1: load2b r8, ip sub len, len, #2 - adcs sum, sum, r8 + adcs sum, sum, r8, lsl #byte(0) strb r8, [dst], #1 - adcs sum, sum, ip, lsl #8 + adcs sum, sum, ip, lsl #byte(1) strb ip, [dst], #1 .less8_aligned: tst len, #6 bne 1b @@ -80,7 +80,7 @@ tst len, #1 beq .done load1b r8 - adcs sum, sum, r8 @ update checksum + adcs sum, sum, r8, lsl #byte(0) @ update checksum strb r8, [dst], #1 b .done @@ -137,18 +137,19 @@ 4: ands len, len, #3 beq .done - load1l r4 + load1l r5 tst len, #2 + mov r4, r5, lsr #byte(0) beq .exit - adcs sum, sum, r4, lsl #16 + adcs sum, sum, r5, push #16 strb r4, [dst], #1 - mov r4, r4, lsr #8 + mov r4, r5, lsr #byte(1) strb r4, [dst], #1 - mov r4, r4, lsr #8 + mov r4, r5, lsr #byte(2) .exit: tst len, #1 strneb r4, [dst], #1 andne r4, r4, #255 - adcnes sum, sum, r4 + adcnes sum, sum, r4, lsl #byte(0) /* * If the dst pointer was not 16-bit aligned, we @@ -167,27 +168,27 @@ adc sum, sum, #0 @ include C from dst alignment and ip, src, #3 bic src, src, #3 - load1l r4 + load1l r5 cmp ip, #2 beq .src2_aligned bhi .src3_aligned - mov r4, r4, lsr #8 @ C = 0 + mov r4, r5, pull #8 @ C = 0 bics ip, len, #15 beq 2f 1: load4l r5, r6, r7, r8 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 - mov r6, r6, lsr #8 - orr r6, r6, r7, lsl #24 - mov r7, r7, lsr #8 - orr r7, r7, r8, lsl #24 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + mov r6, r6, pull #8 + orr r6, r6, r7, push #24 + mov r7, r7, pull #8 + orr r7, r7, r8, push #24 stmia dst!, {r4, r5, r6, r7} adcs sum, sum, r4 adcs sum, sum, r5 adcs sum, sum, r6 adcs sum, sum, r7 - mov r4, r8, lsr #8 + mov r4, r8, pull #8 sub ip, ip, #16 teq ip, #0 bne 1b @@ -196,49 +197,50 @@ tst ip, #8 beq 3f load2l r5, r6 - orr r4, r4, r5, lsl #24 - mov r5, r5, lsr #8 - orr r5, r5, r6, lsl #24 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 stmia dst!, {r4, r5} adcs sum, sum, r4 adcs sum, sum, r5 - mov r4, r6, lsr #8 + mov r4, r6, pull #8 tst ip, #4 beq 4f 3: load1l r5 - orr r4, r4, r5, lsl #24 + orr r4, r4, r5, push #24 str r4, [dst], #4 adcs sum, sum, r4 - mov r4, r5, lsr #8 4: ands len, len, #3 beq .done + mov r4, r5, lsr #byte(1) tst len, #2 beq .exit - adcs sum, sum, r4, lsl #16 + bic r5, r5, #0xff << byte(0) + adcs sum, sum, r5, push #8 strb r4, [dst], #1 - mov r4, r4, lsr #8 + mov r4, r5, lsr #byte(2) strb r4, [dst], #1 - mov r4, r4, lsr #8 + mov r4, r5, lsr #byte(3) b .exit -.src2_aligned: mov r4, r4, lsr #16 +.src2_aligned: mov r4, r5, pull #16 adds sum, sum, #0 bics ip, len, #15 beq 2f 1: load4l r5, r6, r7, r8 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 - mov r6, r6, lsr #16 - orr r6, r6, r7, lsl #16 - mov r7, r7, lsr #16 - orr r7, r7, r8, lsl #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + mov r6, r6, pull #16 + orr r6, r6, r7, push #16 + mov r7, r7, pull #16 + orr r7, r7, r8, push #16 stmia dst!, {r4, r5, r6, r7} adcs sum, sum, r4 adcs sum, sum, r5 adcs sum, sum, r6 adcs sum, sum, r7 - mov r4, r8, lsr #16 + mov r4, r8, pull #16 sub ip, ip, #16 teq ip, #0 bne 1b @@ -247,51 +249,51 @@ tst ip, #8 beq 3f load2l r5, r6 - orr r4, r4, r5, lsl #16 - mov r5, r5, lsr #16 - orr r5, r5, r6, lsl #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 stmia dst!, {r4, r5} adcs sum, sum, r4 adcs sum, sum, r5 - mov r4, r6, lsr #16 + mov r4, r6, pull #16 tst ip, #4 beq 4f 3: load1l r5 - orr r4, r4, r5, lsl #16 + orr r4, r4, r5, push #16 str r4, [dst], #4 adcs sum, sum, r4 - mov r4, r5, lsr #16 4: ands len, len, #3 beq .done + mov r4, r5, lsr #byte(2) tst len, #2 beq .exit - adcs sum, sum, r4, lsl #16 + adcs sum, sum, r5, pull #16 strb r4, [dst], #1 - mov r4, r4, lsr #8 + mov r4, r5, lsr #byte(3) strb r4, [dst], #1 tst len, #1 beq .done load1b r4 b .exit -.src3_aligned: mov r4, r4, lsr #24 +.src3_aligned: mov r4, r5, pull #24 adds sum, sum, #0 bics ip, len, #15 beq 2f 1: load4l r5, r6, r7, r8 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 - mov r6, r6, lsr #24 - orr r6, r6, r7, lsl #8 - mov r7, r7, lsr #24 - orr r7, r7, r8, lsl #8 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + mov r6, r6, pull #24 + orr r6, r6, r7, push #8 + mov r7, r7, pull #24 + orr r7, r7, r8, push #8 stmia dst!, {r4, r5, r6, r7} adcs sum, sum, r4 adcs sum, sum, r5 adcs sum, sum, r6 adcs sum, sum, r7 - mov r4, r8, lsr #24 + mov r4, r8, pull #24 sub ip, ip, #16 teq ip, #0 bne 1b @@ -300,28 +302,29 @@ tst ip, #8 beq 3f load2l r5, r6 - orr r4, r4, r5, lsl #8 - mov r5, r5, lsr #24 - orr r5, r5, r6, lsl #8 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 stmia dst!, {r4, r5} adcs sum, sum, r4 adcs sum, sum, r5 - mov r4, r6, lsr #24 + mov r4, r6, pull #24 tst ip, #4 beq 4f 3: load1l r5 - orr r4, r4, r5, lsl #8 + orr r4, r4, r5, push #8 str r4, [dst], #4 adcs sum, sum, r4 - mov r4, r5, lsr #24 4: ands len, len, #3 beq .done + mov r4, r5, lsr #byte(3) tst len, #2 beq .exit - adcs sum, sum, r4, lsl #16 + adcs sum, sum, r5, pull #24 strb r4, [dst], #1 - load1l r4 + load1l r5 + mov r4, r5, lsr #byte(0) strb r4, [dst], #1 - adcs sum, sum, r4, lsl #24 - mov r4, r4, lsr #8 + adcs sum, sum, r4, push #24 + mov r4, r5, lsr #byte(1) b .exit diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/lib/ecard.S linux-2.5/arch/arm/lib/ecard.S --- linux-2.5.5/arch/arm/lib/ecard.S Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/lib/ecard.S Fri Mar 1 15:07:37 2002 @@ -12,7 +12,7 @@ #include #include -#if defined(CONFIG_CPU_26) +#ifdef CONFIG_CPU_26 #define CPSR2SPSR(rt) #else #define CPSR2SPSR(rt) \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/lib/getuser.S linux-2.5/arch/arm/lib/getuser.S --- linux-2.5.5/arch/arm/lib/getuser.S Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/lib/getuser.S Tue Feb 26 21:24:48 2002 @@ -27,12 +27,13 @@ * Note also that it is intended that __get_user_bad is not global. */ #include +#include .global __get_user_1 __get_user_1: bic r1, sp, #0x1f00 bic r1, r1, #0x00ff - ldr r1, [r1, #TSK_ADDR_LIMIT] + ldr r1, [r1, #TI_ADDR_LIMIT] sub r1, r1, #1 cmp r0, r1 1: ldrlsbt r1, [r0] @@ -44,7 +45,7 @@ __get_user_2: bic r2, sp, #0x1f00 bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] + ldr r2, [r2, #TI_ADDR_LIMIT] sub r2, r2, #2 cmp r0, r2 2: ldrlsbt r1, [r0], #1 @@ -62,7 +63,7 @@ __get_user_4: bic r1, sp, #0x1f00 bic r1, r1, #0x00ff - ldr r1, [r1, #TSK_ADDR_LIMIT] + ldr r1, [r1, #TI_ADDR_LIMIT] sub r1, r1, #4 cmp r0, r1 4: ldrlst r1, [r0] @@ -74,7 +75,7 @@ __get_user_8: bic r2, sp, #0x1f00 bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] + ldr r2, [r2, #TI_ADDR_LIMIT] sub r2, r2, #8 cmp r0, r2 5: ldrlst r1, [r0], #4 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/lib/io-acorn.S linux-2.5/arch/arm/lib/io-acorn.S --- linux-2.5.5/arch/arm/lib/io-acorn.S Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/lib/io-acorn.S Fri Mar 1 15:07:37 2002 @@ -58,7 +58,7 @@ @ Proto : void memc_write(int register, int value); @ Returns: nothing -#if defined(CONFIG_CPU_26) +#ifdef CONFIG_CPU_26 ENTRY(memc_write) cmp r0, #7 RETINSTR(movgt,pc,lr) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/lib/putuser.S linux-2.5/arch/arm/lib/putuser.S --- linux-2.5.5/arch/arm/lib/putuser.S Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/arm/lib/putuser.S Tue Feb 26 21:24:48 2002 @@ -27,12 +27,13 @@ * Note also that it is intended that __put_user_bad is not global. */ #include +#include .global __put_user_1 __put_user_1: bic r2, sp, #0x1f00 bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] + ldr r2, [r2, #TI_ADDR_LIMIT] sub r2, r2, #1 cmp r0, r2 1: strlsbt r1, [r0] @@ -44,7 +45,7 @@ __put_user_2: bic r2, sp, #0x1f00 bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] + ldr r2, [r2, #TI_ADDR_LIMIT] sub r2, r2, #2 cmp r0, r2 movls r2, r1, lsr #8 @@ -63,7 +64,7 @@ __put_user_4: bic r2, sp, #0x1f00 bic r2, r2, #0x00ff - ldr r2, [r2, #TSK_ADDR_LIMIT] + ldr r2, [r2, #TI_ADDR_LIMIT] sub r2, r2, #4 cmp r0, r2 4: strlst r1, [r0] @@ -75,7 +76,7 @@ __put_user_8: bic ip, sp, #0x1f00 bic ip, ip, #0x00ff - ldr ip, [ip, #TSK_ADDR_LIMIT] + ldr ip, [ip, #TI_ADDR_LIMIT] sub ip, ip, #8 cmp r0, ip 5: strlst r1, [r0], #4 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/lib/strrchr.S linux-2.5/arch/arm/lib/strrchr.S --- linux-2.5.5/arch/arm/lib/strrchr.S Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/lib/strrchr.S Tue Feb 26 21:24:48 2002 @@ -18,7 +18,7 @@ mov r3, #0 1: ldrb r2, [r0], #1 teq r2, r1 - moveq r3, r0 + subeq r3, r0, #1 teq r2, #0 bne 1b mov r0, r3 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-adifcc/arch.c linux-2.5/arch/arm/mach-adifcc/arch.c --- linux-2.5.5/arch/arm/mach-adifcc/arch.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/arm/mach-adifcc/arch.c Tue Feb 26 21:24:48 2002 @@ -7,7 +7,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#include #include #include #include @@ -33,7 +33,7 @@ setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( 0xc0800000, 3*1024*1024 ); - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-adifcc/irq.c linux-2.5/arch/arm/mach-adifcc/irq.c --- linux-2.5.5/arch/arm/mach-adifcc/irq.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/arm/mach-adifcc/irq.c Tue Feb 26 21:24:48 2002 @@ -12,8 +12,6 @@ * 80200 on chip interrupts. That'll change once the hardware adds * support for PCI though. */ - -#include #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-anakin/arch.c linux-2.5/arch/arm/mach-anakin/arch.c --- linux-2.5.5/arch/arm/mach-anakin/arch.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/mach-anakin/arch.c Tue Feb 26 21:24:48 2002 @@ -30,7 +30,7 @@ fixup_anakin(struct machine_desc *desc, struct param_struct *unused, char **cmdline, struct meminfo *mi) { - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 0); setup_ramdisk(1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE); setup_initrd(0xc0800000, 4 * 1024 * 1024); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-arc/arch.c linux-2.5/arch/arm/mach-arc/arch.c --- linux-2.5.5/arch/arm/mach-arc/arch.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/arm/mach-arc/arch.c Tue Feb 26 21:24:48 2002 @@ -9,6 +9,7 @@ * * Architecture specific fixups. */ +#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-arc/dma.c linux-2.5/arch/arm/mach-arc/dma.c --- linux-2.5.5/arch/arm/mach-arc/dma.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/arm/mach-arc/dma.c Fri Mar 1 15:07:37 2002 @@ -28,6 +28,10 @@ static void arc_floppy_data_enable_dma(dmach_t channel, dma_t *dma) { DPRINTK("arc_floppy_data_enable_dma\n"); + + if (dma->using_sg) + BUG(); + switch (dma->dma_mode) { case DMA_MODE_READ: { /* read */ extern unsigned char fdc1772_dma_read, fdc1772_dma_read_end; @@ -39,7 +43,7 @@ memcpy ((void *)0x1c, (void *)&fdc1772_dma_read, &fdc1772_dma_read_end - &fdc1772_dma_read); - fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */ + fdc1772_setupdma(dma->buf.length, dma->buf.__address); /* Sets data pointer up */ enable_fiq(FIQ_FLOPPYDATA); restore_flags(flags); } @@ -54,7 +58,7 @@ clf(); memcpy ((void *)0x1c, (void *)&fdc1772_dma_write, &fdc1772_dma_write_end - &fdc1772_dma_write); - fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */ + fdc1772_setupdma(dma->buf.length, dma->buf.__address); /* Sets data pointer up */ enable_fiq(FIQ_FLOPPYDATA; restore_flags(flags); @@ -96,7 +100,7 @@ /* 10/1/1999 DAG - Presume whether there is an outstanding command? */ extern unsigned int fdc1772_fdc_int_done; - * Explicit! If the int done is 0 then 1 int to go */ + /* Explicit! If the int done is 0 then 1 int to go */ return (fdc1772_fdc_int_done==0)?1:0; } @@ -140,6 +144,9 @@ extern void floppy_fiqsetup(unsigned long len, unsigned long addr, unsigned long port); + if (dma->using_sg) + BUG(); + if (dma->dma_mode == DMA_MODE_READ) { extern unsigned char floppy_fiqin_start, floppy_fiqin_end; fiqhandler_start = &floppy_fiqin_start; @@ -155,7 +162,7 @@ } memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length); regs.ARM_r9 = dma->buf.length; - regs.ARM_r10 = (unsigned long)dma->buf.address; + regs.ARM_r10 = (unsigned long)dma->buf.__address; regs.ARM_fp = FLOPPYDMA_BASE; set_fiq_regs(®s); enable_fiq(dma->dma_irq); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-clps711x/Makefile linux-2.5/arch/arm/mach-clps711x/Makefile --- linux-2.5.5/arch/arm/mach-clps711x/Makefile Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/arm/mach-clps711x/Makefile Fri Mar 1 15:07:37 2002 @@ -21,9 +21,10 @@ obj-$(CONFIG_ARCH_AUTCPU12) += autcpu12.o obj-$(CONFIG_ARCH_CDB89712) += cdb89712.o obj-$(CONFIG_ARCH_CLEP7312) += clep7312.o -obj-$(CONFIG_ARCH_EDB7211) += edb7211-arch.o edb7211-mm.o -obj-$(CONFIG_ARCH_P720T) += p720t.o -leds-$(CONFIG_ARCH_P720T) += p720t-leds.o -obj-$(CONFIG_LEDS) += $(leds-y) +obj-$(CONFIG_ARCH_EDB7211) += edb7211-arch.o edb7211-mm.o +obj-$(CONFIG_ARCH_FORTUNET) += fortunet.o +obj-$(CONFIG_ARCH_P720T) += p720t.o +leds-$(CONFIG_ARCH_P720T) += p720t-leds.o +obj-$(CONFIG_LEDS) += $(leds-y) include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-clps711x/cdb89712.c linux-2.5/arch/arm/mach-clps711x/cdb89712.c --- linux-2.5.5/arch/arm/mach-clps711x/cdb89712.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/mach-clps711x/cdb89712.c Tue Feb 26 21:24:48 2002 @@ -17,7 +17,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-clps711x/fortunet.c linux-2.5/arch/arm/mach-clps711x/fortunet.c --- linux-2.5.5/arch/arm/mach-clps711x/fortunet.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-clps711x/fortunet.c Fri Mar 1 15:07:37 2002 @@ -0,0 +1,81 @@ +/* + * linux/arch/arm/mach-clps711x/fortunet.c + * + * Derived from linux/arch/arm/mach-integrator/arch.c + * + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern void clps711x_map_io(void); +extern void clps711x_init_irq(void); + +struct meminfo memmap = { 1, 0xC1000000, {{0xC0000000,0x01000000,0}}}; + +typedef struct tag_IMAGE_PARAMS +{ + int ramdisk_ok; + int ramdisk_address; + int ramdisk_size; + int ram_size; + int extra_param_type; + int extra_param_ptr; + int command_line; +} IMAGE_PARAMS; + +#define IMAGE_PARAMS_PHYS 0xC01F0000 + +static void __init +fortunet_fixup(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + IMAGE_PARAMS *ip; + ip = (IMAGE_PARAMS *)__phys_to_virt(IMAGE_PARAMS_PHYS); + *cmdline = (char *)__phys_to_virt(ip->command_line); +#ifdef CONFIG_BLK_DEV_INITRD + if(ip->ramdisk_ok) + { + initrd_start = __phys_to_virt(ip->ramdisk_address); + initrd_end = initrd_start + ip->ramdisk_size; + } +#endif + memmap.bank[0].size = ip->ram_size; + memmap.end = ip->ram_size+0xC0000000; + *mi = memmap; +} + +MACHINE_START(FORTUNET, "ARM-FortuNet") + MAINTAINER("FortuNet Inc.") + BOOT_MEM(0xc0000000, 0x80000000, 0xf0000000) + BOOT_PARAMS(0x00000000) + FIXUP(fortunet_fixup) + MAPIO(clps711x_map_io) + INITIRQ(clps711x_init_irq) +MACHINE_END diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-clps711x/irq.c linux-2.5/arch/arm/mach-clps711x/irq.c --- linux-2.5.5/arch/arm/mach-clps711x/irq.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/arm/mach-clps711x/irq.c Fri Mar 1 15:07:37 2002 @@ -26,7 +26,7 @@ #include -static void mask_irq_int1(unsigned int irq) +static void int1_mask(unsigned int irq) { u32 intmr1; @@ -35,7 +35,7 @@ clps_writel(intmr1, INTMR1); } -static void mask_ack_irq_int1(unsigned int irq) +static void int1_ack(unsigned int irq) { u32 intmr1; @@ -53,7 +53,7 @@ } } -static void unmask_irq_int1(unsigned int irq) +static void int1_unmask(unsigned int irq) { u32 intmr1; @@ -62,7 +62,13 @@ clps_writel(intmr1, INTMR1); } -static void mask_irq_int2(unsigned int irq) +static struct irqchip int1_chip = { + ack: int1_ack, + mask: int1_mask, + unmask: int1_unmask, +}; + +static void int2_mask(unsigned int irq) { u32 intmr2; @@ -71,7 +77,7 @@ clps_writel(intmr2, INTMR2); } -static void mask_ack_irq_int2(unsigned int irq) +static void int2_ack(unsigned int irq) { u32 intmr2; @@ -84,7 +90,7 @@ } } -static void unmask_irq_int2(unsigned int irq) +static void int2_unmask(unsigned int irq) { u32 intmr2; @@ -93,28 +99,26 @@ clps_writel(intmr2, INTMR2); } +static struct irqchip int2_chip = { + ack: int2_ack, + mask: int2_mask, + unmask: int2_unmask, +}; + void __init clps711x_init_irq(void) { unsigned int i; for (i = 0; i < NR_IRQS; i++) { if (INT1_IRQS & (1 << i)) { - irq_desc[i].valid = 1; - irq_desc[i].probe_ok = 1; - irq_desc[i].mask_ack = (INT1_ACK_IRQS & (1 << i)) ? - mask_ack_irq_int1 : - mask_irq_int1; - irq_desc[i].mask = mask_irq_int1; - irq_desc[i].unmask = unmask_irq_int1; + set_irq_handler(i, do_level_IRQ); + set_irq_chip(i, &int1_chip); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); } if (INT2_IRQS & (1 << i)) { - irq_desc[i].valid = 1; - irq_desc[i].probe_ok = 1; - irq_desc[i].mask_ack = (INT2_ACK_IRQS & (1 << i)) ? - mask_ack_irq_int2 : - mask_irq_int2; - irq_desc[i].mask = mask_irq_int2; - irq_desc[i].unmask = unmask_irq_int2; + set_irq_handler(i, do_level_IRQ); + set_irq_chip(i, &int2_chip); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-ebsa110/core.c linux-2.5/arch/arm/mach-ebsa110/core.c --- linux-2.5.5/arch/arm/mach-ebsa110/core.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/arm/mach-ebsa110/core.c Fri Mar 1 15:07:37 2002 @@ -39,27 +39,31 @@ { __raw_writeb(1 << irq, IRQ_MSET); } + +static struct irqchip ebsa110_irq_chip = { + ack: ebsa110_mask_irq, + mask: ebsa110_mask_irq, + unmask: ebsa110_unmask_irq, +}; static void __init ebsa110_init_irq(void) { unsigned long flags; - int irq; + unsigned int irq; - save_flags_cli (flags); + local_irq_save(flags); __raw_writeb(0xff, IRQ_MCLR); __raw_writeb(0x55, IRQ_MSET); __raw_writeb(0x00, IRQ_MSET); if (__raw_readb(IRQ_MASK) != 0x55) while (1); __raw_writeb(0xff, IRQ_MCLR); /* clear all interrupt enables */ - restore_flags (flags); + local_irq_restore(flags); for (irq = 0; irq < NR_IRQS; irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = ebsa110_mask_irq; - irq_desc[irq].mask = ebsa110_mask_irq; - irq_desc[irq].unmask = ebsa110_unmask_irq; + set_irq_chip(irq, &ebsa110_irq_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-epxa10db/arch.c linux-2.5/arch/arm/mach-epxa10db/arch.c --- linux-2.5.5/arch/arm/mach-epxa10db/arch.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/mach-epxa10db/arch.c Tue Feb 26 21:24:48 2002 @@ -18,7 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include @@ -46,7 +45,7 @@ mi->bank[0].node = 0; /* - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd(0xc0200000, 6*1024*1024); */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-epxa10db/irq.c linux-2.5/arch/arm/mach-epxa10db/irq.c --- linux-2.5.5/arch/arm/mach-epxa10db/irq.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/arm/mach-epxa10db/irq.c Fri Mar 1 15:07:37 2002 @@ -18,28 +18,44 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include +#include #include #include -#include #include #include #include -static void mask_irq(unsigned int irq) +static void epxa_mask_irq(unsigned int irq) { - __raw_writel(1 << irq, INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE))); + writel(1 << irq, INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE))); } -static void unmask_irq(unsigned int irq) +static void epxa_unmask_irq(unsigned int irq) { - __raw_writel(1 << irq, INT_MS(IO_ADDRESS(EXC_INT_CTRL00_BASE))); + writel(1 << irq, INT_MS(IO_ADDRESS(EXC_INT_CTRL00_BASE))); } + +static struct irqchip epxa_irq_chip = { + ack: epxa_mask_irq, + mask: epxa_mask_irq, + unmask: epxa_unmask_irq, +}; + +static struct resource irq_resource = { + name: "irq_handler", + start: IO_ADDRESS(EXC_INT_CTRL00_BASE), + end: IO_ADDRESS(INT_PRIORITY_FC(EXC_INT_CTRL00_BASE))+4, +}; + void __init epxa10db_init_irq(void) { unsigned int i; + request_resource(&iomem_resource, &irq_resource); + /* * This bit sets up the interrupt controller using * the 6 PLD interrupts mode (the default) each @@ -49,22 +65,15 @@ * on the contents of your PLD */ - __raw_writel(3,INT_MODE(IO_ADDRESS(EXC_INT_CTRL00_BASE))); + writel(3,INT_MODE(IO_ADDRESS(EXC_INT_CTRL00_BASE))); for (i = 0; i < NR_IRQS; i++){ - __raw_writel(i+1, INT_PRIORITY_P0(IO_ADDRESS(EXC_INT_CTRL00_BASE)) + (4*i)); - } - - - for (i = 0; i < NR_IRQS; i++) { - - irq_desc[i].valid = 1; - irq_desc[i].probe_ok = 1; - irq_desc[i].mask_ack = mask_irq; - irq_desc[i].mask = mask_irq; - irq_desc[i].unmask = unmask_irq; + writel(i+1, INT_PRIORITY_P0(IO_ADDRESS(EXC_INT_CTRL00_BASE)) + (4*i)); + set_irq_chip(i,&epxa_irq_chip); + set_irq_handler(i,do_level_IRQ); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); } - /* Disable all interrupt */ - __raw_writel(-1,INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE))); + /* Disable all interrupts */ + writel(-1,INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE))); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-footbridge/Makefile linux-2.5/arch/arm/mach-footbridge/Makefile --- linux-2.5.5/arch/arm/mach-footbridge/Makefile Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/arm/mach-footbridge/Makefile Fri Mar 1 15:07:37 2002 @@ -11,7 +11,7 @@ # Object file lists. -obj-y := arch.o dc21285.o dma.o irq.o mm.o +obj-y := arch.o dc21285.o dma.o irq.o isa-irq.o mm.o obj-m := obj-n := obj- := diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-footbridge/irq.c linux-2.5/arch/arm/mach-footbridge/irq.c --- linux-2.5.5/arch/arm/mach-footbridge/irq.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/mach-footbridge/irq.c Fri Mar 1 15:07:37 2002 @@ -27,6 +27,8 @@ #include #include +extern void __init isa_init_irq(unsigned int irq); + /* * Footbridge IRQ translation table * Converts from our IRQ numbers into FootBridge masks @@ -64,9 +66,15 @@ *CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(irq)]; } +static struct irqchip fb_chip = { + ack: fb_mask_irq, + mask: fb_mask_irq, + unmask: fb_unmask_irq, +}; + static void __init __fb_init_irq(void) { - int irq; + unsigned int irq; /* * setup DC21285 IRQs @@ -75,128 +83,9 @@ *CSR_FIQ_DISABLE = -1; for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = fb_mask_irq; - irq_desc[irq].mask = fb_mask_irq; - irq_desc[irq].unmask = fb_unmask_irq; - } -} - -extern int isa_irq; - -static void isa_mask_pic_lo_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); -} - -static void isa_mask_ack_pic_lo_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); - outb(0x20, PIC_LO); -} - -static void isa_unmask_pic_lo_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO); -} - -static void isa_mask_pic_hi_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); -} - -static void isa_mask_ack_pic_hi_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); - outb(0x62, PIC_LO); - outb(0x20, PIC_HI); -} - -static void isa_unmask_pic_hi_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq & 7); - - outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI); -} - -static void no_action(int irq, void *dev_id, struct pt_regs *regs) -{ -} - -static struct irqaction irq_cascade = { handler: no_action, name: "cascade", }; -static struct resource pic1_resource = { "pic1", 0x20, 0x3f }; -static struct resource pic2_resource = { "pic2", 0xa0, 0xbf }; - -static void __init isa_init_irq(int irq) -{ - /* - * Setup, and then probe for an ISA PIC - * If the PIC is not there, then we - * ignore the PIC. - */ - outb(0x11, PIC_LO); - outb(_ISA_IRQ(0), PIC_MASK_LO); /* IRQ number */ - outb(0x04, PIC_MASK_LO); /* Slave on Ch2 */ - outb(0x01, PIC_MASK_LO); /* x86 */ - outb(0xf5, PIC_MASK_LO); /* pattern: 11110101 */ - - outb(0x11, PIC_HI); - outb(_ISA_IRQ(8), PIC_MASK_HI); /* IRQ number */ - outb(0x02, PIC_MASK_HI); /* Slave on Ch1 */ - outb(0x01, PIC_MASK_HI); /* x86 */ - outb(0xfa, PIC_MASK_HI); /* pattern: 11111010 */ - - outb(0x0b, PIC_LO); - outb(0x0b, PIC_HI); - - if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) { - outb(0xff, PIC_MASK_LO);/* mask all IRQs */ - outb(0xff, PIC_MASK_HI);/* mask all IRQs */ - isa_irq = irq; - } else - isa_irq = -1; - - if (isa_irq != -1) { - for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = isa_mask_ack_pic_lo_irq; - irq_desc[irq].mask = isa_mask_pic_lo_irq; - irq_desc[irq].unmask = isa_unmask_pic_lo_irq; - } - - for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = isa_mask_ack_pic_hi_irq; - irq_desc[irq].mask = isa_mask_pic_hi_irq; - irq_desc[irq].unmask = isa_unmask_pic_hi_irq; - } - - request_resource(&ioport_resource, &pic1_resource); - request_resource(&ioport_resource, &pic2_resource); - setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade); - setup_arm_irq(isa_irq, &irq_cascade); - - /* - * On the NetWinder, don't automatically - * enable ISA IRQ11 when it is requested. - * There appears to be a missing pull-up - * resistor on this line. - */ - if (machine_is_netwinder()) - irq_desc[_ISA_IRQ(11)].noautoenable = 1; + set_irq_chip(irq, &fb_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-footbridge/isa-irq.c linux-2.5/arch/arm/mach-footbridge/isa-irq.c --- linux-2.5.5/arch/arm/mach-footbridge/isa-irq.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-footbridge/isa-irq.c Fri Mar 1 15:07:37 2002 @@ -0,0 +1,170 @@ +/* + * linux/arch/arm/mach-footbridge/irq.c + * + * Copyright (C) 1996-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 22-Aug-1998 RMK Restructured IRQ routines + * 03-Sep-1998 PJB Merged CATS support + * 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder + * 26-Jan-1999 PJB Don't use IACK on CATS + * 16-Mar-1999 RMK Added autodetect of ISA PICs + */ +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +static void isa_mask_pic_lo_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); +} + +static void isa_ack_pic_lo_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO); + outb(0x20, PIC_LO); +} + +static void isa_unmask_pic_lo_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO); +} + +static struct irqchip isa_lo_chip = { + ack: isa_ack_pic_lo_irq, + mask: isa_mask_pic_lo_irq, + unmask: isa_unmask_pic_lo_irq, +}; + +static void isa_mask_pic_hi_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); +} + +static void isa_ack_pic_hi_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI); + outb(0x62, PIC_LO); + outb(0x20, PIC_HI); +} + +static void isa_unmask_pic_hi_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq & 7); + + outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI); +} + +static struct irqchip isa_hi_chip = { + ack: isa_ack_pic_hi_irq, + mask: isa_mask_pic_hi_irq, + unmask: isa_unmask_pic_hi_irq, +}; + +static void no_action(int irq, void *dev_id, struct pt_regs *regs) +{ +} + +static void +isa_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + unsigned int isa_irq = *(unsigned char *)PCIIACK_BASE; + + if (isa_irq < _ISA_IRQ(0) || isa_irq >= _ISA_IRQ(16)) { + do_bad_IRQ(isa_irq, desc, regs); + return; + } + + desc = irq_desc + isa_irq; + desc->handle(isa_irq, desc, regs); +} + +static struct irqaction irq_cascade = { handler: no_action, name: "cascade", }; +static struct resource pic1_resource = { "pic1", 0x20, 0x3f }; +static struct resource pic2_resource = { "pic2", 0xa0, 0xbf }; + +void __init isa_init_irq(unsigned int irq) +{ + /* + * Setup, and then probe for an ISA PIC + * If the PIC is not there, then we + * ignore the PIC. + */ + outb(0x11, PIC_LO); + outb(_ISA_IRQ(0), PIC_MASK_LO); /* IRQ number */ + outb(0x04, PIC_MASK_LO); /* Slave on Ch2 */ + outb(0x01, PIC_MASK_LO); /* x86 */ + outb(0xf5, PIC_MASK_LO); /* pattern: 11110101 */ + + outb(0x11, PIC_HI); + outb(_ISA_IRQ(8), PIC_MASK_HI); /* IRQ number */ + outb(0x02, PIC_MASK_HI); /* Slave on Ch1 */ + outb(0x01, PIC_MASK_HI); /* x86 */ + outb(0xfa, PIC_MASK_HI); /* pattern: 11111010 */ + + outb(0x0b, PIC_LO); + outb(0x0b, PIC_HI); + + if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) { + outb(0xff, PIC_MASK_LO);/* mask all IRQs */ + outb(0xff, PIC_MASK_HI);/* mask all IRQs */ + } else { + printk(KERN_INFO "IRQ: ISA PIC not found\n"); + irq = -1; + } + + if (irq != -1) { + for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) { + set_irq_chip(irq, &isa_lo_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + + for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) { + set_irq_chip(irq, &isa_hi_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + + request_resource(&ioport_resource, &pic1_resource); + request_resource(&ioport_resource, &pic2_resource); + setup_irq(IRQ_ISA_CASCADE, &irq_cascade); + + set_irq_chained_handler(irq, isa_irq_handler); + + /* + * On the NetWinder, don't automatically + * enable ISA IRQ11 when it is requested. + * There appears to be a missing pull-up + * resistor on this line. + */ + if (machine_is_netwinder()) + set_irq_flags(_ISA_IRQ(11), IRQF_VALID | + IRQF_PROBE | IRQF_NOAUTOEN); + } +} + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-footbridge/netwinder-hw.c linux-2.5/arch/arm/mach-footbridge/netwinder-hw.c --- linux-2.5.5/arch/arm/mach-footbridge/netwinder-hw.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/arm/mach-footbridge/netwinder-hw.c Fri Mar 1 15:07:37 2002 @@ -320,7 +320,7 @@ */ spin_lock_irqsave(&gpio_lock, flags); gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN); - spin_unlock_irqrestore(&gpio_loc, flags); + spin_unlock_irqrestore(&gpio_lock, flags); } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-ftvpci/core.c linux-2.5/arch/arm/mach-ftvpci/core.c --- linux-2.5.5/arch/arm/mach-ftvpci/core.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/mach-ftvpci/core.c Tue Feb 26 21:24:48 2002 @@ -8,7 +8,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#include #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-integrator/irq.c linux-2.5/arch/arm/mach-integrator/irq.c --- linux-2.5.5/arch/arm/mach-integrator/irq.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/arm/mach-integrator/irq.c Fri Mar 1 15:07:37 2002 @@ -46,21 +46,17 @@ { __raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET); } + +static struct irqchip sc_chip = { + ack: sc_mask_irq, + mask: sc_mask_irq, + unmask: sc_unmask_irq, +}; void __init integrator_init_irq(void) { unsigned int i; - for (i = 0; i < NR_IRQS; i++) { - if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) { - irq_desc[i].valid = 1; - irq_desc[i].probe_ok = 1; - irq_desc[i].mask_ack = sc_mask_irq; - irq_desc[i].mask = sc_mask_irq; - irq_desc[i].unmask = sc_unmask_irq; - } - } - /* Disable all interrupts initially. */ /* Do the core module ones */ __raw_writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); @@ -68,4 +64,12 @@ /* do the header card stuff next */ __raw_writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); __raw_writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); + + for (i = 0; i < NR_IRQS; i++) { + if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) { + set_irq_chip(i, &sc_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + } + } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-integrator/pci.c linux-2.5/arch/arm/mach-integrator/pci.c --- linux-2.5.5/arch/arm/mach-integrator/pci.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/mach-integrator/pci.c Fri Mar 1 15:07:37 2002 @@ -110,7 +110,6 @@ return irq_tab[intnr]; } -extern void pci_v3_setup_resources(struct resource **res); extern void pci_v3_init(void *); struct hw_pci integrator_pci __initdata = { @@ -118,6 +117,7 @@ swizzle: integrator_swizzle, map_irq: integrator_map_irq, setup: pci_v3_setup, + nr_controllers: 1, scan: pci_v3_scan_bus, preinit: pci_v3_preinit, postinit: pci_v3_postinit, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-integrator/pci_v3.c linux-2.5/arch/arm/mach-integrator/pci_v3.c --- linux-2.5.5/arch/arm/mach-integrator/pci_v3.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/mach-integrator/pci_v3.c Fri Mar 1 15:07:37 2002 @@ -20,6 +20,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include @@ -37,8 +38,6 @@ #include -int setup_arm_irq(int irq, struct irqaction * new); - /* * The V3 PCI interface chip in Integrator provides several windows from * local bus memory into the PCI memory areas. Unfortunately, there @@ -413,12 +412,19 @@ flags: IORESOURCE_MEM | IORESOURCE_PREFETCH, }; -static void __init pci_v3_setup_resources(struct resource **resource) +static int __init pci_v3_setup_resources(struct resource **resource) { - if (request_resource(&iomem_resource, &non_mem)) - printk("PCI: unable to allocate non-prefetchable memory region\n"); - if (request_resource(&iomem_resource, &pre_mem)) - printk("PCI: unable to allocate prefetchable memory region\n"); + if (request_resource(&iomem_resource, &non_mem)) { + printk(KERN_ERR "PCI: unable to allocate non-prefetchable " + "memory region\n"); + return -EBUSY; + } + if (request_resource(&iomem_resource, &pre_mem)) { + release_resource(&non_mem); + printk(KERN_ERR "PCI: unable to allocate prefetchable " + "memory region\n"); + return -EBUSY; + } /* * bus->resource[0] is the IO resource for this bus @@ -428,6 +434,8 @@ resource[0] = &ioport_resource; resource[1] = &non_mem; resource[2] = &pre_mem; + + return 0; } /* @@ -443,13 +451,15 @@ { unsigned long pc = instruction_pointer(regs); unsigned long instr = *(unsigned long *)pc; -// char buf[128]; +#if 0 + char buf[128]; -// sprintf(buf, "V3 fault: address=0x%08lx, pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", -// addr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255, -// v3_readb(V3_LB_ISTAT)); -// printk("%s", buf); -// printascii(buf); + sprintf(buf, "V3 fault: address=0x%08lx, pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", + addr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255, + v3_readb(V3_LB_ISTAT)); + printk(KERN_DEBUG "%s", buf); + printascii(buf); +#endif v3_writeb(V3_LB_ISTAT, 0); __raw_writel(3, SC_PCI); @@ -513,28 +523,21 @@ #endif } -static struct irqaction v3_int = { - name: "V3", - handler: v3_irq, -}; - -static struct irqaction v3_int2 = { - name: "V3TM", - handler: v3_irq, -}; - extern int (*external_fault)(unsigned long addr, struct pt_regs *regs); -int pci_v3_setup(int nr, struct pci_sys_data *sys) +int __init pci_v3_setup(int nr, struct pci_sys_data *sys) { - if (nr) - pci_v3_setup_resources(sys->resource); - return nr ? 0 : 1; + int ret = 0; + + if (nr == 0) + ret = pci_v3_setup_resources(sys->resource); + + return ret; } struct pci_bus *pci_v3_scan_bus(int nr, struct pci_sys_data *sys) { - return pci_scan_bus(sys->busnr, &pci_v3_ops, sys); + return pci_scan_bus(sys->busnr, &pci_v3_ops, sys); } /* @@ -545,6 +548,7 @@ { unsigned long flags; unsigned int temp; + int ret; /* * Hook in our fault handler for PCI errors @@ -592,7 +596,7 @@ temp |= V3_PCI_CFG_M_IO_REG_DIS | V3_PCI_CFG_M_IO_DIS; v3_writew(V3_PCI_CFG, temp); - printk("FIFO_CFG: %04x FIFO_PRIO: %04x\n", + printk(KERN_DEBUG "FIFO_CFG: %04x FIFO_PRIO: %04x\n", v3_readw(V3_FIFO_CFG), v3_readw(V3_FIFO_PRIORITY)); /* @@ -619,7 +623,10 @@ /* * Grab the PCI error interrupt. */ - setup_arm_irq(IRQ_V3INT, &v3_int); + ret = request_irq(IRQ_V3INT, v3_irq, 0, "V3", NULL); + if (ret) + printk(KERN_ERR "PCI: unable to grab PCI error " + "interrupt: %d\n", ret); spin_unlock_irqrestore(&v3_lock, flags); } @@ -627,6 +634,7 @@ void __init pci_v3_postinit(void) { unsigned int pci_cmd; + int ret; pci_cmd = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; @@ -636,5 +644,10 @@ v3_writeb(V3_LB_ISTAT, ~0x40); v3_writeb(V3_LB_IMASK, 0x68); -// setup_arm_irq(IRQ_LBUSTIMEOUT, &v3_int2); +#if 0 + ret = request_irq(IRQ_LBUSTIMEOUT, lb_timeout, 0, "bus timeout", NULL); + if (ret) + printk(KERN_ERR "PCI: unable to grab local bus timeout " + "interrupt: %d\n", ret); +#endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-iop310/arch.c linux-2.5/arch/arm/mach-iop310/arch.c --- linux-2.5.5/arch/arm/mach-iop310/arch.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/mach-iop310/arch.c Tue Feb 26 21:24:48 2002 @@ -9,7 +9,7 @@ * published by the Free Software Foundation. * */ - +#include #include #include #include @@ -44,7 +44,7 @@ #elif defined(CONFIG_BLK_DEV_INITRD) setup_ramdisk( 1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE ); setup_initrd( 0xc0800000, 4*1024*1024 ); - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */ + ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 0); /* /dev/ram */ #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-iop310/iop310-irq.c linux-2.5/arch/arm/mach-iop310/iop310-irq.c --- linux-2.5.5/arch/arm/mach-iop310/iop310-irq.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/arm/mach-iop310/iop310-irq.c Fri Mar 1 15:07:37 2002 @@ -13,8 +13,6 @@ * Added IOP310 chipset and IQ80310 board demuxing, masking code. - DS * */ - -#include #include #include #include @@ -31,40 +29,46 @@ extern void do_IRQ(int, struct pt_regs *); -u32 iop310_mask = 0; +static u32 iop310_mask /* = 0 */; -static void -iop310_irq_mask (unsigned int irq) +static void iop310_irq_mask (unsigned int irq) { - iop310_mask |= (1 << (irq - IOP310_IRQ_OFS)); + iop310_mask ++; /* * No mask bits on the 80312, so we have to * mask everything from the outside! */ - xs80200_irq_mask(IRQ_XS80200_EXTIRQ); + if (iop310_mask == 1) { + disable_irq(IRQ_XS80200_EXTIRQ); + irq_desc[IRQ_XS80200_EXTIRQ].chip->mask(IRQ_XS80200_EXTIRQ); + } } -static void -iop310_irq_unmask (unsigned int irq) +static void iop310_irq_unmask (unsigned int irq) { - iop310_mask &= ~(1 << (irq - IOP310_IRQ_OFS)); + if (iop310_mask) + iop310_mask --; /* * Check if all 80312 sources are unmasked now */ - if(!iop310_mask) - { - xs80200_irq_unmask(IRQ_XS80200_EXTIRQ); - - } + if (iop310_mask == 0) + enable_irq(IRQ_XS80200_EXTIRQ); } -void iop310_irq_demux(int irq, void *dev_id, - struct pt_regs *regs) +struct irqchip ext_chip = { + ack: iop310_irq_mask, + mask: iop310_irq_mask, + unmask: iop310_irq_unmask, +}; + +void +iop310_irq_demux(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) { u32 fiq1isr = *((volatile u32*)IOP310_FIQ1ISR); u32 fiq2isr = *((volatile u32*)IOP310_FIQ2ISR); + struct irqdesc *d; unsigned int irqno = 0; if(fiq1isr) @@ -88,22 +92,22 @@ irqno = IRQ_IOP310_MU; } - do_IRQ(irqno, regs); + if (irqno) { + d = irq_desc + irqno; + d->handle(irqno, d, regs); + } } void __init iop310_init_irq(void) { - int i; + unsigned int i; for(i = IOP310_IRQ_OFS; i < NR_IOP310_IRQS; i++) { - irq_desc[i].valid = 1; - irq_desc[i].probe_ok = 1; - irq_desc[i].mask_ack = iop310_irq_mask; - irq_desc[i].mask = iop310_irq_mask; - irq_desc[i].unmask = iop310_irq_unmask; + set_irq_chip(i, &ext_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); } xs80200_init_irq(); } - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-iop310/iop310-pci.c linux-2.5/arch/arm/mach-iop310/iop310-pci.c --- linux-2.5.5/arch/arm/mach-iop310/iop310-pci.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/arm/mach-iop310/iop310-pci.c Fri Mar 1 15:07:37 2002 @@ -52,7 +52,7 @@ #ifdef DEBUG #define DBG(x...) printk(x) #else -#define DBG(x...) +#define DBG(x...) do { } while (0) #endif extern int (*external_fault)(unsigned long, struct pt_regs *); @@ -247,7 +247,8 @@ *IOP310_SATUISR = uisr & 0x0000069f; ret = 1; } -//if (ret) printk("ERROR (%08lx %08lx)", usr, uisr); + if (ret) + DBG("ERROR (%08lx %08lx)", usr, uisr); return ret; } @@ -256,16 +257,19 @@ { int ret; u8 val; -//printk("rdb: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where); + + DBG("rdb: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where); *IOP310_SOCCAR = iop310_cfg_address(dev, where); val = (*IOP310_SOCCDR) >> ((where & 3) * 8); __asm__ __volatile__("nop; nop; nop; nop"); -//printk(">= %08lx ", val); + + DBG(">= %08lx ", val); ret = iop310_sec_pci_status(); if (ret) val = 0xff; -//printk("\n"); + DBG("\n"); *p = val; return PCIBIOS_SUCCESSFUL; @@ -276,16 +280,19 @@ { int ret; u16 val; -//printk("rdw: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where); + + DBG("rdw: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where); *IOP310_SOCCAR = iop310_cfg_address(dev, where); val = (*IOP310_SOCCDR) >> ((where & 3) * 8); __asm__ __volatile__("nop; nop; nop; nop"); -//printk(">= %08lx ", val); + + DBG(">= %08lx ", val); ret = iop310_sec_pci_status(); if (ret) val = 0xffff; -//printk("\n"); + DBG("\n"); *p = val; return PCIBIOS_SUCCESSFUL; @@ -296,16 +303,19 @@ { int ret; u32 val; -//printk("rdl: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where); + + DBG("rdl: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where); *IOP310_SOCCAR = iop310_cfg_address(dev, where); val = *IOP310_SOCCDR; __asm__ __volatile__("nop; nop; nop; nop"); -//printk(">= %08lx ", val); + + DBG(">= %08lx ", val); ret = iop310_sec_pci_status(); if (ret) val = 0xffffffff; -//printk("\n"); + DBG("\n"); *p = val; return PCIBIOS_SUCCESSFUL; @@ -316,12 +326,15 @@ { int ret; u32 val; -//printk("wrb: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where); + + DBG("wrb: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where); *IOP310_SOCCAR = iop310_cfg_address(dev, where); val = *IOP310_SOCCDR; __asm__ __volatile__("nop; nop; nop; nop"); -//printk("<= %08lx", v); + + DBG("<= %08lx", v); ret = iop310_sec_pci_status(); if (ret == 0) { where = (where & 3) * 8; @@ -329,7 +342,7 @@ val |= v << where; *IOP310_SOCCDR = val; } -//printk("\n"); + DBG("\n"); return PCIBIOS_SUCCESSFUL; } @@ -338,12 +351,15 @@ { int ret; u32 val; -//printk("wrw: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where); + + DBG("wrw: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where); *IOP310_SOCCAR = iop310_cfg_address(dev, where); val = *IOP310_SOCCDR; __asm__ __volatile__("nop; nop; nop; nop"); -//printk("<= %08lx", v); + + DBG("<= %08lx", v); ret = iop310_sec_pci_status(); if (ret == 0) { where = (where & 2) * 8; @@ -351,18 +367,20 @@ val |= v << where; *IOP310_SOCCDR = val; } -//printk("\n"); + DBG("\n"); return PCIBIOS_SUCCESSFUL; } static int iop310_sec_wr_cfg_dword(struct pci_dev *dev, int where, u32 v) { -//printk("wrl: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where); + DBG("wrl: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where); *IOP310_SOCCAR = iop310_cfg_address(dev, where); *IOP310_SOCCDR = v; __asm__ __volatile__("nop; nop; nop; nop"); -//printk("<= %08lx\n", v); + + DBG("<= %08lx\n", v); return PCIBIOS_SUCCESSFUL; } @@ -381,8 +399,8 @@ */ int iop310_pci_abort_handler(unsigned long addr, struct pt_regs *regs) { -// printk("PCI abort: address = %08x PC = %08x LR = %08lx\n", -// addr, regs->ARM_pc, regs->ARM_lr); + DBG("PCI abort: address = %08x PC = %08x LR = %08lx\n", + addr, regs->ARM_pc, regs->ARM_lr); return 0; } @@ -443,11 +461,11 @@ case 1: res[0].start = IOP310_PCISEC_LOWER_IO + 0x6e000000; res[0].end = IOP310_PCISEC_LOWER_IO + 0x6e00ffff; - res[0].name = "PCI IO Primary"; + res[0].name = "PCI IO Secondary"; res[1].start = IOP310_PCISEC_LOWER_MEM; res[1].end = IOP310_PCISEC_LOWER_MEM + IOP310_PCI_WINDOW_SIZE; - res[1].name = "PCI Memory Primary"; + res[1].name = "PCI Memory Secondary"; break; } @@ -465,18 +483,17 @@ void iop310_init(void) { DBG("PCI: Intel 80312 PCI-to-PCI init code.\n"); - DBG(" ATU secondary: IOP310_SOMWVR=0x%04x, IOP310_SOIOWVR=0x%04x\n", - *IOP310_SOMWVR, - *IOP310_SOIOWVR); - DBG(" ATU secondary: IOP310_ATUCR=0x%08x\n", *IOP310_ATUCR); - DBG(" ATU secondary: IOP310_SIABAR=0x%08x IOP310_SIALR=0x%08x IOP310_SIATVR=%08x\n", *IOP310_SIABAR, *IOP310_SIALR, *IOP310_SIATVR); - - DBG(" ATU primary: IOP310_POMWVR=0x%04x, IOP310_POIOWVR=0x%04x\n", - *IOP310_POMWVR, - *IOP310_POIOWVR); - DBG(" ATU secondary: IOP310_PIABAR=0x%08x IOP310_PIALR=0x%08x IOP310_PIATVR=%08x\n", *IOP310_PIABAR, *IOP310_PIALR, *IOP310_PIATVR); - - DBG(" P2P: IOP310_PCR=0x%04x IOP310_BCR=0x%04x IOP310_EBCR=0x%04x\n", *IOP310_PCR, *IOP310_BCR, *IOP310_EBCR); + DBG(" ATU secondary: ATUCR =0x%08x\n", *IOP310_ATUCR); + DBG(" ATU secondary: SOMWVR=0x%08x SOIOWVR=0x%08x\n", + *IOP310_SOMWVR, *IOP310_SOIOWVR); + DBG(" ATU secondary: SIABAR=0x%08x SIALR =0x%08x SIATVR=%08x\n", + *IOP310_SIABAR, *IOP310_SIALR, *IOP310_SIATVR); + DBG(" ATU primary: POMWVR=0x%08x POIOWVR=0x%08x\n", + *IOP310_POMWVR, *IOP310_POIOWVR); + DBG(" ATU primary: PIABAR=0x%08x PIALR =0x%08x PIATVR=%08x\n", + *IOP310_PIABAR, *IOP310_PIALR, *IOP310_PIATVR); + DBG(" P2P: PCR=0x%04x BCR=0x%04x EBCR=0x%04x\n", + *IOP310_PCR, *IOP310_BCR, *IOP310_EBCR); /* * Windows have to be carefully opened via a nice set of calls @@ -495,6 +512,5 @@ *IOP310_PCR &= 0xfff8; external_fault = iop310_pci_abort_handler; - } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-iop310/iq80310-irq.c linux-2.5/arch/arm/mach-iop310/iq80310-irq.c --- linux-2.5.5/arch/arm/mach-iop310/iq80310-irq.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/mach-iop310/iq80310-irq.c Fri Mar 1 15:07:37 2002 @@ -14,8 +14,6 @@ * Moved demux from asm to C - DS * Fixes for various revision boards - DS */ - -#include #include #include #include @@ -29,121 +27,86 @@ #include -extern void xs80200_irq_mask(unsigned int); -extern void xs80200_irq_unmask(unsigned int); -extern void xs80200_init_irq(void); +extern void iop310_init_irq(void); +extern void iop310_irq_demux(unsigned int, struct irqdesc *, struct pt_regs *); -extern void do_IRQ(int, struct pt_regs *); +static void iq80310_irq_mask(unsigned int irq) +{ + *(volatile char *)IQ80310_INT_MASK |= (1 << (irq - IQ80310_IRQ_OFS)); +} -extern u32 iop310_mask; +static void iq80310_irq_unmask(unsigned int irq) +{ + *(volatile char *)IQ80310_INT_MASK &= ~(1 << (irq - IQ80310_IRQ_OFS)); +} -extern void iop310_irq_demux(int, void *, struct pt_regs *); +static struct irqchip iq80310_irq_chip = { + ack: iq80310_irq_mask, + mask: iq80310_irq_mask, + unmask: iq80310_irq_unmask, +}; -extern int iop310_init_irq(void); +extern struct irqchip ext_chip; static void -iq80310_irq_mask (unsigned int irq) +iq80310_cpld_irq_handler(unsigned int irq, struct irqdesc *desc, + struct pt_regs *regs) { - volatile char *mask = (volatile char *)IQ80310_INT_MASK; - *mask |= (1 << (irq - IQ80310_IRQ_OFS)); + unsigned int irq_stat = *(volatile u8*)IQ80310_INT_STAT; + unsigned int irq_mask = *(volatile u8*)IQ80310_INT_MASK; + unsigned int i, handled = 0; + struct irqdesc *d; + + desc->chip->ack(irq); /* - * There's no mask for PCI INT A-C, so we just mask out all - * external interrupts on the CPU. - * - * We set a bit of the iop310 mask so that the iop310_irq_mask - * function does not unmask EXTINT + * Mask out the interrupts which aren't enabled. */ - if (irq > IRQ_IQ80310_INTD) - { - xs80200_irq_mask(IRQ_XS80200_EXTIRQ); - iop310_mask |= (0x80000000 >> (irq - IRQ_IQ80310_INTD)); - } -} - -static void -iq80310_irq_unmask (unsigned int irq) -{ - volatile char *mask = (volatile char *)IQ80310_INT_MASK; - *mask &= ~(1 << (irq - IQ80310_IRQ_OFS)); + irq_stat &= 0x1f & ~irq_mask; /* - * See comment above + * Test each IQ80310 CPLD interrupt */ - if (irq > IRQ_IQ80310_INTD) - { - xs80200_irq_unmask(IRQ_XS80200_EXTIRQ); - iop310_mask &= ~((0x80000000 >> (irq - IRQ_IQ80310_INTD))); - } -} - -static void iq80310_cpld_irq_demux(int irq, void *dev_id, - struct pt_regs *regs) -{ - u8 irq_stat = *((volatile u8*)IQ80310_INT_STAT); - u8 irq_mask = *((volatile u8*)IQ80310_INT_MASK); - unsigned int irqno = 0xffffffff; - - // Needed? If IRQ is masked, it shouldn't get through... - irq_stat &= ~irq_mask; - - - if(irq_stat & 0x01) - irqno = IRQ_IQ80310_TIMER; - else if(irq_stat & 0x02) - irqno = IRQ_IQ80310_I82559; - else if(irq_stat & 0x04) - irqno = IRQ_IQ80310_UART1; - else if(irq_stat & 0x08) - irqno = IRQ_IQ80310_UART2; - else if(irq_stat & 0x10) - irqno = IRQ_IQ80310_INTD; - else if(system_rev) - { - irq_stat = *((volatile u8*)IQ80310_PCI_INT_STAT) & 0xf; - - if(irq_stat & 0x1) - irqno = IRQ_IQ80310_INTA; - else if(irq_stat & 0x2) - irqno = IRQ_IQ80310_INTB; - else if(irq_stat & 0x4) - irqno = IRQ_IQ80310_INTC; - } - else /* Running on a REV D.1 or older, assume PCI INTA */ - irqno = IRQ_IQ80310_INTA; + for (i = IRQ_IQ80310_TIMER, d = irq_desc + IRQ_IQ80310_TIMER; + irq_stat; i++, d++, irq_stat >>= 1) + if (irq_stat & 1) { + d->handle(i, d, regs); + handled++; + } /* - * If we didn't read a CPLD interrupt, we assume it's from - * a device on the chipset itself. + * If running on a board later than REV D.1, we can + * decode the PCI interrupt status. */ - if(irqno == 0xffffffff) - { - iop310_irq_demux(irq, dev_id, regs); - return; + if (system_rev) { + irq_stat = *((volatile u8*)IQ80310_PCI_INT_STAT) & 7; + + for (i = IRQ_IQ80310_INTA, d = irq_desc + IRQ_IQ80310_INTA; + irq_stat; i++, d++, irq_stat >>= 1) + if (irq_stat & 0x1) { + d->handle(i, d, regs); + handled++; + } } /* - * If on a REV D.1 or lower board, we just assumed INTA since - * PCI is not routed, and it may actually be an on-chip interrupt. + * If on a REV D.1 or lower board, we just assumed INTA + * since PCI is not routed, and it may actually be an + * on-chip interrupt. * - * Note that we're giving on-chip interrupts slightly higher - * priority than PCI by handling them first. + * Note that we're giving on-chip interrupts slightly + * higher priority than PCI by handling them first. + * + * On boards later than REV D.1, if we didn't read a + * CPLD interrupt, we assume it's from a device on the + * chipset itself. */ - if(irqno == IRQ_IQ80310_INTA && !system_rev) - iop310_irq_demux(irq, dev_id, regs); + if (system_rev == 0 || handled == 0) + iop310_irq_demux(irq, desc, regs); - do_IRQ(irqno, regs); + desc->chip->unmask(irq); } - -static struct irqaction iq80310_cpld_irq = { - name: "CPLD_IRQ", - handler: iq80310_cpld_irq_demux, - flags: SA_INTERRUPT -}; - -extern int setup_arm_irq(int, struct irqaction *); - void __init iq80310_init_irq(void) { volatile char *mask = (volatile char *)IQ80310_INT_MASK; @@ -156,17 +119,26 @@ */ *IOP310_PIRSR = 0xff; - for (i = IQ80310_IRQ_OFS; i < NR_IRQS; i++) { - irq_desc[i].valid = 1; - irq_desc[i].probe_ok = 1; - irq_desc[i].mask_ack = iq80310_irq_mask; - irq_desc[i].mask = iq80310_irq_mask; - irq_desc[i].unmask = iq80310_irq_unmask; + /* + * Setup the IRQs in the FE820000/FE860000 registers + */ + for (i = IQ80310_IRQ_OFS; i <= IRQ_IQ80310_INTD; i++) { + set_irq_chip(i, &iq80310_irq_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + } + + /* + * Setup the PCI IRQs + */ + for (i = IRQ_IQ80310_INTA; i < IRQ_IQ80310_INTC; i++) { + set_irq_chip(i, &ext_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID); } *mask = 0xff; /* mask all sources */ - setup_arm_irq(IRQ_XS80200_EXTIRQ, &iq80310_cpld_irq); - /* enable only external IRQ in the INTCTL for now */ - asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (1<<1)); + set_irq_chained_handler(IRQ_XS80200_EXTIRQ, + &iq80310_cpld_irq_handler); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-iop310/iq80310-time.c linux-2.5/arch/arm/mach-iop310/iq80310-time.c --- linux-2.5.5/arch/arm/mach-iop310/iq80310-time.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/arm/mach-iop310/iq80310-time.c Fri Mar 1 15:07:37 2002 @@ -11,25 +11,21 @@ * published by the Free Software Foundation. * */ - - -#include #include #include #include #include #include #include +#include #include -#include +#include #include #include - -#include -#include - +#include #include +#include static void iq80310_write_timer (u_long val) { @@ -109,14 +105,12 @@ }; -extern int setup_arm_irq(int, struct irqaction*); - void __init time_init(void) { volatile u_char *timer_en = (volatile u_char *)IQ80310_TIMER_EN; gettimeoffset = iq80310_gettimeoffset; - setup_arm_irq(IRQ_IQ80310_TIMER, &timer_irq); + setup_irq(IRQ_IQ80310_TIMER, &timer_irq); *timer_en = 0; iq80310_write_timer(LATCH); *timer_en |= 2; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-iop310/mm.c linux-2.5/arch/arm/mach-iop310/mm.c --- linux-2.5.5/arch/arm/mach-iop310/mm.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/mach-iop310/mm.c Tue Feb 26 21:24:48 2002 @@ -13,7 +13,7 @@ * option) any later version. * */ - +#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-iop310/xs80200-irq.c linux-2.5/arch/arm/mach-iop310/xs80200-irq.c --- linux-2.5.5/arch/arm/mach-iop310/xs80200-irq.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/arm/mach-iop310/xs80200-irq.c Fri Mar 1 15:07:37 2002 @@ -10,8 +10,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - -#include #include #include #include @@ -22,45 +20,47 @@ #include -void -xs80200_irq_mask (unsigned int irq) +static void xs80200_irq_mask (unsigned int irq) { - long INTCTL; - asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); + unsigned long intctl; + asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (intctl)); switch (irq) { - case IRQ_XS80200_BCU: INTCTL &= ~(1<<3); break; - case IRQ_XS80200_PMU: INTCTL &= ~(1<<2); break; - case IRQ_XS80200_EXTIRQ: INTCTL &= ~(1<<1); break; - case IRQ_XS80200_EXTFIQ: INTCTL &= ~(1<<0); break; + case IRQ_XS80200_BCU: intctl &= ~(1<<3); break; + case IRQ_XS80200_PMU: intctl &= ~(1<<2); break; + case IRQ_XS80200_EXTIRQ: intctl &= ~(1<<1); break; + case IRQ_XS80200_EXTFIQ: intctl &= ~(1<<0); break; } - asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); + asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (intctl)); } -void -xs80200_irq_unmask (unsigned int irq) +static void xs80200_irq_unmask (unsigned int irq) { - long INTCTL; - asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL)); + unsigned long intctl; + asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (intctl)); switch (irq) { - case IRQ_XS80200_BCU: INTCTL |= (1<<3); break; - case IRQ_XS80200_PMU: INTCTL |= (1<<2); break; - case IRQ_XS80200_EXTIRQ: INTCTL |= (1<<1); break; - case IRQ_XS80200_EXTFIQ: INTCTL |= (1<<0); break; + case IRQ_XS80200_BCU: intctl |= (1<<3); break; + case IRQ_XS80200_PMU: intctl |= (1<<2); break; + case IRQ_XS80200_EXTIRQ: intctl |= (1<<1); break; + case IRQ_XS80200_EXTFIQ: intctl |= (1<<0); break; } - asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL)); + asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (intctl)); } +static struct irqchip xs80200_chip = { + ack: xs80200_irq_mask, + mask: xs80200_irq_mask, + unmask: xs80200_irq_unmask, +}; + void __init xs80200_init_irq(void) { - int i; + unsigned int i; + + asm("mcr p13, 0, %0, c0, c0, 0" : : "r" (0)); for (i = 0; i < NR_XS80200_IRQS; i++) { - irq_desc[i].valid = 1; - irq_desc[i].probe_ok = 0; - irq_desc[i].mask_ack = xs80200_irq_mask; - irq_desc[i].mask = xs80200_irq_mask; - irq_desc[i].unmask = xs80200_irq_unmask; + set_irq_chip(i, &xs80200_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID); } } - - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-l7200/core.c linux-2.5/arch/arm/mach-l7200/core.c --- linux-2.5.5/arch/arm/mach-l7200/core.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/arm/mach-l7200/core.c Tue Feb 26 21:24:48 2002 @@ -5,6 +5,7 @@ * * Extra MM routines for L7200 architecture */ +#include #include #include @@ -90,7 +91,7 @@ mi->bank[0].size = (32*1024*1024); mi->bank[0].node = 0; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE); setup_initrd( __phys_to_virt(0xf1000000), 0x005dac7b); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-rpc/dma.c linux-2.5/arch/arm/mach-rpc/dma.c --- linux-2.5.5/arch/arm/mach-rpc/dma.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/arm/mach-rpc/dma.c Fri Mar 1 15:07:37 2002 @@ -188,7 +188,7 @@ */ if (!dma->using_sg) { dma->buf.dma_address = pci_map_single(NULL, - dma->buf.address, dma->buf.length, + dma->buf.__address, dma->buf.length, dma->dma_mode == DMA_MODE_READ ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); } @@ -275,6 +275,9 @@ unsigned int fiqhandler_length; struct pt_regs regs; + if (dma->using_sg) + BUG(); + if (dma->dma_mode == DMA_MODE_READ) { extern unsigned char floppy_fiqin_start, floppy_fiqin_end; fiqhandler_start = &floppy_fiqin_start; @@ -286,7 +289,7 @@ } regs.ARM_r9 = dma->buf.length; - regs.ARM_r10 = (unsigned long)dma->buf.address; + regs.ARM_r10 = (unsigned long)dma->buf.__address; regs.ARM_fp = FLOPPYDMA_BASE; if (claim_fiq(&fh)) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-rpc/irq.c linux-2.5/arch/arm/mach-rpc/irq.c --- linux-2.5.5/arch/arm/mach-rpc/irq.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/arm/mach-rpc/irq.c Fri Mar 1 15:07:37 2002 @@ -5,7 +5,7 @@ #include #include -static void rpc_mask_irq_ack_a(unsigned int irq) +static void iomd_ack_irq_a(unsigned int irq) { unsigned int val, mask; @@ -15,7 +15,7 @@ iomd_writeb(mask, IOMD_IRQCLRA); } -static void rpc_mask_irq_a(unsigned int irq) +static void iomd_mask_irq_a(unsigned int irq) { unsigned int val, mask; @@ -24,7 +24,7 @@ iomd_writeb(val & ~mask, IOMD_IRQMASKA); } -static void rpc_unmask_irq_a(unsigned int irq) +static void iomd_unmask_irq_a(unsigned int irq) { unsigned int val, mask; @@ -33,7 +33,13 @@ iomd_writeb(val | mask, IOMD_IRQMASKA); } -static void rpc_mask_irq_b(unsigned int irq) +static struct irqchip iomd_a_chip = { + ack: iomd_ack_irq_a, + mask: iomd_mask_irq_a, + unmask: iomd_unmask_irq_a, +}; + +static void iomd_mask_irq_b(unsigned int irq) { unsigned int val, mask; @@ -42,7 +48,7 @@ iomd_writeb(val & ~mask, IOMD_IRQMASKB); } -static void rpc_unmask_irq_b(unsigned int irq) +static void iomd_unmask_irq_b(unsigned int irq) { unsigned int val, mask; @@ -51,7 +57,13 @@ iomd_writeb(val | mask, IOMD_IRQMASKB); } -static void rpc_mask_irq_dma(unsigned int irq) +static struct irqchip iomd_b_chip = { + ack: iomd_mask_irq_b, + mask: iomd_mask_irq_b, + unmask: iomd_unmask_irq_b, +}; + +static void iomd_mask_irq_dma(unsigned int irq) { unsigned int val, mask; @@ -60,7 +72,7 @@ iomd_writeb(val & ~mask, IOMD_DMAMASK); } -static void rpc_unmask_irq_dma(unsigned int irq) +static void iomd_unmask_irq_dma(unsigned int irq) { unsigned int val, mask; @@ -69,7 +81,13 @@ iomd_writeb(val | mask, IOMD_DMAMASK); } -static void rpc_mask_irq_fiq(unsigned int irq) +static struct irqchip iomd_dma_chip = { + ack: iomd_mask_irq_dma, + mask: iomd_mask_irq_dma, + unmask: iomd_unmask_irq_dma, +}; + +static void iomd_mask_irq_fiq(unsigned int irq) { unsigned int val, mask; @@ -78,7 +96,7 @@ iomd_writeb(val & ~mask, IOMD_FIQMASK); } -static void rpc_unmask_irq_fiq(unsigned int irq) +static void iomd_unmask_irq_fiq(unsigned int irq) { unsigned int val, mask; @@ -87,9 +105,15 @@ iomd_writeb(val | mask, IOMD_FIQMASK); } +static struct irqchip iomd_fiq_chip = { + ack: iomd_mask_irq_fiq, + mask: iomd_mask_irq_fiq, + unmask: iomd_unmask_irq_fiq, +}; + void __init rpc_init_irq(void) { - int irq; + unsigned int irq, flags; iomd_writeb(0, IOMD_IRQMASKA); iomd_writeb(0, IOMD_IRQMASKB); @@ -97,45 +121,40 @@ iomd_writeb(0, IOMD_DMAMASK); for (irq = 0; irq < NR_IRQS; irq++) { + flags = IRQF_VALID; + + if (irq <= 6 || (irq >= 9 && irq <= 15)) + flags |= IRQF_PROBE; + + if (irq == 21 || (irq >= 16 && irq <= 19) || + irq == IRQ_KEYBOARDTX) + flags |= IRQF_NOAUTOEN; + switch (irq) { - case 0 ... 6: - irq_desc[irq].probe_ok = 1; - case 7: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = rpc_mask_irq_ack_a; - irq_desc[irq].mask = rpc_mask_irq_a; - irq_desc[irq].unmask = rpc_unmask_irq_a; + case 0 ... 7: + set_irq_chip(irq, &iomd_a_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, flags); break; - case 9 ... 15: - irq_desc[irq].probe_ok = 1; - case 8: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = rpc_mask_irq_b; - irq_desc[irq].mask = rpc_mask_irq_b; - irq_desc[irq].unmask = rpc_unmask_irq_b; + case 8 ... 15: + set_irq_chip(irq, &iomd_b_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, flags); break; - case 16 ... 19: - case 21: - irq_desc[irq].noautoenable = 1; - case 20: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = rpc_mask_irq_dma; - irq_desc[irq].mask = rpc_mask_irq_dma; - irq_desc[irq].unmask = rpc_unmask_irq_dma; + case 16 ... 21: + set_irq_chip(irq, &iomd_dma_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, flags); break; case 64 ... 71: - irq_desc[irq].valid = 1; - irq_desc[irq].mask_ack = rpc_mask_irq_fiq; - irq_desc[irq].mask = rpc_mask_irq_fiq; - irq_desc[irq].unmask = rpc_unmask_irq_fiq; + set_irq_chip(irq, &iomd_fiq_chip); + set_irq_flags(irq, IRQF_VALID); break; } } - - irq_desc[IRQ_KEYBOARDTX].noautoenable = 1; init_FIQ(); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/adsbitsy.c linux-2.5/arch/arm/mach-sa1100/adsbitsy.c --- linux-2.5.5/arch/arm/mach-sa1100/adsbitsy.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/mach-sa1100/adsbitsy.c Tue Feb 26 21:24:48 2002 @@ -26,8 +26,6 @@ #include #include -#include - #include "generic.h" #include "sa1111.h" @@ -120,7 +118,7 @@ SET_BANK( 0, 0xc0000000, 32*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/assabet.c linux-2.5/arch/arm/mach-sa1100/assabet.c --- linux-2.5.5/arch/arm/mach-sa1100/assabet.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/mach-sa1100/assabet.c Fri Mar 1 15:07:37 2002 @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -89,7 +90,7 @@ /* * Set the IRQ edges */ - set_GPIO_IRQ_edge(GPIO_GPIO23, GPIO_RISING_EDGE); /* UCB1300 */ + set_irq_type(IRQ_GPIO23, IRQT_RISING); /* UCB1300 */ sa1100fb_lcd_power = assabet_lcd_power; sa1100fb_backlight_power = assabet_backlight_power; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/badge4.c linux-2.5/arch/arm/mach-sa1100/badge4.c --- linux-2.5.5/arch/arm/mach-sa1100/badge4.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-sa1100/badge4.c Fri Mar 1 15:07:37 2002 @@ -0,0 +1,211 @@ +/* + * linux/arch/arm/mach-sa1100/badge4.c + * + * BadgePAD 4 specific initialization + * + * Tim Connors + * Christopher Hoover + * + * Copyright (C) 2002 Hewlett-Packard Company + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "generic.h" +#include "sa1111.h" + +static int __init badge4_sa1111_init(void) +{ + int ret; + + /* + * Ensure that the memory bus request/grant signals are setup, + * and the grant is held in its inactive state + */ + sa1110_mb_disable(); + + /* + * Probe for SA1111. + */ + ret = sa1111_probe(BADGE4_SA1111_BASE); + if (ret < 0) + return ret; + + /* + * We found it. Wake the chip up. + */ + sa1111_wake(); + + /* + * The SDRAM configuration of the SA1110 and the SA1111 must + * match. This is very important to ensure that SA1111 accesses + * don't corrupt the SDRAM. Note that this ungates the SA1111's + * MBGNT signal, so we must have called sa1110_mb_disable() + * beforehand. + */ + sa1111_configure_smc(1, + FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), + FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); + + /* + * We only need to turn on DCLK whenever we want to use the + * DMA. It can otherwise be held firmly in the off position. + */ + SKPCR |= SKPCR_DCLKEN; + + /* + * Enable the SA1110 memory bus request and grant signals. + */ + sa1110_mb_enable(); + + sa1111_init_irq(BADGE4_IRQ_GPIO_SA1111); + + return 0; +} + +static int __init badge4_init(void) +{ + int ret; + + if (!machine_is_badge4()) + return -ENODEV; + + ret = badge4_sa1111_init(); + if (ret < 0) + printk(KERN_ERR __FUNCTION__ + ": SA-1111 initialization failed (%d)\n", ret); + + /* N.B, according to rmk this is the singular place that GPDR + should be set */ + + /* Video expansion */ + GPCR = (BADGE4_GPIO_INT_VID | BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 | + BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 | BADGE4_GPIO_LGP6 | + BADGE4_GPIO_LGP7 | BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 | + BADGE4_GPIO_GPA_VID | BADGE4_GPIO_GPB_VID | + BADGE4_GPIO_GPC_VID); + GPDR |= (BADGE4_GPIO_INT_VID | BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 | + BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 | BADGE4_GPIO_LGP6 | + BADGE4_GPIO_LGP7 | BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 | + BADGE4_GPIO_GPA_VID | BADGE4_GPIO_GPB_VID | + BADGE4_GPIO_GPC_VID); + + /* SDRAM SPD i2c */ + GPCR = (BADGE4_GPIO_SDSDA | BADGE4_GPIO_SDSCL); + GPDR |= (BADGE4_GPIO_SDSDA | BADGE4_GPIO_SDSCL); + + /* uart */ + GPCR = (BADGE4_GPIO_UART_HS1 | BADGE4_GPIO_UART_HS2); + GPDR |= (BADGE4_GPIO_UART_HS1 | BADGE4_GPIO_UART_HS2); + + /* drives CPLD muxsel0 input */ + GPCR = BADGE4_GPIO_MUXSEL0; + GPDR |= BADGE4_GPIO_MUXSEL0; + + /* test points */ + GPCR = (BADGE4_GPIO_TESTPT_J7 | BADGE4_GPIO_TESTPT_J6 | + BADGE4_GPIO_TESTPT_J5); + GPDR |= (BADGE4_GPIO_TESTPT_J7 | BADGE4_GPIO_TESTPT_J6 | + BADGE4_GPIO_TESTPT_J5); + + /* drives CPLD sdram type inputs; this shouldn't be needed; + bootloader left it this way. */ + GPDR |= (BADGE4_GPIO_SDTYP0 | BADGE4_GPIO_SDTYP1); + + /* 5V supply rail. */ + GPCR = BADGE4_GPIO_PCMEN5V; /* initially off */ + GPDR |= BADGE4_GPIO_PCMEN5V; + + /* drives SA1111 reset pin; this shouldn't be needed; + bootloader left it this way. */ + GPSR = BADGE4_GPIO_SA1111_NRST; + GPDR |= BADGE4_GPIO_SA1111_NRST; + + return 0; +} + +__initcall(badge4_init); + + +static unsigned badge4_5V_bitmap = 0; + +void badge4_set_5V(unsigned subsystem, int on) +{ + unsigned long flags; + unsigned old_5V_bitmap; + + local_irq_save(flags); + + old_5V_bitmap = badge4_5V_bitmap; + + if (on) { + badge4_5V_bitmap |= subsystem; + } else { + badge4_5V_bitmap &= ~subsystem; + } + + /* detect on->off and off->on transitions */ + if ((!old_5V_bitmap) && (badge4_5V_bitmap)) { + /* was off, now on */ + printk(KERN_INFO __FUNCTION__ ": enabling 5V supply rail\n"); + GPSR = BADGE4_GPIO_PCMEN5V; + } else if ((old_5V_bitmap) && (!badge4_5V_bitmap)) { + /* was on, now off */ + printk(KERN_INFO __FUNCTION__ ": disabling 5V supply rail\n"); + GPCR = BADGE4_GPIO_PCMEN5V; + } + + local_irq_restore(flags); +} +EXPORT_SYMBOL(badge4_set_5V); + + +static void __init +fixup_badge4(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + /* nothing needed here */ +} + +static struct map_desc badge4_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + {0xf1000000, 0x08000000, 0x00100000, DOMAIN_IO, 1,1,0,0},/* SRAM bank 1 */ + {0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 1,1,0,0},/* SRAM bank 2 */ + {0xf4000000, 0x48000000, 0x00100000, DOMAIN_IO, 1,1,0,0},/* SA-1111 */ + LAST_DESC +}; + +static void __init badge4_map_io(void) +{ + sa1100_map_io(); + iotable_init(badge4_io_desc); + + sa1100_register_uart(0, 3); + sa1100_register_uart(1, 1); +} + +MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_badge4) + MAPIO(badge4_map_io) + INITIRQ(sa1100_init_irq) +MACHINE_END diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/brutus.c linux-2.5/arch/arm/mach-sa1100/brutus.c --- linux-2.5.5/arch/arm/mach-sa1100/brutus.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/mach-sa1100/brutus.c Tue Feb 26 21:24:48 2002 @@ -32,7 +32,7 @@ SET_BANK( 3, 0xd8000000, 4*1024*1024 ); mi->nr_banks = 4; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 ); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/cerf.c linux-2.5/arch/arm/mach-sa1100/cerf.c --- linux-2.5.5/arch/arm/mach-sa1100/cerf.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/arm/mach-sa1100/cerf.c Fri Mar 1 15:07:37 2002 @@ -1,11 +1,12 @@ /* * linux/arch/arm/mach-sa1100/cerf.c */ - +#include #include #include #include +#include #include #include @@ -26,12 +27,12 @@ */ #ifdef CONFIG_SA1100_CERF_CPLD /* PDA Full serial port */ - set_GPIO_IRQ_edge(GPIO_GPIO3, GPIO_RISING_EDGE); + set_irq_type(IRQ_GPIO3, IRQT_RISING); /* PDA Bluetooth */ - set_GPIO_IRQ_edge(GPIO_GPIO2, GPIO_RISING_EDGE); + set_irq_type(IRQ_GPIO2, IRQT_RISING); #endif /* CONFIG_SA1100_CERF_CPLD */ - set_GPIO_IRQ_edge(GPIO_UCB1200_IRQ, GPIO_RISING_EDGE); + set_irq_type(IRQ_GPIO_UCB1200_IRQ, IRQT_RISING); } static void __init @@ -55,7 +56,7 @@ #error "Undefined memory size for Cerfboard." #endif -// ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); +// ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); // setup_ramdisk(1, 0, 0, 8192); // // Save 2Meg for RAMDisk // setup_initrd(0xc0500000, 3*1024*1024); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/empeg.c linux-2.5/arch/arm/mach-sa1100/empeg.c --- linux-2.5.5/arch/arm/mach-sa1100/empeg.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/arm/mach-sa1100/empeg.c Tue Feb 26 21:24:48 2002 @@ -24,7 +24,7 @@ SET_BANK( 1, 0xc8000000, 4*1024*1024 ); mi->nr_banks = 2; - ROOT_DEV = MKDEV( 3, 1 ); /* /dev/hda1 */ + ROOT_DEV = mk_kdev( 3, 1 ); /* /dev/hda1 */ setup_ramdisk( 1, 0, 0, 4096 ); setup_initrd( 0xd0000000+((1024-320)*1024), (320*1024) ); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/flexanet.c linux-2.5/arch/arm/mach-sa1100/flexanet.c --- linux-2.5.5/arch/arm/mach-sa1100/flexanet.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/arm/mach-sa1100/flexanet.c Tue Feb 26 21:24:48 2002 @@ -9,8 +9,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - -#include #include #include #include @@ -113,7 +111,6 @@ * * get_mctrl : set state of modem control lines * set_mctrl : set the modem control lines - * enable_ms : enable modem-status interrupts * pm : power-management. Turn device on/off. * */ @@ -121,7 +118,6 @@ { set_mctrl : flexanet_set_mctrl, get_mctrl : flexanet_get_mctrl, - enable_ms : NULL, pm : NULL, }; @@ -168,7 +164,7 @@ mi->nr_banks = 1; /* setup ramdisk */ - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( 0xc0800000, 3*1024*1024 ); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/freebird.c linux-2.5/arch/arm/mach-sa1100/freebird.c --- linux-2.5.5/arch/arm/mach-sa1100/freebird.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/mach-sa1100/freebird.c Tue Feb 26 21:24:48 2002 @@ -58,7 +58,7 @@ #ifdef CONFIG_SA1100_FREEBIRD_OLD SET_BANK( 0, 0xc0000000, 32*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0 ,0 , 8192 ); setup_initrd( 0xc0800000, 3*1024*1024 ); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/graphicsclient.c linux-2.5/arch/arm/mach-sa1100/graphicsclient.c --- linux-2.5.5/arch/arm/mach-sa1100/graphicsclient.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/arm/mach-sa1100/graphicsclient.c Fri Mar 1 15:07:37 2002 @@ -25,8 +25,6 @@ #include #include -#include - #include "generic.h" @@ -68,6 +66,12 @@ ADS_INT_EN1 |= (1 << (irq - ADS_EXT_IRQ(0))); } +static struct irqchip ADS0_chip = { + ack: ADS_mask_and_ack_irq0, + mask: ADS_mask_irq0, + unmask: ADS_unmask_irq0, +}; + static void ADS_mask_and_ack_irq1(unsigned int irq) { int mask = (1 << (irq - ADS_EXT_IRQ(8))); @@ -85,9 +89,15 @@ ADS_INT_EN2 |= (1 << (irq - ADS_EXT_IRQ(8))); } +static struct irqchip ADS1_chip = { + ack: ADS_mask_and_ack_irq1, + mask: ADS_mask_irq1, + unmask: ADS_unmask_irq1, +}; + static void __init graphicsclient_init_irq(void) { - int irq; + unsigned int irq; /* First the standard SA1100 IRQs */ sa1100_init_irq(); @@ -100,18 +110,14 @@ ADS_INT_ST2 = 0xff; for (irq = ADS_EXT_IRQ(0); irq <= ADS_EXT_IRQ(7); irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = ADS_mask_and_ack_irq0; - irq_desc[irq].mask = ADS_mask_irq0; - irq_desc[irq].unmask = ADS_unmask_irq0; + set_irq_chip(irq, &ADS0_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } for (irq = ADS_EXT_IRQ(8); irq <= ADS_EXT_IRQ(15); irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = ADS_mask_and_ack_irq1; - irq_desc[irq].mask = ADS_mask_irq1; - irq_desc[irq].unmask = ADS_unmask_irq1; + set_irq_chip(irq, &ADS1_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE); setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq ); @@ -130,7 +136,7 @@ SET_BANK( 1, 0xc8000000, 16*1024*1024 ); mi->nr_banks = 2; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); } @@ -148,6 +154,8 @@ { GPIO_GC_UART2_CTS, 0, NULL,NULL } }; +#error Old code. Someone needs to decide what to do with this +#if 0 static void graphicsclient_cts_intr(int irq, void *dev_id, struct pt_regs *regs) { @@ -243,6 +251,7 @@ return 0; } +#endif static u_int graphicsclient_get_mctrl(struct uart_port *port) { @@ -296,8 +305,6 @@ } static struct sa1100_port_fns graphicsclient_port_fns __initdata = { - open: graphicsclient_uart_open, - close: graphicsclient_uart_close, get_mctrl: graphicsclient_get_mctrl, set_mctrl: graphicsclient_set_mctrl, pm: graphicsclient_uart_pm, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/graphicsmaster.c linux-2.5/arch/arm/mach-sa1100/graphicsmaster.c --- linux-2.5.5/arch/arm/mach-sa1100/graphicsmaster.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/arm/mach-sa1100/graphicsmaster.c Fri Mar 1 15:07:37 2002 @@ -23,8 +23,6 @@ #include #include -#include - #include "generic.h" #include "sa1111.h" @@ -130,6 +128,12 @@ ADS_INT_EN1 |= (1 << (irq - ADS_EXT_IRQ(0))); } +static struct irqchip ADS0_chip = { + ack: ADS_mask_and_ack_irq0, + mask: ADS_mask_irq0, + unmask: ADS_unmask_irq0, +}; + static void ADS_mask_and_ack_irq1(unsigned int irq) { int mask = (1 << (irq - ADS_EXT_IRQ(8))); @@ -147,9 +151,15 @@ ADS_INT_EN2 |= (1 << (irq - ADS_EXT_IRQ(8))); } +static struct irqchip ADS1_chip = { + ack: ADS_mask_irq1, + mask: ADS_mask_irq1, + unmask: ADS_mask_irq1, +}; + static void __init graphicsmaster_init_irq(void) { - int irq; + unsigned int irq; /* First the standard SA1100 IRQs */ sa1100_init_irq(); @@ -162,18 +172,14 @@ ADS_INT_ST2 = 0xff; for (irq = ADS_EXT_IRQ(0); irq <= ADS_EXT_IRQ(7); irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = ADS_mask_and_ack_irq0; - irq_desc[irq].mask = ADS_mask_irq0; - irq_desc[irq].unmask = ADS_unmask_irq0; + set_irq_chip(irq, &ADS0_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_PROBE | IRQF_VALID); } for (irq = ADS_EXT_IRQ(8); irq <= ADS_EXT_IRQ(15); irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = ADS_mask_and_ack_irq1; - irq_desc[irq].mask = ADS_mask_irq1; - irq_desc[irq].unmask = ADS_unmask_irq1; + set_irq_chip(irq, &ADS1_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_PROBE | IRQF_VALID); } set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE); setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq ); @@ -193,7 +199,7 @@ SET_BANK( 1, 0xc8000000, 16*1024*1024 ); mi->nr_banks = 2; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); } @@ -206,6 +212,8 @@ LAST_DESC }; +#error Old code. Someone needs to decide what to do about this. +#if 0 static int graphicsmaster_uart_open(struct uart_port *port, struct uart_info *info) { int ret = 0; @@ -226,6 +234,7 @@ } return ret; } +#endif static u_int graphicsmaster_get_mctrl(struct uart_port *port) { @@ -279,7 +288,6 @@ } static struct sa1100_port_fns graphicsmaster_port_fns __initdata = { - open: graphicsmaster_uart_open, get_mctrl: graphicsmaster_get_mctrl, set_mctrl: graphicsmaster_set_mctrl, pm: graphicsmaster_uart_pm, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/h3600.c linux-2.5/arch/arm/mach-sa1100/h3600.c --- linux-2.5.5/arch/arm/mach-sa1100/h3600.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/arm/mach-sa1100/h3600.c Fri Mar 1 15:07:37 2002 @@ -19,8 +19,6 @@ * and abstracted EGPIO interface. * */ - -#include #include #include #include @@ -61,7 +59,7 @@ | GPIO_H3100_IR_ON \ | GPIO_H3100_IR_FSEL) -void h3100_init_egpio( void ) +static void h3100_init_egpio( void ) { GPDR |= H3100_DIRECT_EGPIO; GPCR = H3100_DIRECT_EGPIO; /* Initially all off */ @@ -74,7 +72,7 @@ H3600_EGPIO = h3600_egpio; } -void h3100_control_egpio( enum ipaq_egpio_type x, int setp ) +static void h3100_control_egpio( enum ipaq_egpio_type x, int setp ) { unsigned int egpio = 0; long gpio = 0; @@ -140,7 +138,7 @@ */ } -unsigned long h3100_read_egpio( void ) +static unsigned long h3100_read_egpio( void ) { return h3600_egpio; } @@ -156,13 +154,13 @@ /************************* H3600 *************************/ -void h3600_init_egpio( void ) +static void h3600_init_egpio( void ) { h3600_egpio = EGPIO_H3600_RS232_ON; H3600_EGPIO = h3600_egpio; } -void h3600_control_egpio( enum ipaq_egpio_type x, int setp ) +static void h3600_control_egpio( enum ipaq_egpio_type x, int setp ) { unsigned int egpio = 0; unsigned long flags; @@ -219,7 +217,7 @@ local_irq_restore(flags); } -unsigned long h3600_read_egpio( void ) +static unsigned long h3600_read_egpio( void ) { return h3600_egpio; } @@ -239,7 +237,7 @@ static unsigned int h3800_asic1_gpio; static unsigned int h3800_asic2_gpio; -void h3800_init_egpio(void) +static void h3800_init_egpio(void) { /* Set up ASIC #1 */ H3800_ASIC1_GPIO_Direction = ASIC1_OUTPUTS; /* All outputs */ @@ -273,7 +271,7 @@ H3800_ASIC1_FlashWP_VPP_ON = 0; } -void h3800_control_egpio( enum ipaq_egpio_type x, int setp ) +static void h3800_control_egpio( enum ipaq_egpio_type x, int setp ) { unsigned int set_asic1_egpio = 0; unsigned int clear_asic1_egpio = 0; @@ -327,7 +325,7 @@ local_irq_restore(flags); } -unsigned long h3800_read_egpio( void ) +static unsigned long h3800_read_egpio( void ) { return h3800_asic1_gpio | (h3800_asic2_gpio << 16); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/huw_webpanel.c linux-2.5/arch/arm/mach-sa1100/huw_webpanel.c --- linux-2.5.5/arch/arm/mach-sa1100/huw_webpanel.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/arm/mach-sa1100/huw_webpanel.c Tue Feb 26 21:24:48 2002 @@ -2,8 +2,6 @@ * linux/arch/arm/mach-sa1100/huw_webpanel.c * */ - -#include #include #include #include @@ -66,7 +64,7 @@ **/ SET_BANK( 0, 0xc0000000, ((32*1024 - (256 + 32)) * 1024)); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xc0800000), 8*1024*1024 ); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/irq.c linux-2.5/arch/arm/mach-sa1100/irq.c --- linux-2.5.5/arch/arm/mach-sa1100/irq.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/arm/mach-sa1100/irq.c Fri Mar 1 15:07:37 2002 @@ -9,8 +9,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - -#include #include #include #include @@ -21,7 +19,6 @@ #include #include #include -#include #include "generic.h" @@ -32,156 +29,170 @@ * This must be called *before* the appropriate IRQ is registered. * Use this instead of directly setting GRER/GFER. */ - static int GPIO_IRQ_rising_edge; static int GPIO_IRQ_falling_edge; +static int GPIO_IRQ_mask = (1 << 11) - 1; -void set_GPIO_IRQ_edge( int gpio_mask, int edge ) +static void sa1100_manual_rerun(unsigned int irq) { - int flags; - - local_irq_save(flags); - if (edge & GPIO_FALLING_EDGE) - GPIO_IRQ_falling_edge |= gpio_mask; - else - GPIO_IRQ_falling_edge &= ~gpio_mask; - if (edge & GPIO_RISING_EDGE) - GPIO_IRQ_rising_edge |= gpio_mask; - else - GPIO_IRQ_rising_edge &= ~gpio_mask; - GPDR &= ~gpio_mask; - GAFR &= ~gpio_mask; - restore_flags(flags); + struct pt_regs regs; + memset(®s, 0, sizeof(regs)); + irq_desc[irq].handle(irq, &irq_desc[irq], ®s); } -EXPORT_SYMBOL(set_GPIO_IRQ_edge); +#define GPIO11_27_MASK(irq) (1 << GPIO_11_27_IRQ(irq)) +static int sa1100_gpio_type(unsigned int irq, unsigned int type) +{ + unsigned int mask; -/* - * We don't need to ACK IRQs on the SA1100 unless they're GPIOs - * this is for internal IRQs i.e. from 11 to 31. - */ + printk(KERN_DEBUG "IRQ%d: ", irq); -static void sa1100_mask_irq(unsigned int irq) -{ - ICMR &= ~(1 << irq); -} + if (irq <= 10) + mask = 1 << irq; + else + mask = GPIO11_27_MASK(irq); -static void sa1100_unmask_irq(unsigned int irq) -{ - ICMR |= (1 << irq); + if (type & __IRQT_RISEDGE) { + printk("rising "); + GPIO_IRQ_rising_edge |= mask; + } else + GPIO_IRQ_rising_edge &= ~mask; + if (type & __IRQT_FALEDGE) { + printk("falling "); + GPIO_IRQ_falling_edge |= mask; + } else + GPIO_IRQ_falling_edge &= ~mask; + + printk("edges\n"); + + GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; + GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; + + return 0; } /* * GPIO IRQs must be acknoledged. This is for IRQs from 0 to 10. */ - -static void sa1100_mask_and_ack_GPIO0_10_irq(unsigned int irq) +static void sa1100_low_gpio_ack(unsigned int irq) { - ICMR &= ~(1 << irq); GEDR = (1 << irq); } -static void sa1100_mask_GPIO0_10_irq(unsigned int irq) +static void sa1100_low_gpio_mask(unsigned int irq) { ICMR &= ~(1 << irq); } -static void sa1100_unmask_GPIO0_10_irq(unsigned int irq) +static void sa1100_low_gpio_unmask(unsigned int irq) { - GRER = (GRER & ~(1 << irq)) | (GPIO_IRQ_rising_edge & (1 << irq)); - GFER = (GFER & ~(1 << irq)) | (GPIO_IRQ_falling_edge & (1 << irq)); - ICMR |= (1 << irq); + ICMR |= 1 << irq; } +static struct irqchip sa1100_low_gpio_chip = { + ack: sa1100_low_gpio_ack, + mask: sa1100_low_gpio_mask, + unmask: sa1100_low_gpio_unmask, + rerun: sa1100_manual_rerun, + type: sa1100_gpio_type, +}; + /* - * Install handler for GPIO 11-27 edge detect interrupts + * IRQ11 (GPIO11 through 27) handler. We enter here with the + * irq_controller_lock held, and IRQs disabled. Decode the IRQ + * and call the handler. */ - -static int GPIO_11_27_enabled; /* enabled i.e. unmasked GPIO IRQs */ -static int GPIO_11_27_spurious; /* GPIOs that triggered when masked */ - -static void sa1100_GPIO11_27_demux(int irq, void *dev_id, - struct pt_regs *regs) +static void +sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc, + struct pt_regs *regs) { - int i, spurious; + unsigned int mask; - while ((irq = (GEDR & 0xfffff800))) { + mask = GEDR & 0xfffff800; + do { /* - * We don't want to clear GRER/GFER when the corresponding - * IRQ is masked because we could miss a level transition - * i.e. an IRQ which need servicing as soon as it is - * unmasked. However, such situation should happen only - * during the loop below. Thus all IRQs which aren't - * enabled at this point are considered spurious. Those - * are cleared but only de-activated if they happen twice. + * clear down all currently active IRQ sources. + * We will be processing them all. */ - spurious = irq & ~GPIO_11_27_enabled; - if (spurious) { - GEDR = spurious; - GRER &= ~(spurious & GPIO_11_27_spurious); - GFER &= ~(spurious & GPIO_11_27_spurious); - GPIO_11_27_spurious |= spurious; - irq ^= spurious; - if (!irq) continue; - } - - for (i = 11; i <= 27; ++i) { - if (irq & (1<>= 11; + do { + if (mask & 1) + desc->handle(irq, desc, regs); + mask >>= 1; + irq++; + desc++; + } while (mask); + + mask = GEDR & 0xfffff800; + } while (mask); +} -static void sa1100_mask_and_ack_GPIO11_27_irq(unsigned int irq) +/* + * Like GPIO0 to 10, GPIO11-27 IRQs need to be handled specially. + * In addition, the IRQs are all collected up into one bit in the + * interrupt controller registers. + */ +static void sa1100_high_gpio_ack(unsigned int irq) { - int mask = (1 << GPIO_11_27_IRQ(irq)); - GPIO_11_27_spurious &= ~mask; - GPIO_11_27_enabled &= ~mask; + unsigned int mask = GPIO11_27_MASK(irq); + GEDR = mask; } -static void sa1100_mask_GPIO11_27_irq(unsigned int irq) +static void sa1100_high_gpio_mask(unsigned int irq) { - int mask = (1 << GPIO_11_27_IRQ(irq)); - GPIO_11_27_spurious &= ~mask; - GPIO_11_27_enabled &= ~mask; + unsigned int mask = GPIO11_27_MASK(irq); + + GPIO_IRQ_mask &= ~mask; + + GRER &= ~mask; + GFER &= ~mask; } -static void sa1100_unmask_GPIO11_27_irq(unsigned int irq) +static void sa1100_high_gpio_unmask(unsigned int irq) { - int mask = (1 << GPIO_11_27_IRQ(irq)); - if (GPIO_11_27_spurious & mask) { - /* - * We don't want to miss an interrupt that would have occurred - * while it was masked. Simulate it if it is the case. - */ - int state = GPLR; - if (((state & GPIO_IRQ_rising_edge) | - (~state & GPIO_IRQ_falling_edge)) & mask) - { - /* just in case it gets referenced: */ - struct pt_regs dummy; - - memzero(&dummy, sizeof(dummy)); - do_IRQ(irq, &dummy); - - /* we are being called recursively from do_IRQ() */ - return; - } - } - GPIO_11_27_enabled |= mask; - GRER = (GRER & ~mask) | (GPIO_IRQ_rising_edge & mask); - GFER = (GFER & ~mask) | (GPIO_IRQ_falling_edge & mask); + unsigned int mask = GPIO11_27_MASK(irq); + + GPIO_IRQ_mask |= mask; + + GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; + GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; +} + +static struct irqchip sa1100_high_gpio_chip = { + ack: sa1100_high_gpio_ack, + mask: sa1100_high_gpio_mask, + unmask: sa1100_high_gpio_unmask, + rerun: sa1100_manual_rerun, + type: sa1100_gpio_type, +}; + +/* + * We don't need to ACK IRQs on the SA1100 unless they're GPIOs + * this is for internal IRQs i.e. from 11 to 31. + */ +static void sa1100_mask_irq(unsigned int irq) +{ + ICMR &= ~(1 << irq); +} + +static void sa1100_unmask_irq(unsigned int irq) +{ + ICMR |= (1 << irq); } +static struct irqchip sa1100_normal_chip = { + ack: sa1100_mask_irq, + mask: sa1100_mask_irq, + unmask: sa1100_unmask_irq, + /* rerun should never be called */ +}; + static struct resource irq_resource = { name: "irqs", start: 0x90050000, @@ -190,7 +201,7 @@ void __init sa1100_init_irq(void) { - int irq; + unsigned int irq; request_resource(&iomem_resource, &irq_resource); @@ -212,33 +223,32 @@ ICCR = 1; for (irq = 0; irq <= 10; irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = sa1100_mask_and_ack_GPIO0_10_irq; - irq_desc[irq].mask = sa1100_mask_GPIO0_10_irq; - irq_desc[irq].unmask = sa1100_unmask_GPIO0_10_irq; + set_irq_chip(irq, &sa1100_low_gpio_chip); + set_irq_handler(irq, do_edge_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - for (irq = 11; irq <= 31; irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 0; - irq_desc[irq].mask_ack = sa1100_mask_irq; - irq_desc[irq].mask = sa1100_mask_irq; - irq_desc[irq].unmask = sa1100_unmask_irq; + for (irq = 12; irq <= 31; irq++) { + set_irq_chip(irq, &sa1100_normal_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, IRQF_VALID); } for (irq = 32; irq <= 48; irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = sa1100_mask_and_ack_GPIO11_27_irq; - irq_desc[irq].mask = sa1100_mask_GPIO11_27_irq; - irq_desc[irq].unmask = sa1100_unmask_GPIO11_27_irq; + set_irq_chip(irq, &sa1100_high_gpio_chip); + set_irq_handler(irq, do_edge_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - setup_arm_irq( IRQ_GPIO11_27, &GPIO11_27_irq ); + + /* + * Install handler for GPIO 11-27 edge detect interrupts + */ + set_irq_chip(IRQ_GPIO11_27, &sa1100_normal_chip); + set_irq_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler); /* * We generally don't want the LCD IRQ being * enabled as soon as we request it. */ - irq_desc[IRQ_LCD].noautoenable = 1; + set_irq_flags(IRQ_LCD, IRQF_VALID | IRQF_NOAUTOEN); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/jornada720.c linux-2.5/arch/arm/mach-sa1100/jornada720.c --- linux-2.5.5/arch/arm/mach-sa1100/jornada720.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/mach-sa1100/jornada720.c Fri Mar 1 15:07:37 2002 @@ -48,7 +48,7 @@ /* initialize extra IRQs */ set_GPIO_IRQ_edge(GPIO_GPIO1, GPIO_RISING_EDGE); - sa1111_init_irq(IRQ_GPIO1)); /* chained on GPIO 1 */ + sa1111_init_irq(IRQ_GPIO1); /* chained on GPIO 1 */ return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/leds-adsbitsy.c linux-2.5/arch/arm/mach-sa1100/leds-adsbitsy.c --- linux-2.5.5/arch/arm/mach-sa1100/leds-adsbitsy.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/mach-sa1100/leds-adsbitsy.c Tue Feb 26 21:24:48 2002 @@ -28,7 +28,7 @@ { unsigned long flags; - save_flags_cli(flags); + local_irq_save(flags); switch (evt) { case led_start: @@ -92,5 +92,5 @@ GPCR = hw_led_state ^ LED_MASK; } - restore_flags(flags); + local_irq_restore(flags); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/leds-graphicsclient.c linux-2.5/arch/arm/mach-sa1100/leds-graphicsclient.c --- linux-2.5.5/arch/arm/mach-sa1100/leds-graphicsclient.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/mach-sa1100/leds-graphicsclient.c Tue Feb 26 21:24:48 2002 @@ -30,7 +30,7 @@ { unsigned long flags; - save_flags_cli(flags); + local_irq_save(flags); switch (evt) { case led_start: @@ -100,5 +100,5 @@ GPCR = hw_led_state ^ LED_MASK; } - restore_flags(flags); + local_irq_restore(flags); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/leds-graphicsmaster.c linux-2.5/arch/arm/mach-sa1100/leds-graphicsmaster.c --- linux-2.5.5/arch/arm/mach-sa1100/leds-graphicsmaster.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/arm/mach-sa1100/leds-graphicsmaster.c Tue Feb 26 21:24:48 2002 @@ -30,7 +30,7 @@ { unsigned long flags; - save_flags_cli(flags); + local_irq_save(flags); switch (evt) { case led_start: @@ -100,5 +100,5 @@ GPCR = hw_led_state ^ LED_MASK; } - restore_flags(flags); + local_irq_restore(flags); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/leds-system3.c linux-2.5/arch/arm/mach-sa1100/leds-system3.c --- linux-2.5.5/arch/arm/mach-sa1100/leds-system3.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/mach-sa1100/leds-system3.c Tue Feb 26 21:24:48 2002 @@ -26,7 +26,6 @@ * * */ -#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/leds.c linux-2.5/arch/arm/mach-sa1100/leds.c --- linux-2.5.5/arch/arm/mach-sa1100/leds.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/arm/mach-sa1100/leds.c Tue Feb 26 21:24:48 2002 @@ -5,7 +5,6 @@ * * Copyright (C) 2001 Nicolas Pitre */ -#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/nanoengine.c linux-2.5/arch/arm/mach-sa1100/nanoengine.c --- linux-2.5.5/arch/arm/mach-sa1100/nanoengine.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/mach-sa1100/nanoengine.c Tue Feb 26 21:24:48 2002 @@ -23,7 +23,7 @@ SET_BANK( 0, 0xc0000000, 32*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/neponset.c linux-2.5/arch/arm/mach-sa1100/neponset.c --- linux-2.5.5/arch/arm/mach-sa1100/neponset.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/arm/mach-sa1100/neponset.c Fri Mar 1 15:07:37 2002 @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -24,53 +23,78 @@ /* - * Install handler for Neponset IRQ. Yes, yes... we are way down the IRQ - * cascade which is not good for IRQ latency, but the hardware has been - * designed that way... + * Install handler for Neponset IRQ. Note that we have to loop here + * since the ETHERNET and USAR IRQs are level based, and we need to + * ensure that the IRQ signal is deasserted before returning. This + * is rather unfortunate. */ - -static void neponset_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs ) +static void +neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) { - int irr; + unsigned int irr; + + while (1) { + struct irqdesc *d; + + /* + * Acknowledge the parent IRQ. + */ + desc->chip->ack(irq); - for(;;){ - irr = IRR & (IRR_ETHERNET | IRR_USAR | IRR_SA1111); - /* Let's have all active IRQ bits high. - * Note: there is a typo in the Neponset user's guide - * for the SA1111 IRR level. + /* + * Read the interrupt reason register. Let's have all + * active IRQ bits high. Note: there is a typo in the + * Neponset user's guide for the SA1111 IRR level. */ - irr ^= (IRR_ETHERNET | IRR_USAR); - if (!irr) break; + irr = IRR ^ (IRR_ETHERNET | IRR_USAR); - if( irr & IRR_ETHERNET ) - do_IRQ(IRQ_NEPONSET_SMC9196, regs); + if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0) + break; - if( irr & IRR_USAR ) - do_IRQ(IRQ_NEPONSET_USAR, regs); + /* + * Since there is no individual mask, we have to + * mask the parent IRQ. This is safe, since we'll + * recheck the register for any pending IRQs. + */ + if (irr & (IRR_ETHERNET | IRR_USAR)) { + desc->chip->mask(irq); - if( irr & IRR_SA1111 ) - sa1111_IRQ_demux(irq, dev_id, regs); + if (irr & IRR_ETHERNET) { + d = irq_desc + IRQ_NEPONSET_SMC9196; + d->handle(IRQ_NEPONSET_SMC9196, d, regs); + } + + if (irr & IRR_USAR) { + d = irq_desc + IRQ_NEPONSET_USAR; + d->handle(IRQ_NEPONSET_USAR, d, regs); + } + + desc->chip->unmask(irq); + } + + if (irr & IRR_SA1111) { + d = irq_desc + IRQ_NEPONSET_SA1111; + d->handle(IRQ_NEPONSET_SA1111, d, regs); + } } } -static struct irqaction neponset_irq = { - name: "Neponset", - handler: neponset_IRQ_demux, - flags: SA_INTERRUPT -}; - static void __init neponset_init_irq(void) { - sa1111_init_irq(-1); /* SA1111 IRQ not routed to a GPIO */ - - /* setup extra Neponset IRQs */ - irq_desc[IRQ_NEPONSET_SMC9196].valid = 1; - irq_desc[IRQ_NEPONSET_SMC9196].probe_ok = 1; - irq_desc[IRQ_NEPONSET_USAR].valid = 1; - irq_desc[IRQ_NEPONSET_USAR].probe_ok = 1; + /* + * Install handler for GPIO25. + */ + set_irq_type(IRQ_GPIO25, IRQT_RISING); + set_irq_chained_handler(IRQ_GPIO25, neponset_irq_handler); - set_GPIO_IRQ_edge(GPIO_GPIO25, GPIO_RISING_EDGE); - setup_arm_irq(IRQ_GPIO25, &neponset_irq); + /* + * Setup other Neponset IRQs. SA1111 will be done by the + * generic SA1111 code. + */ + set_irq_handler(IRQ_NEPONSET_SMC9196, do_simple_IRQ); + set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE); + set_irq_handler(IRQ_NEPONSET_USAR, do_simple_IRQ); + set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE); } static int __init neponset_init(void) @@ -101,6 +125,8 @@ return -ENODEV; } + neponset_init_irq(); + /* * Disable GPIO 0/1 drivers so the buttons work on the module. */ @@ -146,7 +172,10 @@ */ sa1110_mb_enable(); - neponset_init_irq(); + /* + * Initialise SA1111 IRQs + */ + sa1111_init_irq(IRQ_NEPONSET_SA1111); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/omnimeter.c linux-2.5/arch/arm/mach-sa1100/omnimeter.c --- linux-2.5.5/arch/arm/mach-sa1100/omnimeter.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/mach-sa1100/omnimeter.c Tue Feb 26 21:24:48 2002 @@ -47,7 +47,7 @@ SET_BANK( 0, 0xc0000000, 16*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xd0000000), 0x00400000 ); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/pangolin.c linux-2.5/arch/arm/mach-sa1100/pangolin.c --- linux-2.5.5/arch/arm/mach-sa1100/pangolin.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/arm/mach-sa1100/pangolin.c Tue Feb 26 21:24:48 2002 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mach-sa1100/pangolin.c */ - +#include #include #include #include @@ -23,7 +23,7 @@ SET_BANK( 0, 0xc0000000, 128*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 16384 ); setup_initrd( 0xc0800000, 3*1024*1024 ); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/pfs168.c linux-2.5/arch/arm/mach-sa1100/pfs168.c --- linux-2.5.5/arch/arm/mach-sa1100/pfs168.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/mach-sa1100/pfs168.c Tue Feb 26 21:24:48 2002 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mach-sa1100/pfs168.c */ - +#include #include #include #include @@ -96,7 +96,7 @@ SET_BANK( 0, 0xc0000000, 16*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( 0xc0800000, 3*1024*1024 ); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/pleb.c linux-2.5/arch/arm/mach-sa1100/pleb.c --- linux-2.5.5/arch/arm/mach-sa1100/pleb.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/mach-sa1100/pleb.c Tue Feb 26 21:24:48 2002 @@ -28,7 +28,7 @@ /* make it 1 if a 16MB memory card is used */ mi->nr_banks = 2; /* Default 32MB */ - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 0); setup_ramdisk(1, 0, 0, 8192); setup_initrd(0xc0400000, 4*1024*1024); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/pm.c linux-2.5/arch/arm/mach-sa1100/pm.c --- linux-2.5.5/arch/arm/mach-sa1100/pm.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/arm/mach-sa1100/pm.c Fri Mar 1 15:07:37 2002 @@ -51,8 +51,6 @@ int pm_do_suspend(void) { - int retval; - /* set up pointer to sleep parameters */ sleep_save = kmalloc(SLEEP_SAVE_SIZE*sizeof(long), GFP_ATOMIC); if (!sleep_save) @@ -107,7 +105,7 @@ PSPR = 0; #ifdef DEBUG - printk("*** made it back from resume\n"); + printk(KERN_DEBUG "*** made it back from resume\n"); #endif /* restore registers */ @@ -171,28 +169,22 @@ #define ACPI_S1_SLP_TYP 19 /* - * Send us to sleep. We must not be called from IRQ context. + * Send us to sleep. */ static int sysctl_pm_do_suspend(void) { int retval; - if (in_interrupt()) { - printk(KERN_CRIT "pm_do_suspend() called from IRQ\n"); - return -EINVAL; - } - retval = pm_send_all(PM_SUSPEND, (void *)3); if (retval == 0) { - retval = __pm_do_suspend(); + retval = pm_do_suspend(); pm_send_all(PM_RESUME, (void *)0); } return retval; } - static struct ctl_table pm_table[] = { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/sa1111-pcibuf.c linux-2.5/arch/arm/mach-sa1100/sa1111-pcibuf.c --- linux-2.5.5/arch/arm/mach-sa1100/sa1111-pcibuf.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/mach-sa1100/sa1111-pcibuf.c Tue Feb 26 21:24:48 2002 @@ -13,7 +13,6 @@ * * 06/13/2001 - created. */ -#include #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/sa1111.c linux-2.5/arch/arm/mach-sa1100/sa1111.c --- linux-2.5.5/arch/arm/mach-sa1100/sa1111.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/arm/mach-sa1100/sa1111.c Fri Mar 1 15:07:37 2002 @@ -27,7 +27,6 @@ #include #include #include -#include #include @@ -40,70 +39,104 @@ EXPORT_SYMBOL(sa1111_resource); /* - * SA1111 interrupt support + * SA1111 interrupt support. Since clearing an IRQ while there are + * active IRQs causes the interrupt output to pulse, the upper levels + * will call us again if there are more interrupts to process. */ -void sa1111_IRQ_demux(int irq, void *dev_id, struct pt_regs *regs) +static void +sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) { - unsigned long stat0, stat1; + unsigned int stat0, stat1, i; - while (1) { - int i; + desc->chip->ack(irq); - stat0 = INTSTATCLR0; - stat1 = INTSTATCLR1; + stat0 = INTSTATCLR0; + stat1 = INTSTATCLR1; - if (stat0 == 0 && stat1 == 0) - break; - - for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1) - if (stat0 & 1) - do_IRQ(i, regs); - - for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1) - if (stat1 & 1) - do_IRQ(i, regs); + if (stat0 == 0 && stat1 == 0) { + do_bad_IRQ(irq, desc, regs); + return; } + + for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1) + if (stat0 & 1) + do_edge_IRQ(i, irq_desc + i, regs); + + for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1) + if (stat1 & 1) + do_edge_IRQ(i, irq_desc + i, regs); } #define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START)) #define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32)) +static void sa1111_ack_lowirq(unsigned int irq) +{ + INTSTATCLR0 = SA1111_IRQMASK_LO(irq); +} + +static void sa1111_mask_lowirq(unsigned int irq) +{ + INTEN0 &= ~SA1111_IRQMASK_LO(irq); +} + +static void sa1111_unmask_lowirq(unsigned int irq) +{ + INTEN0 |= SA1111_IRQMASK_LO(irq); +} + /* - * A note about masking IRQs: - * - * The GPIO IRQ edge detection only functions while the IRQ itself is - * enabled; edges are not detected while the IRQ is disabled. - * - * This is especially important for the PCMCIA signals, where we must - * pick up every transition. We therefore do not disable the IRQs - * while processing them. - * - * However, since we are changed to a GPIO on the host processor, - * all SA1111 IRQs will be disabled while we're processing any SA1111 - * IRQ. - * - * Note also that changing INTPOL while an IRQ is enabled will itself - * trigger an IRQ. + * Attempt to re-trigger the interrupt. The SA1111 contains a register + * (INTSET) which claims to do this. However, in practice no amount of + * manipulation of INTEN and INTSET guarantees that the interrupt will + * be triggered. In fact, its very difficult, if not impossible to get + * INTSET to re-trigger the interrupt. */ -static void sa1111_mask_and_ack_lowirq(unsigned int irq) +static void sa1111_rerun_lowirq(unsigned int irq) { unsigned int mask = SA1111_IRQMASK_LO(irq); + int i; + + for (i = 0; i < 8; i++) { + INTPOL0 ^= mask; + INTPOL0 ^= mask; + if (INTSTATCLR1 & mask) + break; + } - //INTEN0 &= ~mask; - INTSTATCLR0 = mask; + if (i == 8) + printk(KERN_ERR "Danger Will Robinson: failed to " + "re-trigger IRQ%d\n", irq); } -static void sa1111_mask_and_ack_highirq(unsigned int irq) +static int sa1111_type_lowirq(unsigned int irq, unsigned int flags) { - unsigned int mask = SA1111_IRQMASK_HI(irq); + unsigned int mask = SA1111_IRQMASK_LO(irq); + + if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0) + return -EINVAL; + + printk("IRQ%d: %s edge\n", irq, flags & __IRQT_RISEDGE ? "rising" : "falling"); - //INTEN1 &= ~mask; - INTSTATCLR1 = mask; + if (flags & __IRQT_RISEDGE) + INTPOL0 &= ~mask; + else + INTPOL0 |= mask; + + return 0; } -static void sa1111_mask_lowirq(unsigned int irq) +static struct irqchip sa1111_low_chip = { + ack: sa1111_ack_lowirq, + mask: sa1111_mask_lowirq, + unmask: sa1111_unmask_lowirq, + rerun: sa1111_rerun_lowirq, + type: sa1111_type_lowirq, +}; + +static void sa1111_ack_highirq(unsigned int irq) { - INTEN0 &= ~SA1111_IRQMASK_LO(irq); + INTSTATCLR1 = SA1111_IRQMASK_HI(irq); } static void sa1111_mask_highirq(unsigned int irq) @@ -111,19 +144,63 @@ INTEN1 &= ~SA1111_IRQMASK_HI(irq); } -static void sa1111_unmask_lowirq(unsigned int irq) +static void sa1111_unmask_highirq(unsigned int irq) { - INTEN0 |= SA1111_IRQMASK_LO(irq); + INTEN1 |= SA1111_IRQMASK_HI(irq); } -static void sa1111_unmask_highirq(unsigned int irq) +/* + * Attempt to re-trigger the interrupt. The SA1111 contains a register + * (INTSET) which claims to do this. However, in practice no amount of + * manipulation of INTEN and INTSET guarantees that the interrupt will + * be triggered. In fact, its very difficult, if not impossible to get + * INTSET to re-trigger the interrupt. + */ +static void sa1111_rerun_highirq(unsigned int irq) { - INTEN1 |= SA1111_IRQMASK_HI(irq); + unsigned int mask = SA1111_IRQMASK_HI(irq); + int i; + + for (i = 0; i < 8; i++) { + INTPOL1 ^= mask; + INTPOL1 ^= mask; + if (INTSTATCLR1 & mask) + break; + } + + if (i == 8) + printk(KERN_ERR "Danger Will Robinson: failed to " + "re-trigger IRQ%d\n", irq); } +static int sa1111_type_highirq(unsigned int irq, unsigned int flags) +{ + unsigned int mask = SA1111_IRQMASK_HI(irq); + + if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0) + return -EINVAL; + + printk("IRQ%d: %s edge\n", irq, flags & __IRQT_RISEDGE ? "rising" : "falling"); + + if (flags & __IRQT_RISEDGE) + INTPOL1 &= ~mask; + else + INTPOL1 |= mask; + + return 0; +} + +static struct irqchip sa1111_high_chip = { + ack: sa1111_ack_highirq, + mask: sa1111_mask_highirq, + unmask: sa1111_unmask_highirq, + rerun: sa1111_rerun_highirq, + type: sa1111_type_highirq, +}; + void __init sa1111_init_irq(int irq_nr) { - int irq, ret; + unsigned int irq; request_mem_region(_INTTEST0, 512, "irqs"); @@ -140,33 +217,26 @@ SA1111_IRQMASK_HI(S1_READY_NINT); /* clear all IRQs */ - INTSTATCLR0 = -1; - INTSTATCLR1 = -1; + INTSTATCLR0 = ~0; + INTSTATCLR1 = ~0; for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 0; - irq_desc[irq].mask_ack = sa1111_mask_and_ack_lowirq; - irq_desc[irq].mask = sa1111_mask_lowirq; - irq_desc[irq].unmask = sa1111_unmask_lowirq; + set_irq_chip(irq, &sa1111_low_chip); + set_irq_handler(irq, do_edge_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } + for (irq = AUDXMTDMADONEA; irq <= S1_BVD1_STSCHG; irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 0; - irq_desc[irq].mask_ack = sa1111_mask_and_ack_highirq; - irq_desc[irq].mask = sa1111_mask_highirq; - irq_desc[irq].unmask = sa1111_unmask_highirq; + set_irq_chip(irq, &sa1111_high_chip); + set_irq_handler(irq, do_edge_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - /* Register SA1111 interrupt */ - if (irq_nr < 0) - return; - - ret = request_irq(irq_nr, sa1111_IRQ_demux, SA_INTERRUPT, - "SA1111", NULL); - if (ret < 0) - printk(KERN_ERR "SA1111: unable to claim IRQ%d: %d\n", - irq_nr, ret); + /* + * Register SA1111 interrupt + */ + set_irq_type(irq_nr, IRQT_RISING); + set_irq_chained_handler(irq_nr, sa1111_irq_handler); } /** @@ -199,12 +269,12 @@ */ id = SBI_SKID; if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { - printk(KERN_DEBUG "SA-1111 not detected: ID = %08lx\n", id); + printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id); ret = -ENODEV; goto release; } - printk(KERN_INFO "SA-1111 Microprocessor Companion Chip: " + printk(KERN_INFO "SA1111 Microprocessor Companion Chip: " "silicon revision %lx, metal revision %lx\n", (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/sherman.c linux-2.5/arch/arm/mach-sa1100/sherman.c --- linux-2.5.5/arch/arm/mach-sa1100/sherman.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/mach-sa1100/sherman.c Tue Feb 26 21:24:48 2002 @@ -24,7 +24,7 @@ SET_BANK( 1, 0xc8000000, 64*1024*1024 ); mi->nr_banks = 2; - ROOT_DEV = MKDEV( 60, 2 ); + ROOT_DEV = mk_kdev( 60, 2 ); setup_ramdisk( 1, 0, 0, 8192 ); // setup_initrd( 0xc0400000, 8*1024*1024 ); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/simpad.c linux-2.5/arch/arm/mach-sa1100/simpad.c --- linux-2.5.5/arch/arm/mach-sa1100/simpad.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/arm/mach-sa1100/simpad.c Fri Mar 1 15:07:37 2002 @@ -50,7 +50,7 @@ SET_BANK( 0, 0xc0000000, 32*1024*1024 ); #endif mi->nr_banks = 1; - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); } @@ -93,7 +93,7 @@ sa1100_register_uart(0, 3); sa1100_register_uart(1, 1); - set_GPIO_IRQ_edge(GPIO_UCB1300_IRQ); + set_irq_type(IRQ_GPIO_UCB1300_IRQ, IRQT_RISING); } #ifdef CONFIG_PROC_FS diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/stork.c linux-2.5/arch/arm/mach-sa1100/stork.c --- linux-2.5.5/arch/arm/mach-sa1100/stork.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mach-sa1100/stork.c Fri Mar 1 15:07:37 2002 @@ -0,0 +1,361 @@ +/* + * linux/arch/arm/mach-sa1100/stork.c + * + * Copyright (C) 2001 Ken Gordon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "generic.h" + + +#define STORK_VM_BASE_CS1 0xf0000000 /* where we get mapped (virtual) */ +#define STORK_VM_OFF_CS1 0x08000000 /* where we started mapping (physical) */ +#define STORK_VM_ADJUST_CS1 (STORK_VM_BASE_CS1-STORK_VM_OFF_CS1) /* add to the phys to get virt */ + +#define STORK_VM_BASE_CS2 0xf1000000 /* where we get mapped (virtual) */ +#define STORK_VM_OFF_CS2 0x10000000 /* where we started mapping (physical) */ +#define STORK_VM_ADJUST_CS2 (STORK_VM_BASE_CS2-STORK_VM_OFF_CS2) /* add to the phys to get virt */ + +static int debug = 0; + +static int storkLatchA = 0; +static int storkLatchB = 0; +static int storkLCDCPLD[4] = { 0, 0, 0, 0}; + +int +storkSetLatchA(int bits) +{ + int ret = storkLatchA; + volatile unsigned int *latch = (unsigned int *)(STORK_LATCH_A_ADDR+STORK_VM_ADJUST_CS1); + + storkLatchA |= bits; + *latch = storkLatchA; + return ret; +} + +int +storkClearLatchA(int bits) +{ + int ret = storkLatchA; + volatile unsigned int *latch = (unsigned int *)(STORK_LATCH_A_ADDR+STORK_VM_ADJUST_CS1); + + storkLatchA &= ~bits; + *latch = storkLatchA; + return ret; +} + +int +storkSetLCDCPLD(int which, int bits) +{ + int ret = storkLCDCPLD[which]; + volatile unsigned int *latch = (unsigned int *)(STORK_LCDCPLD_BASE_ADDR+STORK_VM_ADJUST_CS2 + 0x20*which); + + storkLCDCPLD[which] |= bits; + *latch = storkLCDCPLD[which]; + return ret; +} + + +/* NB we don't shadow these 'cos there is no relation between the data written and the data read */ +/* ie the read registers are read only and the write registers write only */ + +int +storkGetLCDCPLD(int which) +{ + volatile unsigned int *latch = (unsigned int *)(STORK_LCDCPLD_BASE_ADDR+STORK_VM_ADJUST_CS2 + 0x20*which); + return *latch; +} + +int +storkClearLCDCPLD(int which, int bits) +{ + int ret = storkLCDCPLD[which]; + volatile unsigned int *latch = (unsigned int *)(STORK_LCDCPLD_BASE_ADDR+STORK_VM_ADJUST_CS2 + 0x20*which); + + storkLCDCPLD[which] &= ~bits; + *latch = storkLCDCPLD[which]; + return ret; +} + +int +storkSetLatchB(int bits) +{ + int ret = storkLatchB; + char buf[100]; + + volatile unsigned int *latch = (unsigned int *)(STORK_LATCH_B_ADDR+STORK_VM_ADJUST_CS1); + sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits); + if (debug) printk(buf); + + storkLatchB |= bits; + *latch = storkLatchB; + return ret; +} + +int +storkClearLatchB(int bits) +{ + int ret = storkLatchB; + char buf[100]; + + volatile unsigned int *latch = (unsigned int *)(STORK_LATCH_B_ADDR+STORK_VM_ADJUST_CS1); + sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits); + if (debug) printk(buf); + + storkLatchB &= ~bits; + *latch = storkLatchB; + return ret; +} + +void +storkSetGPIO(int bits) +{ + char buf[100]; + + sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits); + if (debug) printk(buf); + GPSR = bits; +} + +void +storkClearGPIO(int bits) +{ + char buf[100]; + + sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits); + if (debug) printk(buf); + GPCR = bits; +} + +int +storkGetGPIO() +{ + char buf[100]; + + int bits = GPLR; + + sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits); + if (debug) printk(buf); + + return bits; +} + +/* this will return the current state of the hardware ANDED with the given bits + so NE => at least one bit was set, but maybe not all of them! */ + +int +storkTestGPIO(int bits) +{ + int val = storkGetGPIO(); + char buf[100]; + + sprintf(buf, "%s: bits %04x val %04x\n", __FUNCTION__, bits, val); + if (debug) printk(buf); + + return (val & bits); +} + +/* NB the touch screen and the d to a use the same data and clock out pins */ + +static void storkClockTS(void) +{ + storkSetLatchB(STORK_TOUCH_SCREEN_DCLK); + udelay(10); /* hmm wait 200ns (min) - ok this ought to be udelay(1) but that doesn't get */ + /* consistant values so I'm using 10 (urgh) */ + storkClearLatchB(STORK_TOUCH_SCREEN_DCLK); + udelay(10); +} + + +int /* there is always a 12 bit read after the write! */ +storkClockByteToTS(int byte) +{ + int timeout = 10000; /* stuff is meant to happen in 60ns */ + int bit; + int result = 0; + + if (debug) printk("storkClockByteToTS: %02x\n", byte); + + storkClearLatchB(STORK_TOUCH_SCREEN_CS); /* slect touch screen */ + + while (timeout-- > 0) + if (storkTestGPIO(GPIO_STORK_TOUCH_SCREEN_BUSY) == 0) + break; + + if (timeout < 0) { + printk("storkClockBitToTS: GPIO_STORK_TOUCH_SCREEN_BUSY didn't go low!\n\r"); +/* ignore error for now return; */ + } + +/* clock out the given byte */ + + for (bit = 0x80; bit > 0; bit = bit >> 1) { + + if ((bit & byte) == 0) + storkClearLatchB(STORK_TOUCH_SCREEN_DIN); + else + storkSetLatchB(STORK_TOUCH_SCREEN_DIN); + + storkClockTS(); + } + + storkClockTS(); /* will be busy for at a clock (at least) */ + + for (timeout = 10000; timeout >= 0; timeout--) + if (storkTestGPIO(GPIO_STORK_TOUCH_SCREEN_BUSY) == 0) + break; + + if (timeout < 0) { + printk("storkClockBitToTS: 2nd GPIO_STORK_TOUCH_SCREEN_BUSY didn't go low!\n\r"); +/* ignore error for now return; */ + } + +/* clock in the result */ + + for (bit = 0x0800; bit > 0; bit = bit >> 1) { + + if (storkTestGPIO(GPIO_STORK_TOUCH_SCREEN_DATA)) + result |= bit; + + storkClockTS(); + } + + storkSetLatchB(STORK_TOUCH_SCREEN_CS); /* unselect touch screen */ + + return result; +} + +void +storkClockShortToDtoA(int word) +{ + int bit; + + storkClearLatchB(STORK_DA_CS); /* select D to A */ + +/* clock out the given byte */ + + for (bit = 0x8000; bit > 0; bit = bit >> 1) { + + if ((bit & word) == 0) + storkClearLatchB(STORK_TOUCH_SCREEN_DIN); + else + storkSetLatchB(STORK_TOUCH_SCREEN_DIN); + + storkClockTS(); + } + + storkSetLatchB(STORK_DA_CS); /* unselect D to A */ + +/* set DTOA#_LOAD low then high (min 20ns) to transfer value to D to A */ + storkClearLatchB(STORK_DA_LD); + storkSetLatchB(STORK_DA_LD); +} + + + +void +storkInitTSandDtoA(void) +{ + storkClearLatchB(STORK_TOUCH_SCREEN_DCLK | STORK_TOUCH_SCREEN_DIN); + storkSetLatchB(STORK_TOUCH_SCREEN_CS | STORK_DA_CS | STORK_DA_LD); + storkClockByteToTS(0xE2); /* turn on the reference */ + storkClockShortToDtoA(0x8D00); /* turn on the contrast */ + storkClockShortToDtoA(0x0A00); /* turn on the brightness */ +} + +/* see asm-arm/keyboard.h - there are a bunch of basically virtual functions required */ +/* we have to fill in for them or else we can't call handle_scancode when we see a button pressed */ + +static int +stork_kbd_translate(unsigned char scancode, unsigned char *keycode, char rawmode) +{ + if (keycode) + *keycode = scancode; + + return 1; +} + +static char +stork_kbd_unexpected_up(unsigned char code) +{ + return 0; +} + + +struct map_desc stork_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ + { STORK_VM_BASE_CS1, STORK_VM_OFF_CS1, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0 */ + { 0xf1000000, 0x10000000, 0x02800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2 */ + { 0xf3800000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4 */ + LAST_DESC +}; + +int __init +stork_map_io(void) +{ + sa1100_map_io(); + iotable_init(stork_io_desc); + + sa1100_register_uart(0, 1); /* com port */ + sa1100_register_uart(1, 2); + sa1100_register_uart(2, 3); + + printk("Stork driver initing latches\r\n"); + + storkClearLatchB(STORK_RED_LED); /* let's have the red LED on please */ + storkSetLatchB(STORK_YELLOW_LED); + storkSetLatchB(STORK_GREEN_LED); + storkSetLatchA(STORK_BATTERY_CHARGER_ON); + storkSetLatchA(STORK_LCD_5V_POWER_ON); + storkSetLatchA(STORK_LCD_3V3_POWER_ON); + + storkInitTSandDtoA(); + + k_translate = stork_kbd_translate; + k_unexpected_up = stork_kbd_unexpected_up; + + return 0; +} + + +MACHINE_START(STORK, "Stork Technologies prototype") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + MAPIO(stork_map_io) + INITIRQ(sa1100_init_irq) +MACHINE_END + + +EXPORT_SYMBOL(storkTestGPIO); +EXPORT_SYMBOL(storkSetGPIO); +EXPORT_SYMBOL(storkClearGPIO); +EXPORT_SYMBOL(storkSetLatchA); +EXPORT_SYMBOL(storkClearLatchA); +EXPORT_SYMBOL(storkSetLatchB); +EXPORT_SYMBOL(storkClearLatchB); +EXPORT_SYMBOL(storkClockByteToTS); +EXPORT_SYMBOL(storkClockShortToDtoA); +EXPORT_SYMBOL(storkGetLCDCPLD); +EXPORT_SYMBOL(storkSetLCDCPLD); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/system3.c linux-2.5/arch/arm/mach-sa1100/system3.c --- linux-2.5.5/arch/arm/mach-sa1100/system3.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/mach-sa1100/system3.c Tue Feb 26 21:24:48 2002 @@ -54,8 +54,6 @@ #include #include -#include - #include #include "generic.h" @@ -227,7 +225,7 @@ { DPRINTK( "%s\n", "START" ); - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + ROOT_DEV = mk_kdev(RAMDISK_MAJOR,0); setup_ramdisk( 1, 0, 0, 8192 ); setup_initrd( 0xc0800000, 8*1024*1024 ); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/victor.c linux-2.5/arch/arm/mach-sa1100/victor.c --- linux-2.5.5/arch/arm/mach-sa1100/victor.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/arch/arm/mach-sa1100/victor.c Tue Feb 26 21:24:48 2002 @@ -48,7 +48,7 @@ SET_BANK( 0, 0xc0000000, 4*1024*1024 ); mi->nr_banks = 1; - ROOT_DEV = MKDEV( 60, 2 ); + ROOT_DEV = mk_kdev( 60, 2 ); /* Get command line parameters passed from the loader (if any) */ if( *((char*)0xc0000000) ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-sa1100/yopy.c linux-2.5/arch/arm/mach-sa1100/yopy.c --- linux-2.5.5/arch/arm/mach-sa1100/yopy.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/mach-sa1100/yopy.c Tue Feb 26 21:24:48 2002 @@ -1,8 +1,6 @@ /* * linux/arch/arm/mach-sa1100/yopy.c */ - -#include #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-shark/irq.c linux-2.5/arch/arm/mach-shark/irq.c --- linux-2.5.5/arch/arm/mach-shark/irq.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/arm/mach-shark/irq.c Fri Mar 1 15:07:37 2002 @@ -7,6 +7,12 @@ * include/asm-arm/arch-ebsa110/irq.h * Copyright (C) 1996-1998 Russell King */ + +#include +#include +#include +#include + #include #include #include @@ -31,12 +37,12 @@ if (irq<8) { mask = 1 << irq; cached_irq_mask[0] |= mask; + outb(cached_irq_mask[1],0xA1); } else { mask = 1 << (irq-8); cached_irq_mask[1] |= mask; + outb(cached_irq_mask[0],0x21); } - outb(cached_irq_mask[1],0xA1); - outb(cached_irq_mask[0],0x21); } static void shark_enable_8259A_irq(unsigned int irq) @@ -45,31 +51,15 @@ if (irq<8) { mask = ~(1 << irq); cached_irq_mask[0] &= mask; + outb(cached_irq_mask[0],0x21); } else { mask = ~(1 << (irq-8)); cached_irq_mask[1] &= mask; + outb(cached_irq_mask[1],0xA1); } - outb(cached_irq_mask[1],0xA1); - outb(cached_irq_mask[0],0x21); } -/* - * Careful! The 8259A is a fragile beast, it pretty - * much _has_ to be done exactly like this (mask it - * first, _then_ send the EOI, and the order of EOI - * to the two 8259s is important! - */ -static void shark_mask_and_ack_8259A_irq(unsigned int irq) -{ - if (irq & 8) { - cached_irq_mask[1] |= 1 << (irq-8); - inb(0xA1); /* DUMMY */ - outb(cached_irq_mask[1],0xA1); - } else { - cached_irq_mask[0] |= 1 << irq; - outb(cached_irq_mask[0],0x21); - } -} +static void shark_ack_8259A_irq(unsigned int irq){} static void bogus_int(int irq, void *dev_id, struct pt_regs *regs) { @@ -78,32 +68,30 @@ static struct irqaction cascade; +static struct irqchip fb_chip = { + ack: shark_ack_8259A_irq, + mask: shark_disable_8259A_irq, + unmask: shark_enable_8259A_irq, +}; + void __init shark_init_irq(void) { int irq; for (irq = 0; irq < NR_IRQS; irq++) { - irq_desc[irq].valid = 1; - irq_desc[irq].probe_ok = 1; - irq_desc[irq].mask_ack = shark_mask_and_ack_8259A_irq; - irq_desc[irq].mask = shark_disable_8259A_irq; - irq_desc[irq].unmask = shark_enable_8259A_irq; + set_irq_chip(irq, &fb_chip); + set_irq_handler(irq, do_edge_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - /* The PICs are initialized to level triggered and auto eoi! - * If they are set to edge triggered they lose some IRQs, - * if they are set to manual eoi they get locked up after - * a short time - */ - /* init master interrupt controller */ - outb(0x19, 0x20); /* Start init sequence, level triggered */ + outb(0x11, 0x20); /* Start init sequence, edge triggered (level: 0x19)*/ outb(0x00, 0x21); /* Vector base */ outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */ outb(0x03, 0x21); /* Select 8086 mode , auto eoi*/ outb(0x0A, 0x20); /* init slave interrupt controller */ - outb(0x19, 0xA0); /* Start init sequence, level triggered */ + outb(0x11, 0xA0); /* Start init sequence, edge triggered */ outb(0x08, 0xA1); /* Vector base */ outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */ outb(0x03, 0xA1); /* Select 8086 mode, auto eoi */ @@ -119,6 +107,6 @@ cascade.name = "cascade"; cascade.next = NULL; cascade.dev_id = NULL; - setup_arm_irq(2,&cascade); + setup_irq(2,&cascade); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mach-shark/pci.c linux-2.5/arch/arm/mach-shark/pci.c --- linux-2.5.5/arch/arm/mach-shark/pci.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/mach-shark/pci.c Fri Mar 1 15:07:37 2002 @@ -17,11 +17,14 @@ if (dev->bus->number == 0) if (dev->devfn == 0) return 255; else return 11; - else return 6; + else return 255; } struct hw_pci shark_pci __initdata = { - init: via82c505_init, - swizzle: no_swizzle, - map_irq: shark_map_irq + setup: via82c505_setup, + swizzle: pci_std_swizzle, + map_irq: shark_map_irq, + nr_controllers: 1, + scan: via82c505_scan_bus, + preinit: via82c505_preinit }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/Makefile linux-2.5/arch/arm/mm/Makefile --- linux-2.5.5/arch/arm/mm/Makefile Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/mm/Makefile Fri Mar 1 15:07:37 2002 @@ -29,16 +29,16 @@ # Select the processor-specific files p-$(CONFIG_CPU_26) += proc-arm2,3.o -p-$(CONFIG_CPU_ARM610) += proc-arm6,7.o -p-$(CONFIG_CPU_ARM710) += proc-arm6,7.o -p-$(CONFIG_CPU_ARM720T) += proc-arm720.o armv4t-late-abort.o -p-$(CONFIG_CPU_ARM920T) += proc-arm920.o armv4t-early-abort.o -p-$(CONFIG_CPU_ARM922T) += proc-arm922.o armv4t-early-abort.o -p-$(CONFIG_CPU_ARM926T) += proc-arm926.o armv5ej-early-abort.o -p-$(CONFIG_CPU_ARM1020) += proc-arm1020.o armv4t-early-abort.o -p-$(CONFIG_CPU_SA110) += proc-sa110.o armv4-early-abort.o -p-$(CONFIG_CPU_SA1100) += proc-sa110.o armv4-early-abort.o minicache.o -p-$(CONFIG_CPU_XSCALE) += proc-xscale.o armv4t-early-abort.o minicache.o +p-$(CONFIG_CPU_ARM610) += proc-arm6,7.o tlb-v3.o copypage-v3.o +p-$(CONFIG_CPU_ARM710) += proc-arm6,7.o tlb-v3.o copypage-v3.o +p-$(CONFIG_CPU_ARM720T) += proc-arm720.o tlb-v4.o copypage-v4.o abort-lv4t.o +p-$(CONFIG_CPU_ARM920T) += proc-arm920.o tlb-v4wb.o copypage-v4.o abort-ev4t.o +p-$(CONFIG_CPU_ARM922T) += proc-arm922.o tlb-v4wb.o copypage-v4.o abort-ev4t.o +p-$(CONFIG_CPU_ARM926T) += proc-arm926.o tlb-v4wb.o copypage-v4.o abort-ev5ej.o +p-$(CONFIG_CPU_ARM1020) += proc-arm1020.o tlb-v4wb.o copypage-v4.o abort-ev4t.o +p-$(CONFIG_CPU_SA110) += proc-sa110.o tlb-v4wb.o copypage-v4.o copypage-v4mc.o abort-ev4.o minicache.o +p-$(CONFIG_CPU_SA1100) += proc-sa110.o tlb-v4wb.o copypage-v4.o copypage-v4mc.o abort-ev4.o minicache.o +p-$(CONFIG_CPU_XSCALE) += proc-xscale.o tlb-v4wb.o copypage-v5te.o abort-ev4t.o minicache.o obj-y += $(sort $(p-y)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/abort-ev4.S linux-2.5/arch/arm/mm/abort-ev4.S --- linux-2.5.5/arch/arm/mm/abort-ev4.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/abort-ev4.S Fri Mar 1 15:07:37 2002 @@ -0,0 +1,29 @@ +#include +#include +/* + * Function: armv4_early_abort + * + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR + * + * Returns : r0 = address of abort + * : r1 = FSR, bit 8 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers + * + * Purpose : obtain information about current aborted instruction. + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. + */ + .align 5 +ENTRY(armv4_early_abort) + mrc p15, 0, r1, c5, c0, 0 @ get FSR + mrc p15, 0, r0, c6, c0, 0 @ get FAR + ldr r3, [r2] @ read aborted ARM instruction + tst r3, #1 << 20 @ L = 1 -> write? + orreq r1, r1, #1 << 8 @ yes. + mov pc, lr + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/abort-ev4t.S linux-2.5/arch/arm/mm/abort-ev4t.S --- linux-2.5.5/arch/arm/mm/abort-ev4t.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/abort-ev4t.S Fri Mar 1 15:07:37 2002 @@ -0,0 +1,31 @@ +#include +#include +/* + * Function: armv4t_early_abort + * + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR + * + * Returns : r0 = address of abort + * : r1 = FSR, bit 8 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers + * + * Purpose : obtain information about current aborted instruction. + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. + */ + .align 5 +ENTRY(armv4t_early_abort) + mrc p15, 0, r1, c5, c0, 0 @ get FSR + mrc p15, 0, r0, c6, c0, 0 @ get FAR + tst r3, #PSR_T_BIT + ldrneh r3, [r2] @ read aborted thumb instruction + ldreq r3, [r2] @ read aborted ARM instruction + bic r1, r1, #1 << 8 + movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 + tst r3, #1 << 20 @ check write + orreq r1, r1, #1 << 8 + mov pc, lr diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/abort-ev5ej.S linux-2.5/arch/arm/mm/abort-ev5ej.S --- linux-2.5.5/arch/arm/mm/abort-ev5ej.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/abort-ev5ej.S Fri Mar 1 15:07:37 2002 @@ -0,0 +1,35 @@ +#include +#include +/* + * Function: armv5ej_early_abort + * + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR + * + * Returns : r0 = address of abort + * : r1 = FSR, bit 8 = write + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers + * + * Purpose : obtain information about current aborted instruction. + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. + */ + .align 5 +ENTRY(armv5ej_early_abort) + mrc p15, 0, r1, c5, c0, 0 @ get FSR + mrc p15, 0, r0, c6, c0, 0 @ get FAR + tst r3, #PSR_J_BIT + orrne r1, r1, #1 << 8 @ always assume write + bne 1f + tst r3, #PSR_T_BIT + ldrneh r3, [r2] @ read aborted thumb instruction + ldreq r3, [r2] @ read aborted ARM instruction + movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 + tst r2, #1 << 20 @ L = 1 -> write + orreq r1, r1, #1 << 8 @ yes. +1: mov pc, lr + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/abort-lv4t.S linux-2.5/arch/arm/mm/abort-lv4t.S --- linux-2.5.5/arch/arm/mm/abort-lv4t.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/abort-lv4t.S Fri Mar 1 15:07:37 2002 @@ -0,0 +1,224 @@ +#include +#include +/* + * Function: armv4t_late_abort + * + * Params : r2 = address of aborted instruction + * : r3 = saved SPSR + * + * Returns : r0 = address of abort + * : r1 = FSR, bit 8 = writing + * : r2-r8 = corrupted + * : r9 = preserved + * : sp = pointer to registers + * + * Purpose : obtain information about current aborted instruction. + * Note: we read user space. This means we might cause a data + * abort here if the I-TLB and D-TLB aren't seeing the same + * picture. Unfortunately, this does happen. We live with it. + */ +ENTRY(armv4t_late_abort) + tst r3, #PSR_T_BIT @ check for thumb mode + mrc p15, 0, r1, c5, c0, 0 @ get FSR + mrc p15, 0, r0, c6, c0, 0 @ get FAR + ldreq r8, [r2] @ read arm instruction + bne .data_thumb_abort + tst r8, #1 << 20 @ L = 1 -> write? + orreq r1, r1, #1 << 8 @ yes. + and r7, r8, #15 << 24 + add pc, pc, r7, lsr #22 @ Now branch to the relevant processing routine + nop + +/* 0 */ b .data_arm_lateldrhpost @ ldrh rd, [rn], #m/rm +/* 1 */ b .data_arm_lateldrhpre @ ldrh rd, [rn, #m/rm] +/* 2 */ b .data_unknown +/* 3 */ b .data_unknown +/* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m +/* 5 */ b .data_arm_lateldrpreconst @ ldr rd, [rn, #m] +/* 6 */ b .data_arm_lateldrpostreg @ ldr rd, [rn], rm +/* 7 */ b .data_arm_lateldrprereg @ ldr rd, [rn, rm] +/* 8 */ b .data_arm_ldmstm @ ldm*a rn, +/* 9 */ b .data_arm_ldmstm @ ldm*b rn, +/* a */ b .data_unknown +/* b */ b .data_unknown +/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m +/* d */ mov pc, lr @ ldc rd, [rn, #m] +/* e */ b .data_unknown +/* f */ +.data_unknown: @ Part of jumptable + mov r0, r2 + mov r1, r8 + mov r2, sp + bl baddataabort + b ret_from_exception + +.data_arm_ldmstm: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup + mov r7, #0x11 + orr r7, r7, #0x1100 + and r6, r8, r7 + and r2, r8, r7, lsl #1 + add r6, r6, r2, lsr #1 + and r2, r8, r7, lsl #2 + add r6, r6, r2, lsr #2 + and r2, r8, r7, lsl #3 + add r6, r6, r2, lsr #3 + add r6, r6, r6, lsr #8 + add r6, r6, r6, lsr #4 + and r6, r6, #15 @ r7 = no. of registers to transfer. + and r5, r8, #15 << 16 @ Extract 'n' form instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r6, lsl #2 @ Undo increment + addeq r7, r7, r6, lsl #2 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrhpre: + tst r8, #1 << 21 @ Check writeback bit + moveq pc, lr @ No writeback -> no fixup +.data_arm_lateldrhpost: + and r5, r8, #0x00f @ get Rm / low nibble of immediate value + tst r8, #1 << 22 @ if (immediate offset) + andne r6, r8, #0xf00 @ { immediate high nibble + orrne r6, r5, r6, lsr #4 @ combine nibbles } else + ldreq r6, [sp, r5, lsl #2] @ { load Rm value } +.data_arm_apply_r6_and_rn: + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r6 @ Undo incrmenet + addeq r7, r7, r6 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrpreconst: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup +.data_arm_lateldrpostconst: + movs r2, r8, lsl #20 @ Get offset + moveq pc, lr @ zero -> no fixup + and r5, r8, #15 << 16 @ Extract 'n' from instruction + ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' + tst r8, #1 << 23 @ Check U bit + subne r7, r7, r2, lsr #20 @ Undo increment + addeq r7, r7, r2, lsr #20 @ Undo decrement + str r7, [sp, r5, lsr #14] @ Put register 'Rn' + mov pc, lr + +.data_arm_lateldrprereg: + tst r8, #1 << 21 @ check writeback bit + moveq pc, lr @ no writeback -> no fixup +.data_arm_lateldrpostreg: + and r7, r8, #15 @ Extract 'm' from instruction + ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' + mov r5, r8, lsr #7 @ get shift count + ands r5, r5, #31 + and r7, r8, #0x70 @ get shift type + orreq r7, r7, #8 @ shift count = 0 + add pc, pc, r7 + nop + + mov r6, r6, lsl r5 @ 0: LSL #!0 + b .data_arm_apply_r6_and_rn + b .data_arm_apply_r6_and_rn @ 1: LSL #0 + nop + b .data_unknown @ 2: MUL? + nop + b .data_unknown @ 3: MUL? + nop + mov r6, r6, lsr r5 @ 4: LSR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, lsr #32 @ 5: LSR #32 + b .data_arm_apply_r6_and_rn + b .data_unknown @ 6: MUL? + nop + b .data_unknown @ 7: MUL? + nop + mov r6, r6, asr r5 @ 8: ASR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, asr #32 @ 9: ASR #32 + b .data_arm_apply_r6_and_rn + b .data_unknown @ A: MUL? + nop + b .data_unknown @ B: MUL? + nop + mov r6, r6, ror r5 @ C: ROR #!0 + b .data_arm_apply_r6_and_rn + mov r6, r6, rrx @ D: RRX + b .data_arm_apply_r6_and_rn + b .data_unknown @ E: MUL? + nop + b .data_unknown @ F: MUL? + +.data_thumb_abort: + ldrh r8, [r2] @ read instruction + tst r8, #1 << 11 @ L = 1 -> write? + orreq r1, r1, #1 << 8 @ yes + and r7, r8, #15 << 12 + add pc, pc, r7, lsr #10 @ lookup in table + nop + +/* 0 */ b .data_unknown +/* 1 */ b .data_unknown +/* 2 */ b .data_unknown +/* 3 */ b .data_unknown +/* 4 */ b .data_unknown +/* 5 */ b .data_thumb_reg +/* 6 */ mov pc, lr +/* 7 */ mov pc, lr +/* 8 */ mov pc, lr +/* 9 */ mov pc, lr +/* A */ b .data_unknown +/* B */ b .data_thumb_pushpop +/* C */ b .data_thumb_ldmstm +/* D */ b .data_unknown +/* E */ b .data_unknown +/* F */ b .data_unknown + +.data_thumb_reg: + tst r8, #1 << 9 + moveq pc, lr + tst r8, #1 << 10 @ If 'S' (signed) bit is set + movne r1, #0 @ it must be a load instr + mov pc, lr + +.data_thumb_pushpop: + tst r8, #1 << 10 + beq .data_unknown + mov r7, #0x11 + and r6, r8, r7 + and r2, r8, r7, lsl #1 + add r6, r6, r2, lsr #1 + and r2, r8, r7, lsl #2 + add r6, r6, r2, lsr #2 + and r2, r8, r7, lsl #3 + add r6, r6, r2, lsr #3 + add r6, r6, r6, lsr #4 + and r2, r8, #0x0100 @ catch 'R' bit for push/pop + add r6, r6, r2, lsr #8 + and r6, r6, #15 @ number of regs to transfer + ldr r7, [sp, #13 << 2] + tst r8, #1 << 11 + addne r7, r7, r6, lsl #2 @ increment SP if PUSH + subeq r7, r7, r6, lsr #2 @ decrement SP if POP + str r7, [sp, #13 << 2] + mov pc, lr + +.data_thumb_ldmstm: + mov r7, #0x11 + and r6, r8, r7 + and r2, r8, r7, lsl #1 + add r6, r6, r2, lsr #1 + and r2, r8, r7, lsl #2 + add r6, r6, r2, lsr #2 + and r2, r8, r7, lsl #3 + add r6, r6, r2, lsr #3 + add r6, r6, r6, lsr #4 + and r6, r6, #15 @ number of regs to transfer + and r5, r8, #7 << 8 + ldr r7, [sp, r5, lsr #6] + sub r7, r7, r6, lsr #2 @ always decrement + str r7, [sp, r5, lsr #6] + mov pc, lr diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/alignment.c linux-2.5/arch/arm/mm/alignment.c --- linux-2.5.5/arch/arm/mm/alignment.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/mm/alignment.c Tue Feb 26 21:24:48 2002 @@ -30,6 +30,10 @@ #include #include +extern void +do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr, + int error_code, struct pt_regs *regs); + /* * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998 * /proc/sys/debug/alignment, modified and integrated into @@ -163,9 +167,9 @@ #define TYPE_LDST 2 #define TYPE_DONE 3 -#define get8_unaligned_check(val,addr,err) \ +#define __get8_unaligned_check(ins,val,addr,err) \ __asm__( \ - "1: ldrb %1, [%2], #1\n" \ + "1: "ins" %1, [%2], #1\n" \ "2:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -179,39 +183,49 @@ : "=r" (err), "=&r" (val), "=r" (addr) \ : "0" (err), "2" (addr)) -#define get8t_unaligned_check(val,addr,err) \ - __asm__( \ - "1: ldrbt %1, [%2], #1\n" \ - "2:\n" \ - " .section .fixup,\"ax\"\n" \ - " .align 2\n" \ - "3: mov %0, #1\n" \ - " b 2b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 3b\n" \ - " .previous\n" \ - : "=r" (err), "=&r" (val), "=r" (addr) \ - : "0" (err), "2" (addr)) +#define __get16_unaligned_check(ins,val,addr) \ + do { \ + unsigned int err = 0, v, a = addr; \ + __get8_unaligned_check(ins,val,a,err); \ + __get8_unaligned_check(ins,v,a,err); \ + val |= v << 8; \ + if (err) \ + goto fault; \ + } while (0) + +#define get16_unaligned_check(val,addr) \ + __get16_unaligned_check("ldrb",val,addr) + +#define get16t_unaligned_check(val,addr) \ + __get16_unaligned_check("ldrbt",val,addr) -#define get16_unaligned_check(val,addr) \ +#define __get32_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v, a = addr; \ - get8_unaligned_check(val,a,err); \ - get8_unaligned_check(v,a,err); \ + __get8_unaligned_check(ins,val,a,err); \ + __get8_unaligned_check(ins,v,a,err); \ val |= v << 8; \ + __get8_unaligned_check(ins,v,a,err); \ + val |= v << 16; \ + __get8_unaligned_check(ins,v,a,err); \ + val |= v << 24; \ if (err) \ goto fault; \ } while (0) -#define put16_unaligned_check(val,addr) \ +#define get32_unaligned_check(val,addr) \ + __get32_unaligned_check("ldrb",val,addr) + +#define get32t_unaligned_check(val,addr) \ + __get32_unaligned_check("ldrbt",val,addr) + +#define __put16_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v = val, a = addr; \ __asm__( \ - "1: strb %1, [%2], #1\n" \ + "1: "ins" %1, [%2], #1\n" \ " mov %1, %1, lsr #8\n" \ - "2: strb %1, [%2]\n" \ + "2: "ins" %1, [%2]\n" \ "3:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -229,6 +243,12 @@ goto fault; \ } while (0) +#define put16_unaligned_check(val,addr) \ + __put16_unaligned_check("strb",val,addr) + +#define put16t_unaligned_check(val,addr) \ + __put16_unaligned_check("strbt",val,addr) + #define __put32_unaligned_check(ins,val,addr) \ do { \ unsigned int err = 0, v = val, a = addr; \ @@ -259,37 +279,9 @@ goto fault; \ } while (0) -#define get32_unaligned_check(val,addr) \ - do { \ - unsigned int err = 0, v, a = addr; \ - get8_unaligned_check(val,a,err); \ - get8_unaligned_check(v,a,err); \ - val |= v << 8; \ - get8_unaligned_check(v,a,err); \ - val |= v << 16; \ - get8_unaligned_check(v,a,err); \ - val |= v << 24; \ - if (err) \ - goto fault; \ - } while (0) - #define put32_unaligned_check(val,addr) \ __put32_unaligned_check("strb", val, addr) -#define get32t_unaligned_check(val,addr) \ - do { \ - unsigned int err = 0, v, a = addr; \ - get8t_unaligned_check(val,a,err); \ - get8t_unaligned_check(v,a,err); \ - val |= v << 8; \ - get8t_unaligned_check(v,a,err); \ - val |= v << 16; \ - get8t_unaligned_check(v,a,err); \ - val |= v << 24; \ - if (err) \ - goto fault; \ - } while (0) - #define put32t_unaligned_check(val,addr) \ __put32_unaligned_check("strbt", val, addr) @@ -319,6 +311,9 @@ ai_half += 1; + if (user_mode(regs)) + goto user; + if (LDST_L_BIT(instr)) { unsigned long val; get16_unaligned_check(val, addr); @@ -333,12 +328,27 @@ return TYPE_LDST; -swp: + user: + if (LDST_L_BIT(instr)) { + unsigned long val; + get16t_unaligned_check(val, addr); + + /* signed half-word? */ + if (instr & 0x40) + val = (signed long)((signed short) val); + + regs->uregs[rd] = val; + } else + put16t_unaligned_check(regs->uregs[rd], addr); + + return TYPE_LDST; + + swp: printk(KERN_ERR "Alignment trap: not handling swp instruction\n"); -bad: + bad: return TYPE_ERROR; -fault: + fault: return TYPE_FAULT; } @@ -349,23 +359,27 @@ ai_word += 1; - if (!LDST_P_BIT(instr) && LDST_W_BIT(instr)) + if ((!LDST_P_BIT(instr) && LDST_W_BIT(instr)) || user_mode(regs)) goto trans; - if (LDST_L_BIT(instr)) - get32_unaligned_check(regs->uregs[rd], addr); - else + if (LDST_L_BIT(instr)) { + unsigned int val; + get32_unaligned_check(val, addr); + regs->uregs[rd] = val; + } else put32_unaligned_check(regs->uregs[rd], addr); return TYPE_LDST; -trans: - if (LDST_L_BIT(instr)) - get32t_unaligned_check(regs->uregs[rd], addr); - else + trans: + if (LDST_L_BIT(instr)) { + unsigned int val; + get32t_unaligned_check(val, addr); + regs->uregs[rd] = val; + } else put32t_unaligned_check(regs->uregs[rd], addr); return TYPE_LDST; -fault: + fault: return TYPE_FAULT; } @@ -431,14 +445,31 @@ } #endif - for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1) - if (regbits & 1) { - if (LDST_L_BIT(instr)) - get32_unaligned_check(regs->uregs[rd], eaddr); - else - put32_unaligned_check(regs->uregs[rd], eaddr); - eaddr += 4; - } + if (user_mode(regs)) { + for (regbits = REGMASK_BITS(instr), rd = 0; regbits; + regbits >>= 1, rd += 1) + if (regbits & 1) { + if (LDST_L_BIT(instr)) { + unsigned int val; + get32t_unaligned_check(val, eaddr); + regs->uregs[rd] = val; + } else + put32t_unaligned_check(regs->uregs[rd], eaddr); + eaddr += 4; + } + } else { + for (regbits = REGMASK_BITS(instr), rd = 0; regbits; + regbits >>= 1, rd += 1) + if (regbits & 1) { + if (LDST_L_BIT(instr)) { + unsigned int val; + get32_unaligned_check(val, eaddr); + regs->uregs[rd] = val; + } else + put32_unaligned_check(regs->uregs[rd], eaddr); + eaddr += 4; + } + } if (LDST_W_BIT(instr)) regs->uregs[rn] = newaddr; @@ -539,7 +570,7 @@ return 0; -bad_or_fault: + bad_or_fault: if (type == TYPE_ERROR) goto bad; regs->ARM_pc -= 4; @@ -549,7 +580,7 @@ do_bad_area(current, current->mm, addr, error_code, regs); return 0; -bad: + bad: /* * Oops, we didn't handle the instruction. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/armv4-early-abort.S linux-2.5/arch/arm/mm/armv4-early-abort.S --- linux-2.5.5/arch/arm/mm/armv4-early-abort.S Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/arm/mm/armv4-early-abort.S Thu Jan 1 00:00:00 1970 @@ -1,29 +0,0 @@ -#include -#include -/* - * Function: armv4_early_abort - * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR - * - * Returns : r0 = address of abort - * : r1 = FSR, bit 8 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers - * - * Purpose : obtain information about current aborted instruction. - * Note: we read user space. This means we might cause a data - * abort here if the I-TLB and D-TLB aren't seeing the same - * picture. Unfortunately, this does happen. We live with it. - */ - .align 5 -ENTRY(armv4_early_abort) - mrc p15, 0, r1, c5, c0, 0 @ get FSR - mrc p15, 0, r0, c6, c0, 0 @ get FAR - ldr r3, [r2] @ read aborted ARM instruction - tst r3, #1 << 20 @ L = 1 -> write? - orreq r1, r1, #1 << 8 @ yes. - mov pc, lr - - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/armv4t-early-abort.S linux-2.5/arch/arm/mm/armv4t-early-abort.S --- linux-2.5.5/arch/arm/mm/armv4t-early-abort.S Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/mm/armv4t-early-abort.S Thu Jan 1 00:00:00 1970 @@ -1,31 +0,0 @@ -#include -#include -/* - * Function: armv4t_early_abort - * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR - * - * Returns : r0 = address of abort - * : r1 = FSR, bit 8 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers - * - * Purpose : obtain information about current aborted instruction. - * Note: we read user space. This means we might cause a data - * abort here if the I-TLB and D-TLB aren't seeing the same - * picture. Unfortunately, this does happen. We live with it. - */ - .align 5 -ENTRY(armv4t_early_abort) - mrc p15, 0, r1, c5, c0, 0 @ get FSR - mrc p15, 0, r0, c6, c0, 0 @ get FAR - tst r3, #PSR_T_BIT - ldrneh r3, [r2] @ read aborted thumb instruction - ldreq r3, [r2] @ read aborted ARM instruction - bic r1, r1, #1 << 8 - movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 - tst r3, #1 << 20 @ check write - orreq r1, r1, #1 << 8 - mov pc, lr diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/armv4t-late-abort.S linux-2.5/arch/arm/mm/armv4t-late-abort.S --- linux-2.5.5/arch/arm/mm/armv4t-late-abort.S Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/arm/mm/armv4t-late-abort.S Thu Jan 1 00:00:00 1970 @@ -1,224 +0,0 @@ -#include -#include -/* - * Function: armv4t_late_abort - * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR - * - * Returns : r0 = address of abort - * : r1 = FSR, bit 8 = writing - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers - * - * Purpose : obtain information about current aborted instruction. - * Note: we read user space. This means we might cause a data - * abort here if the I-TLB and D-TLB aren't seeing the same - * picture. Unfortunately, this does happen. We live with it. - */ -ENTRY(armv4t_late_abort) - tst r3, #PSR_T_BIT @ check for thumb mode - mrc p15, 0, r1, c5, c0, 0 @ get FSR - mrc p15, 0, r0, c6, c0, 0 @ get FAR - ldreq r8, [r2] @ read arm instruction - bne .data_thumb_abort - tst r8, #1 << 20 @ L = 1 -> write? - orreq r1, r1, #1 << 8 @ yes. - and r7, r8, #15 << 24 - add pc, pc, r7, lsr #22 @ Now branch to the relevant processing routine - nop - -/* 0 */ b .data_arm_lateldrhpost @ ldrh rd, [rn], #m/rm -/* 1 */ b .data_arm_lateldrhpre @ ldrh rd, [rn, #m/rm] -/* 2 */ b .data_unknown -/* 3 */ b .data_unknown -/* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m -/* 5 */ b .data_arm_lateldrpreconst @ ldr rd, [rn, #m] -/* 6 */ b .data_arm_lateldrpostreg @ ldr rd, [rn], rm -/* 7 */ b .data_arm_lateldrprereg @ ldr rd, [rn, rm] -/* 8 */ b .data_arm_ldmstm @ ldm*a rn, -/* 9 */ b .data_arm_ldmstm @ ldm*b rn, -/* a */ b .data_unknown -/* b */ b .data_unknown -/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m -/* d */ mov pc, lr @ ldc rd, [rn, #m] -/* e */ b .data_unknown -/* f */ -.data_unknown: @ Part of jumptable - mov r0, r2 - mov r1, r8 - mov r2, sp - bl baddataabort - b ret_from_exception - -.data_arm_ldmstm: - tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup - mov r7, #0x11 - orr r7, r7, #0x1100 - and r6, r8, r7 - and r2, r8, r7, lsl #1 - add r6, r6, r2, lsr #1 - and r2, r8, r7, lsl #2 - add r6, r6, r2, lsr #2 - and r2, r8, r7, lsl #3 - add r6, r6, r2, lsr #3 - add r6, r6, r6, lsr #8 - add r6, r6, r6, lsr #4 - and r6, r6, #15 @ r7 = no. of registers to transfer. - and r5, r8, #15 << 16 @ Extract 'n' form instruction - ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' - tst r8, #1 << 23 @ Check U bit - subne r7, r7, r6, lsl #2 @ Undo increment - addeq r7, r7, r6, lsl #2 @ Undo decrement - str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr - -.data_arm_lateldrhpre: - tst r8, #1 << 21 @ Check writeback bit - moveq pc, lr @ No writeback -> no fixup -.data_arm_lateldrhpost: - and r5, r8, #0x00f @ get Rm / low nibble of immediate value - tst r8, #1 << 22 @ if (immediate offset) - andne r6, r8, #0xf00 @ { immediate high nibble - orrne r6, r5, r6, lsr #4 @ combine nibbles } else - ldreq r6, [sp, r5, lsl #2] @ { load Rm value } -.data_arm_apply_r6_and_rn: - and r5, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' - tst r8, #1 << 23 @ Check U bit - subne r7, r7, r6 @ Undo incrmenet - addeq r7, r7, r6 @ Undo decrement - str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr - -.data_arm_lateldrpreconst: - tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup -.data_arm_lateldrpostconst: - movs r2, r8, lsl #20 @ Get offset - moveq pc, lr @ zero -> no fixup - and r5, r8, #15 << 16 @ Extract 'n' from instruction - ldr r7, [sp, r5, lsr #14] @ Get register 'Rn' - tst r8, #1 << 23 @ Check U bit - subne r7, r7, r2, lsr #20 @ Undo increment - addeq r7, r7, r2, lsr #20 @ Undo decrement - str r7, [sp, r5, lsr #14] @ Put register 'Rn' - mov pc, lr - -.data_arm_lateldrprereg: - tst r8, #1 << 21 @ check writeback bit - moveq pc, lr @ no writeback -> no fixup -.data_arm_lateldrpostreg: - and r7, r8, #15 @ Extract 'm' from instruction - ldr r6, [sp, r7, lsl #2] @ Get register 'Rm' - mov r5, r8, lsr #7 @ get shift count - ands r5, r5, #31 - and r7, r8, #0x70 @ get shift type - orreq r7, r7, #8 @ shift count = 0 - add pc, pc, r7 - nop - - mov r6, r6, lsl r5 @ 0: LSL #!0 - b .data_arm_apply_r6_and_rn - b .data_arm_apply_r6_and_rn @ 1: LSL #0 - nop - b .data_unknown @ 2: MUL? - nop - b .data_unknown @ 3: MUL? - nop - mov r6, r6, lsr r5 @ 4: LSR #!0 - b .data_arm_apply_r6_and_rn - mov r6, r6, lsr #32 @ 5: LSR #32 - b .data_arm_apply_r6_and_rn - b .data_unknown @ 6: MUL? - nop - b .data_unknown @ 7: MUL? - nop - mov r6, r6, asr r5 @ 8: ASR #!0 - b .data_arm_apply_r6_and_rn - mov r6, r6, asr #32 @ 9: ASR #32 - b .data_arm_apply_r6_and_rn - b .data_unknown @ A: MUL? - nop - b .data_unknown @ B: MUL? - nop - mov r6, r6, ror r5 @ C: ROR #!0 - b .data_arm_apply_r6_and_rn - mov r6, r6, rrx @ D: RRX - b .data_arm_apply_r6_and_rn - b .data_unknown @ E: MUL? - nop - b .data_unknown @ F: MUL? - -.data_thumb_abort: - ldrh r8, [r2] @ read instruction - tst r8, #1 << 11 @ L = 1 -> write? - orreq r1, r1, #1 << 8 @ yes - and r7, r8, #15 << 12 - add pc, pc, r7, lsr #10 @ lookup in table - nop - -/* 0 */ b .data_unknown -/* 1 */ b .data_unknown -/* 2 */ b .data_unknown -/* 3 */ b .data_unknown -/* 4 */ b .data_unknown -/* 5 */ b .data_thumb_reg -/* 6 */ mov pc, lr -/* 7 */ mov pc, lr -/* 8 */ mov pc, lr -/* 9 */ mov pc, lr -/* A */ b .data_unknown -/* B */ b .data_thumb_pushpop -/* C */ b .data_thumb_ldmstm -/* D */ b .data_unknown -/* E */ b .data_unknown -/* F */ b .data_unknown - -.data_thumb_reg: - tst r8, #1 << 9 - moveq pc, lr - tst r8, #1 << 10 @ If 'S' (signed) bit is set - movne r1, #0 @ it must be a load instr - mov pc, lr - -.data_thumb_pushpop: - tst r8, #1 << 10 - beq .data_unknown - mov r7, #0x11 - and r6, r8, r7 - and r2, r8, r7, lsl #1 - add r6, r6, r2, lsr #1 - and r2, r8, r7, lsl #2 - add r6, r6, r2, lsr #2 - and r2, r8, r7, lsl #3 - add r6, r6, r2, lsr #3 - add r6, r6, r6, lsr #4 - and r2, r8, #0x0100 @ catch 'R' bit for push/pop - add r6, r6, r2, lsr #8 - and r6, r6, #15 @ number of regs to transfer - ldr r7, [sp, #13 << 2] - tst r8, #1 << 11 - addne r7, r7, r6, lsl #2 @ increment SP if PUSH - subeq r7, r7, r6, lsr #2 @ decrement SP if POP - str r7, [sp, #13 << 2] - mov pc, lr - -.data_thumb_ldmstm: - mov r7, #0x11 - and r6, r8, r7 - and r2, r8, r7, lsl #1 - add r6, r6, r2, lsr #1 - and r2, r8, r7, lsl #2 - add r6, r6, r2, lsr #2 - and r2, r8, r7, lsl #3 - add r6, r6, r2, lsr #3 - add r6, r6, r6, lsr #4 - and r6, r6, #15 @ number of regs to transfer - and r5, r8, #7 << 8 - ldr r7, [sp, r5, lsr #6] - sub r7, r7, r6, lsr #2 @ always decrement - str r7, [sp, r5, lsr #6] - mov pc, lr diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/armv5ej-early-abort.S linux-2.5/arch/arm/mm/armv5ej-early-abort.S --- linux-2.5.5/arch/arm/mm/armv5ej-early-abort.S Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/mm/armv5ej-early-abort.S Thu Jan 1 00:00:00 1970 @@ -1,35 +0,0 @@ -#include -#include -/* - * Function: armv5ej_early_abort - * - * Params : r2 = address of aborted instruction - * : r3 = saved SPSR - * - * Returns : r0 = address of abort - * : r1 = FSR, bit 8 = write - * : r2-r8 = corrupted - * : r9 = preserved - * : sp = pointer to registers - * - * Purpose : obtain information about current aborted instruction. - * Note: we read user space. This means we might cause a data - * abort here if the I-TLB and D-TLB aren't seeing the same - * picture. Unfortunately, this does happen. We live with it. - */ - .align 5 -ENTRY(armv5ej_early_abort) - mrc p15, 0, r1, c5, c0, 0 @ get FSR - mrc p15, 0, r0, c6, c0, 0 @ get FAR - tst r3, #PSR_J_BIT - orrne r1, r1, #1 << 8 @ always assume write - bne 1f - tst r3, #PSR_T_BIT - ldrneh r3, [r2] @ read aborted thumb instruction - ldreq r3, [r2] @ read aborted ARM instruction - movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 - tst r2, #1 << 20 @ L = 1 -> write - orreq r1, r1, #1 << 8 @ yes. -1: mov pc, lr - - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/copypage-v3.S linux-2.5/arch/arm/mm/copypage-v3.S --- linux-2.5.5/arch/arm/mm/copypage-v3.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/copypage-v3.S Fri Mar 1 15:07:37 2002 @@ -0,0 +1,59 @@ +/* + * linux/arch/arm/lib/copypage.S + * + * Copyright (C) 1995-1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ASM optimised string functions + */ +#include +#include +#include + + .text + .align 5 +/* + * ARMv3 optimised copy_user_page + * + * FIXME: do we need to handle cache stuff... + */ +ENTRY(armv3_copy_user_page) + stmfd sp!, {r4, lr} @ 2 + mov r2, #PAGE_SZ/64 @ 1 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 +1: stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4 + subs r2, r2, #1 @ 1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmneia r1!, {r3, r4, ip, lr} @ 4 + bne 1b @ 1 + LOADREGS(fd, sp!, {r4, pc}) @ 3 + + .align 5 +/* + * ARMv3 optimised clear_user_page + * + * FIXME: do we need to handle cache stuff... + */ +ENTRY(armv3_clear_user_page) + str lr, [sp, #-4]! + mov r1, #PAGE_SZ/64 @ 1 + mov r2, #0 @ 1 + mov r3, #0 @ 1 + mov ip, #0 @ 1 + mov lr, #0 @ 1 +1: stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + subs r1, r1, #1 @ 1 + bne 1b @ 1 + ldr pc, [sp], #4 + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/copypage-v4.S linux-2.5/arch/arm/mm/copypage-v4.S --- linux-2.5.5/arch/arm/mm/copypage-v4.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/copypage-v4.S Fri Mar 1 15:07:37 2002 @@ -0,0 +1,70 @@ +/* + * linux/arch/arm/lib/copypage.S + * + * Copyright (C) 1995-1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ASM optimised string functions + */ +#include +#include + + .text + .align 5 +/* + * ARMv4 optimised copy_user_page + * + * We flush the destination cache lines just before we write the data into the + * corresponding address. Since the Dcache is read-allocate, this removes the + * Dcache aliasing issue. The writes will be forwarded to the write buffer, + * and merged as appropriate. + * + * Note: We rely on all ARMv4 processors implementing the "invalidate D line" + * instruction. If your processor does not supply this, you have to write your + * own copy_user_page that does the right thing. + */ +ENTRY(armv4_copy_user_page) + stmfd sp!, {r4, lr} @ 2 + mov r2, #PAGE_SZ/64 @ 1 + ldmia r1!, {r3, r4, ip, lr} @ 4 +1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4 + mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4 + subs r2, r2, #1 @ 1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmneia r1!, {r3, r4, ip, lr} @ 4 + bne 1b @ 1 + mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB + ldmfd sp!, {r4, pc} @ 3 + + .align 5 +/* + * ARMv4 optimised clear_user_page + * + * Same story as above. + */ +ENTRY(armv4_clear_user_page) + str lr, [sp, #-4]! + mov r1, #PAGE_SZ/64 @ 1 + mov r2, #0 @ 1 + mov r3, #0 @ 1 + mov ip, #0 @ 1 + mov lr, #0 @ 1 +1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + subs r1, r1, #1 @ 1 + bne 1b @ 1 + mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB + ldr pc, [sp], #4 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/copypage-v4mc.S linux-2.5/arch/arm/mm/copypage-v4mc.S --- linux-2.5.5/arch/arm/mm/copypage-v4mc.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/copypage-v4mc.S Fri Mar 1 15:07:37 2002 @@ -0,0 +1,71 @@ +/* + * linux/arch/arm/lib/copy_page-armv4mc.S + * + * Copyright (C) 1995-2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ASM optimised string functions + */ +#include +#include + + .text + .align 5 +/* + * ARMv4 mini-dcache optimised copy_user_page + * + * We flush the destination cache lines just before we write the data into the + * corresponding address. Since the Dcache is read-allocate, this removes the + * Dcache aliasing issue. The writes will be forwarded to the write buffer, + * and merged as appropriate. + * + * Note: We rely on all ARMv4 processors implementing the "invalidate D line" + * instruction. If your processor does not supply this, you have to write your + * own copy_user_page that does the right thing. + */ +ENTRY(armv4_mc_copy_user_page) + stmfd sp!, {r4, lr} @ 2 + mov r4, r0 + mov r0, r1 + bl map_page_minicache + mov r1, #PAGE_SZ/64 @ 1 + ldmia r0!, {r2, r3, ip, lr} @ 4 +1: mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line + stmia r4!, {r2, r3, ip, lr} @ 4 + ldmia r0!, {r2, r3, ip, lr} @ 4+1 + stmia r4!, {r2, r3, ip, lr} @ 4 + ldmia r0!, {r2, r3, ip, lr} @ 4 + mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line + stmia r4!, {r2, r3, ip, lr} @ 4 + ldmia r0!, {r2, r3, ip, lr} @ 4 + subs r1, r1, #1 @ 1 + stmia r4!, {r2, r3, ip, lr} @ 4 + ldmneia r0!, {r2, r3, ip, lr} @ 4 + bne 1b @ 1 + ldmfd sp!, {r4, pc} @ 3 + + .align 5 +/* + * ARMv4 optimised clear_user_page + * + * Same story as above. + */ +ENTRY(armv4_mc_clear_user_page) + str lr, [sp, #-4]! + mov r1, #PAGE_SZ/64 @ 1 + mov r2, #0 @ 1 + mov r3, #0 @ 1 + mov ip, #0 @ 1 + mov lr, #0 @ 1 +1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + subs r1, r1, #1 @ 1 + bne 1b @ 1 + ldr pc, [sp], #4 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/copypage-v5te.S linux-2.5/arch/arm/mm/copypage-v5te.S --- linux-2.5.5/arch/arm/mm/copypage-v5te.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/copypage-v5te.S Fri Mar 1 15:07:37 2002 @@ -0,0 +1,79 @@ +/* + * linux/arch/arm/lib/copypage-armv5te.S + * + * Copyright (C) 2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + +/* + * General note: + * We don't really want write-allocate cache behaviour for these functions + * since that will just eat through 8K of the cache. + */ + + .text + .align 5 +/* + * ARMv5TE optimised copy_user_page + * r0 = destination + * r1 = source + * r2 = virtual user address of ultimate destination page + * + * The source page may have some clean entries in the cache already, but we + * can safely ignore them - break_cow() will flush them out of the cache + * if we eventually end up using our copied page. + * + * What we could do is use the mini-cache to buffer reads from the source + * page. We rely on the mini-cache being smaller than one page, so we'll + * cycle through the complete cache anyway. + */ +ENTRY(armv5te_copy_user_page) + stmfd sp!, {r4, r5, lr} + mov r5, r0 + mov r0, r1 + bl map_page_minicache + mov r1, r5 + mov lr, #PAGE_SZ/32 + +1: mov ip, r1 + ldrd r2, [r0], #8 + ldrd r4, [r0], #8 + strd r2, [r1], #8 + ldrd r2, [r0], #8 + strd r4, [r1], #8 + ldrd r4, [r0], #8 + strd r2, [r1], #8 + strd r4, [r1], #8 + mcr p15, 0, ip, c7, c10, 1 @ clean D line + mcr p15, 0, ip, c7, c6, 1 @ invalidate D line + subs lr, lr, #1 + bne 1b + + ldmfd sp!, {r4, r5, pc} + + .align 5 +/* + * ARMv5TE optimised clear_user_page + * r0 = destination + * r1 = virtual user address of ultimate destination page + */ +ENTRY(armv5te_clear_user_page) + str lr, [sp, #-4]! + mov r1, #PAGE_SZ/32 + mov r2, #0 + mov r3, #0 +1: mov ip, r0 + strd r2, [r0], #8 + strd r2, [r0], #8 + strd r2, [r0], #8 + strd r2, [r0], #8 + mcr p15, 0, ip, c7, c10, 1 @ clean D line + mcr p15, 0, ip, c7, c6, 1 @ invalidate D line + subs r1, r1, #1 + bne 1b + ldr pc, [sp], #4 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/fault-armv.c linux-2.5/arch/arm/mm/fault-armv.c --- linux-2.5.5/arch/arm/mm/fault-armv.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/arm/mm/fault-armv.c Fri Mar 1 15:07:37 2002 @@ -116,7 +116,7 @@ if (!inf->fn(addr, fsr, regs)) return; - printk(KERN_ALERT "Unhandled fault: %s (%X) at 0x%08lx\n", + printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", inf->name, fsr, addr); force_sig(inf->sig, current); show_pte(current->mm, addr); @@ -177,38 +177,13 @@ return; } -/* - * Take care of architecture specific things when placing a new PTE into - * a page table, or changing an existing PTE. Basically, there are two - * things that we need to take care of: - * - * 1. If PG_dcache_dirty is set for the page, we need to ensure - * that any cache entries for the kernels virtual memory - * range are written back to the page. - * 2. If we have multiple shared mappings of the same space in - * an object, we need to deal with the cache aliasing issues. - * - * Note that the page_table_lock will be held. - */ -void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) +static void +make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page) { - struct page *page = pte_page(pte); struct vm_area_struct *mpnt; - struct mm_struct *mm; - unsigned long pgoff; - int aliases; - - if (!VALID_PAGE(page) || !page->mapping) - return; - - if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) { - unsigned long kvirt = (unsigned long)page_address(page); - cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0); - } - - mm = vma->vm_mm; - pgoff = (addr - vma->vm_start) >> PAGE_SHIFT; - aliases = 0; + struct mm_struct *mm = vma->vm_mm; + unsigned long pgoff = (addr - vma->vm_start) >> PAGE_SHIFT; + int aliases = 0; /* * If we have any shared mappings that are in the same mm @@ -245,4 +220,31 @@ } if (aliases) adjust_pte(vma, addr); +} + +/* + * Take care of architecture specific things when placing a new PTE into + * a page table, or changing an existing PTE. Basically, there are two + * things that we need to take care of: + * + * 1. If PG_dcache_dirty is set for the page, we need to ensure + * that any cache entries for the kernels virtual memory + * range are written back to the page. + * 2. If we have multiple shared mappings of the same space in + * an object, we need to deal with the cache aliasing issues. + * + * Note that the page_table_lock will be held. + */ +void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) +{ + struct page *page = pte_page(pte); + + if (VALID_PAGE(page) && page->mapping) { + if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) { + unsigned long kvirt = (unsigned long)page_address(page); + cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0); + } + + make_coherent(vma, addr, page); + } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/fault-common.c linux-2.5/arch/arm/mm/fault-common.c --- linux-2.5.5/arch/arm/mm/fault-common.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/arch/arm/mm/fault-common.c Fri Mar 1 15:07:37 2002 @@ -138,9 +138,10 @@ struct siginfo si; #ifdef CONFIG_DEBUG_USER - printk(KERN_DEBUG "%s: unhandled page fault at pc=0x%08lx, " - "lr=0x%08lx (bad address=0x%08lx, code %d)\n", - tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, error_code); + printk(KERN_DEBUG "%s: unhandled page fault at 0x%08lx, code 0x%03x\n", + tsk->comm, addr, error_code); + show_pte(tsk->mm, addr); + show_regs(regs); #endif tsk->thread.address = addr; @@ -224,8 +225,7 @@ * If we are out of memory for pid1, * sleep for a while and retry */ - tsk->policy |= SCHED_YIELD; - schedule(); + yield(); goto survive; check_stack: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/minicache.c linux-2.5/arch/arm/mm/minicache.c --- linux-2.5.5/arch/arm/mm/minicache.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/mm/minicache.c Fri Mar 1 15:07:37 2002 @@ -16,9 +16,14 @@ #include #include #include +#include #include -#define minicache_address (0xffff2000) +/* + * 0xffff8000 to 0xffffffff is reserved for any ARM architecture + * specific hacks for copying pages efficiently. + */ +#define minicache_address (0xffff8000) #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \ L_PTE_CACHEABLE) @@ -39,7 +44,7 @@ unsigned long map_page_minicache(unsigned long virt) { set_pte(minicache_pte, mk_pte_phys(__pa(virt), minicache_pgprot)); - cpu_tlb_invalidate_page(minicache_address, 0); + flush_kern_tlb_page(minicache_address); return minicache_address; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/proc-arm1020.S linux-2.5/arch/arm/mm/proc-arm1020.S --- linux-2.5.5/arch/arm/mm/proc-arm1020.S Wed Feb 20 02:10:54 2002 +++ linux-2.5/arch/arm/mm/proc-arm1020.S Fri Mar 1 15:07:37 2002 @@ -420,71 +420,6 @@ #endif mov pc, lr -/* ================================== TLB ================================= */ - -/* - * cpu_arm1020_tlb_invalidate_all() - * - * Invalidate all TLB entries - */ - .align 5 -ENTRY(cpu_arm1020_tlb_invalidate_all) - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c8, c7, 0 @ invalidate I & D tlbs -#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION - mov r0, r0 - mov r0, r0 -#endif - mov pc, lr - -/* - * cpu_arm1020_tlb_invalidate_range(start, end) - * - * invalidate TLB entries covering the specified range - * - * start: range start address - * end: range end address - */ - .align 5 -ENTRY(cpu_arm1020_tlb_invalidate_range) - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB -1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - add r0, r0, #PAGESIZE -#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION - mov r0, r0 -#endif - cmp r0, r1 - blt 1b - mov pc, lr - -/* - * cpu_arm1020_tlb_invalidate_page(page, flags) - * - * invalidate the TLB entries for the specified page. - * - * page: page to invalidate - * flags: non-zero if we include the I TLB - */ - .align 5 -ENTRY(cpu_arm1020_tlb_invalidate_page) - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB -#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION - mov r0, r0 - mov r0, r0 -#endif - teq r1, #0 - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry -#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION - mov r0, r0 - mov r0, r0 -#endif - mov pc, lr - /* =============================== PageTable ============================== */ /* @@ -695,11 +630,6 @@ .word cpu_arm1020_icache_invalidate_range .word cpu_arm1020_icache_invalidate_page - /* tlb */ - .word cpu_arm1020_tlb_invalidate_all - .word cpu_arm1020_tlb_invalidate_range - .word cpu_arm1020_tlb_invalidate_page - /* pgtable */ .word cpu_arm1020_set_pgd .word cpu_arm1020_set_pmd @@ -741,4 +671,5 @@ .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT .long cpu_arm1020_info .long arm1020_processor_functions + .long v4wbi_tlb_fns .size __arm1020_proc_info, . - __arm1020_proc_info diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/proc-arm2,3.S linux-2.5/arch/arm/mm/proc-arm2,3.S --- linux-2.5.5/arch/arm/mm/proc-arm2,3.S Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/mm/proc-arm2,3.S Fri Mar 1 15:07:37 2002 @@ -341,6 +341,7 @@ .long 0 .long cpu_arm2_info .long SYMBOL_NAME(arm2_processor_functions) + .long 0 .long 0x41560250 .long 0xfffffff0 @@ -351,6 +352,7 @@ .long 0 .long cpu_arm250_info .long SYMBOL_NAME(arm250_processor_functions) + .long 0 .long 0x41560300 .long 0xfffffff0 @@ -361,4 +363,4 @@ .long 0 .long cpu_arm3_info .long SYMBOL_NAME(arm3_processor_functions) - + .long 0 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/proc-arm6,7.S linux-2.5/arch/arm/mm/proc-arm6,7.S --- linux-2.5.5/arch/arm/mm/proc-arm6,7.S Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/arm/mm/proc-arm6,7.S Fri Mar 1 15:07:37 2002 @@ -48,47 +48,6 @@ mov pc, lr /* - * Function: arm6_7_tlb_invalidate_all (void) - * - * Purpose : flush all TLB entries in all caches - */ -ENTRY(cpu_arm6_tlb_invalidate_all) -ENTRY(cpu_arm7_tlb_invalidate_all) - mov r0, #0 - mcr p15, 0, r0, c5, c0, 0 @ flush TLB - mov pc, lr - -/* - * Function: arm6_7_tlb_invalidate_page (unsigned long address, int end, int flags) - * - * Params : address Area start address - * : end Area end address - * : flags b0 = I cache as well - * - * Purpose : flush a TLB entry - */ -ENTRY(cpu_arm6_tlb_invalidate_range) -ENTRY(cpu_arm7_tlb_invalidate_range) -1: mcr p15, 0, r0, c6, c0, 0 @ flush TLB - add r0, r0, #4096 - cmp r0, r1 - blt 1b - mov pc, lr - -/* - * Function: arm6_7_tlb_invalidate_page (unsigned long address, int flags) - * - * Params : address Address - * : flags b0 = I-TLB as well - * - * Purpose : flush a TLB entry - */ -ENTRY(cpu_arm6_tlb_invalidate_page) -ENTRY(cpu_arm7_tlb_invalidate_page) - mcr p15, 0, r0, c6, c0, 0 @ flush TLB - mov pc, lr - -/* * Function: arm6_7_data_abort () * * Params : r0 = address of aborted instruction @@ -409,11 +368,6 @@ .word cpu_arm6_icache_invalidate_range .word cpu_arm6_icache_invalidate_page - /* tlb */ - .word cpu_arm6_tlb_invalidate_all - .word cpu_arm6_tlb_invalidate_range - .word cpu_arm6_tlb_invalidate_page - /* pgtable */ .word cpu_arm6_set_pgd .word cpu_arm6_set_pmd @@ -453,11 +407,6 @@ .word cpu_arm7_icache_invalidate_range .word cpu_arm7_icache_invalidate_page - /* tlb */ - .word cpu_arm7_tlb_invalidate_all - .word cpu_arm7_tlb_invalidate_range - .word cpu_arm7_tlb_invalidate_page - /* pgtable */ .word cpu_arm7_set_pgd .word cpu_arm7_set_pmd @@ -515,6 +464,7 @@ .long HWCAP_SWP | HWCAP_26BIT .long cpu_arm6_info .long arm6_processor_functions + .long v3_tlb_fns .size __arm6_proc_info, . - __arm6_proc_info .type __arm610_proc_info, #object @@ -528,6 +478,7 @@ .long HWCAP_SWP | HWCAP_26BIT .long cpu_arm610_info .long arm6_processor_functions + .long v3_tlb_fns .size __arm610_proc_info, . - __arm610_proc_info .type __arm7_proc_info, #object @@ -541,6 +492,7 @@ .long HWCAP_SWP | HWCAP_26BIT .long cpu_arm7_info .long arm7_processor_functions + .long v3_tlb_fns .size __arm7_proc_info, . - __arm7_proc_info .type __arm710_proc_info, #object @@ -554,4 +506,5 @@ .long HWCAP_SWP | HWCAP_26BIT .long cpu_arm710_info .long arm7_processor_functions + .long v3_tlb_fns .size __arm710_proc_info, . - __arm710_proc_info diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/proc-arm720.S linux-2.5/arch/arm/mm/proc-arm720.S --- linux-2.5.5/arch/arm/mm/proc-arm720.S Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/arm/mm/proc-arm720.S Fri Mar 1 15:07:37 2002 @@ -67,44 +67,6 @@ mov pc, lr /* - * Function: arm720_tlb_invalidate_all (void) - * - * Purpose : flush all TLB entries in all caches - */ -ENTRY(cpu_arm720_tlb_invalidate_all) - mov r0, #0 - mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4) - mov pc, lr - -/* - * Function: arm720_tlb_invalidate_page (unsigned long address, int end, int flags) - * - * Params : address Area start address - * : end Area end address - * : flags b0 = I cache as well - * - * Purpose : flush a TLB entry - */ -ENTRY(cpu_arm720_tlb_invalidate_range) -1: mcr p15, 0, r0, c8, c7, 1 @ flush TLB (v4) - add r0, r0, #4096 - cmp r0, r1 - blt 1b - mov pc, lr - -/* - * Function: arm720_tlb_invalidate_page (unsigned long address, int flags) - * - * Params : address Address - * : flags b0 = I-TLB as well - * - * Purpose : flush a TLB entry - */ -ENTRY(cpu_arm720_tlb_invalidate_page) - mcr p15, 0, r0, c8, c7, 1 @ flush TLB (v4) - mov pc, lr - -/* * Function: arm720_check_bugs (void) * : arm720_proc_init (void) * : arm720_proc_fin (void) @@ -259,11 +221,6 @@ .word cpu_arm720_icache_invalidate_range .word cpu_arm720_icache_invalidate_page - /* tlb */ - .word cpu_arm720_tlb_invalidate_all - .word cpu_arm720_tlb_invalidate_range - .word cpu_arm720_tlb_invalidate_page - /* pgtable */ .word cpu_arm720_set_pgd .word cpu_arm720_set_pmd @@ -307,4 +264,5 @@ .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_26BIT @ elf_hwcap .long cpu_arm720_info @ info .long arm720_processor_functions + .long v4_tlb_fns .size __arm720_proc_info, . - __arm720_proc_info diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/proc-arm920.S linux-2.5/arch/arm/mm/proc-arm920.S --- linux-2.5.5/arch/arm/mm/proc-arm920.S Wed Feb 20 02:10:54 2002 +++ linux-2.5/arch/arm/mm/proc-arm920.S Fri Mar 1 15:07:37 2002 @@ -358,62 +358,6 @@ mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache mov pc, lr -/* ================================== TLB ================================= */ - -/* - * cpu_arm920_tlb_invalidate_all() - * - * Invalidate all TLB entries - */ - .align 5 -ENTRY(cpu_arm920_tlb_invalidate_all) - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c8, c7, 0 @ invalidate I & D TLBs - mov pc, lr - -/* - * cpu_arm920_tlb_invalidate_range(start, end) - * - * invalidate TLB entries covering the specified range - * - * start: range start address - * end: range end address - */ - .align 5 -ENTRY(cpu_arm920_tlb_invalidate_range) - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB - - mov r3, #PAGESIZE - sub r3, r3, #1 - bic r0, r0, r3 - bic r1, r1, r3 - -1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - add r0, r0, #PAGESIZE - cmp r0, r1 - blt 1b - mov pc, lr - -/* - * cpu_arm920_tlb_invalidate_page(page, flags) - * - * invalidate the TLB entries for the specified page. - * - * page: page to invalidate - * flags: non-zero if we include the I TLB - */ - .align 5 -ENTRY(cpu_arm920_tlb_invalidate_page) - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB - teq r1, #0 - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - mov pc, lr - /* =============================== PageTable ============================== */ /* @@ -589,11 +533,6 @@ .word cpu_arm920_icache_invalidate_range .word cpu_arm920_icache_invalidate_page - /* tlb */ - .word cpu_arm920_tlb_invalidate_all - .word cpu_arm920_tlb_invalidate_range - .word cpu_arm920_tlb_invalidate_page - /* pgtable */ .word cpu_arm920_set_pgd .word cpu_arm920_set_pmd @@ -635,4 +574,5 @@ .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT .long cpu_arm920_info .long arm920_processor_functions + .long v4wbi_tlb_fns .size __arm920_proc_info, . - __arm920_proc_info diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/proc-arm922.S linux-2.5/arch/arm/mm/proc-arm922.S --- linux-2.5.5/arch/arm/mm/proc-arm922.S Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/mm/proc-arm922.S Fri Mar 1 15:07:37 2002 @@ -359,62 +359,6 @@ mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache mov pc, lr -/* ================================== TLB ================================= */ - -/* - * cpu_arm922_tlb_invalidate_all() - * - * Invalidate all TLB entries - */ - .align 5 -ENTRY(cpu_arm922_tlb_invalidate_all) - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c8, c7, 0 @ invalidate I & D TLBs - mov pc, lr - -/* - * cpu_arm922_tlb_invalidate_range(start, end) - * - * invalidate TLB entries covering the specified range - * - * start: range start address - * end: range end address - */ - .align 5 -ENTRY(cpu_arm922_tlb_invalidate_range) - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB - - mov r3, #PAGESIZE - sub r3, r3, #1 - bic r0, r0, r3 - bic r1, r1, r3 - -1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - add r0, r0, #PAGESIZE - cmp r0, r1 - blt 1b - mov pc, lr - -/* - * cpu_arm922_tlb_invalidate_page(page, flags) - * - * invalidate the TLB entries for the specified page. - * - * page: page to invalidate - * flags: non-zero if we include the I TLB - */ - .align 5 -ENTRY(cpu_arm922_tlb_invalidate_page) - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB - teq r1, #0 - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - mov pc, lr - /* =============================== PageTable ============================== */ /* @@ -590,11 +534,6 @@ .word cpu_arm922_icache_invalidate_range .word cpu_arm922_icache_invalidate_page - /* tlb */ - .word cpu_arm922_tlb_invalidate_all - .word cpu_arm922_tlb_invalidate_range - .word cpu_arm922_tlb_invalidate_page - /* pgtable */ .word cpu_arm922_set_pgd .word cpu_arm922_set_pmd @@ -636,4 +575,5 @@ .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT .long cpu_arm922_info .long arm922_processor_functions + .long v4wbi_tlb_fns .size __arm922_proc_info, . - __arm922_proc_info diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/proc-arm926.S linux-2.5/arch/arm/mm/proc-arm926.S --- linux-2.5.5/arch/arm/mm/proc-arm926.S Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/mm/proc-arm926.S Fri Mar 1 15:07:37 2002 @@ -387,62 +387,6 @@ mov pc, lr -/* ================================== TLB ================================= */ - -/* - * cpu_arm926_tlb_invalidate_all() - * - * Invalidate all TLB entries - */ - .align 5 -ENTRY(cpu_arm926_tlb_invalidate_all) - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c8, c7, 0 @ invalidate I & D TLBs - mov pc, lr - -/* - * cpu_arm926_tlb_invalidate_range(start, end) - * - * invalidate TLB entries covering the specified range - * - * start: range start address - * end: range end address - */ - .align 5 -ENTRY(cpu_arm926_tlb_invalidate_range) - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB - - mov r3, #PAGESIZE - sub r3, r3, #1 - bic r0, r0, r3 - bic r1, r1, r3 - -1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - add r0, r0, #PAGESIZE - cmp r0, r1 - blt 1b - mov pc, lr - -/* - * cpu_arm926_tlb_invalidate_page(page, flags) - * - * invalidate the TLB entries for the specified page. - * - * page: page to invalidate - * flags: non-zero if we include the I TLB - */ - .align 5 -ENTRY(cpu_arm926_tlb_invalidate_page) - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB - teq r1, #0 - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - mov pc, lr - /* =============================== PageTable ============================== */ /* @@ -627,11 +571,6 @@ .word cpu_arm926_icache_invalidate_range .word cpu_arm926_icache_invalidate_page - /* tlb */ - .word cpu_arm926_tlb_invalidate_all - .word cpu_arm926_tlb_invalidate_range - .word cpu_arm926_tlb_invalidate_page - /* pgtable */ .word cpu_arm926_set_pgd .word cpu_arm926_set_pmd @@ -673,4 +612,5 @@ .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT .long cpu_arm926_info .long arm926_processor_functions + .long v4wbi_tlb_fns .size __arm926_proc_info, . - __arm926_proc_info diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/proc-macros.S linux-2.5/arch/arm/mm/proc-macros.S --- linux-2.5.5/arch/arm/mm/proc-macros.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/proc-macros.S Fri Mar 1 15:07:37 2002 @@ -0,0 +1,25 @@ +#include + +/* + * vma_vm_mm - get mm pointer from vma pointer (vma->vm_mm) + */ + .macro vma_vm_mm, rd, rn + ldr \rd, [\rn, #VMA_VM_MM] + .endm + +/* + * vma_vm_flags - get vma->vm_flags + */ + .macro vma_vm_flags, rd, rn + ldr \rd, [\rn, #VMA_VM_FLAGS] + .endm + +/* + * act_mm - get current->active_mm + */ + .macro act_mm, rd + bic \rd, sp, #8128 + bic \rd, \rd, #63 + ldr \rd, [\rd, #TI_TASK] + ldr \rd, [\rd, #TSK_ACTIVE_MM] + .endm diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/proc-sa110.S linux-2.5/arch/arm/mm/proc-sa110.S --- linux-2.5.5/arch/arm/mm/proc-sa110.S Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/arm/mm/proc-sa110.S Fri Mar 1 15:07:37 2002 @@ -406,61 +406,6 @@ mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache mov pc, lr -/* ================================== TLB ================================= */ - -/* - * cpu_sa110_tlb_invalidate_all() - * - * Invalidate all TLB entries - */ - .align 5 -ENTRY(cpu_sa110_tlb_invalidate_all) -ENTRY(cpu_sa1100_tlb_invalidate_all) - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c8, c7, 0 @ invalidate I & D TLBs - mov pc, lr - -/* - * cpu_sa110_tlb_invalidate_range(start, end) - * - * invalidate TLB entries covering the specified range - * - * start: range start address - * end: range end address - */ - .align 5 -ENTRY(cpu_sa110_tlb_invalidate_range) -ENTRY(cpu_sa1100_tlb_invalidate_range) - bic r0, r0, #0x0ff - bic r0, r0, #0xf00 - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB -1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - add r0, r0, #PAGESIZE - cmp r0, r1 - blo 1b - mcr p15, 0, r3, c8, c5, 0 @ invalidate I TLB - mov pc, lr - -/* - * cpu_sa110_tlb_invalidate_page(page, flags) - * - * invalidate the TLB entries for the specified page. - * - * page: page to invalidate - * flags: non-zero if we include the I TLB - */ - .align 5 -ENTRY(cpu_sa110_tlb_invalidate_page) -ENTRY(cpu_sa1100_tlb_invalidate_page) - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB - teq r1, #0 - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mcrne p15, 0, r3, c8, c5, 0 @ invalidate I TLB - mov pc, lr - /* =============================== PageTable ============================== */ /* @@ -615,11 +560,6 @@ .word cpu_sa110_icache_invalidate_range .word cpu_sa110_icache_invalidate_page - /* tlb */ - .word cpu_sa110_tlb_invalidate_all - .word cpu_sa110_tlb_invalidate_range - .word cpu_sa110_tlb_invalidate_page - /* pgtable */ .word cpu_sa110_set_pgd .word cpu_sa110_set_pmd @@ -665,19 +605,14 @@ .word cpu_sa1100_icache_invalidate_range .word cpu_sa1100_icache_invalidate_page - /* tlb */ - .word cpu_sa1100_tlb_invalidate_all - .word cpu_sa1100_tlb_invalidate_range - .word cpu_sa1100_tlb_invalidate_page - /* pgtable */ .word cpu_sa1100_set_pgd .word cpu_sa1100_set_pmd .word cpu_sa1100_set_pte /* misc */ - .word armv4_clear_user_page - .word armv4_copy_user_page + .word armv4_mc_clear_user_page + .word armv4_mc_copy_user_page .size sa1100_processor_functions, . - sa1100_processor_functions @@ -715,6 +650,7 @@ .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT .long cpu_sa110_info .long sa110_processor_functions + .long v4wb_tlb_fns .size __sa110_proc_info, . - __sa110_proc_info .type __sa1100_proc_info,#object @@ -728,6 +664,7 @@ .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT .long cpu_sa1100_info .long sa1100_processor_functions + .long v4wb_tlb_fns .size __sa1100_proc_info, . - __sa1100_proc_info .type __sa1110_proc_info,#object @@ -741,4 +678,5 @@ .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT .long cpu_sa1110_info .long sa1100_processor_functions + .long v4wb_tlb_fns .size __sa1110_proc_info, . - __sa1110_proc_info diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/proc-syms.c linux-2.5/arch/arm/mm/proc-syms.c --- linux-2.5.5/arch/arm/mm/proc-syms.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/arm/mm/proc-syms.c Fri Mar 1 15:07:37 2002 @@ -8,6 +8,9 @@ * published by the Free Software Foundation. */ #include +#include + +#include #include #ifndef MULTI_CPU @@ -20,12 +23,18 @@ EXPORT_SYMBOL(cpu_dcache_invalidate_range); EXPORT_SYMBOL(cpu_icache_invalidate_range); EXPORT_SYMBOL(cpu_icache_invalidate_page); -EXPORT_SYMBOL(cpu_tlb_invalidate_all); -EXPORT_SYMBOL(cpu_tlb_invalidate_range); -EXPORT_SYMBOL(cpu_tlb_invalidate_page); EXPORT_SYMBOL(cpu_set_pgd); EXPORT_SYMBOL(cpu_set_pmd); EXPORT_SYMBOL(cpu_set_pte); #else EXPORT_SYMBOL(processor); +#endif + +#ifndef MULTI_TLB +EXPORT_SYMBOL_NOVERS(__cpu_flush_kern_tlb_all); +EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_mm); +EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_range); +EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_page); +#else +EXPORT_SYMBOL(cpu_tlb); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/proc-xscale.S linux-2.5/arch/arm/mm/proc-xscale.S --- linux-2.5.5/arch/arm/mm/proc-xscale.S Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/mm/proc-xscale.S Fri Mar 1 15:07:37 2002 @@ -494,55 +494,6 @@ ENTRY(xscale_cache_dummy) mov pc, lr -/* ================================== TLB ================================= */ - -/* - * cpu_xscale_tlb_invalidate_all() - * - * Invalidate all TLB entries - */ - .align 5 -ENTRY(cpu_xscale_tlb_invalidate_all) - mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer - mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs - cpwait_ret lr, ip - -/* - * cpu_xscale_tlb_invalidate_range(start, end) - * - * invalidate TLB entries covering the specified range - * - * start: range start address - * end: range end address - */ - .align 5 -ENTRY(cpu_xscale_tlb_invalidate_range) - bic r0, r0, #(PAGESIZE - 1) & 0x00ff - bic r0, r0, #(PAGESIZE - 1) & 0xff00 - mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer -1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - add r0, r0, #PAGESIZE - cmp r0, r1 - blo 1b - cpwait_ret lr, ip - -/* - * cpu_xscale_tlb_invalidate_page(page, flags) - * - * invalidate the TLB entries for the specified page. - * - * page: page to invalidate - * flags: non-zero if we include the I TLB - */ - .align 5 -ENTRY(cpu_xscale_tlb_invalidate_page) - mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer - teq r1, #0 - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mcrne p15, 0, r3, c8, c5, 1 @ invalidate I TLB entry - cpwait_ret lr, ip - /* ================================ TLB LOCKING============================== * * The XScale MicroArchitecture implements support for locking entries into @@ -637,6 +588,7 @@ orreq r1, r1, #PMD_SECT_TEX(1) #endif str r1, [r0] + mov ip, #0 mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer mov pc, lr @@ -645,6 +597,8 @@ * cpu_xscale_set_pte(ptep, pte) * * Set a PTE and flush it out + * + * Errata 40: must set memory to write-through for user read-only pages. */ .align 5 ENTRY(cpu_xscale_set_pte) @@ -653,29 +607,49 @@ bic r2, r1, #0xff0 orr r2, r2, #PTE_TYPE_EXT @ extended page - eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY + eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY - tst r1, #L_PTE_USER | L_PTE_EXEC @ User or Exec? + tst r3, #L_PTE_USER | L_PTE_EXEC @ User or Exec? orrne r2, r2, #PTE_EXT_AP_URO_SRW @ yes -> user r/o, system r/w - tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty? + tst r3, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty? orreq r2, r2, #PTE_EXT_AP_UNO_SRW @ yes -> user n/a, system r/w @ combined with user -> user r/w + @ + @ Handle the X bit. We want to set this bit for the minicache + @ (U = E = B = W = 0, C = 1) or when write allocate is enabled, + @ and we have a writeable, cacheable region. If we ignore the + @ U and E bits, we can allow user space to use the minicache as + @ well. + @ + @ X = (C & ~W & ~B) | (C & W & B & write_allocate) + @ + eor ip, r1, #L_PTE_CACHEABLE + tst ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE #if PTE_CACHE_WRITE_ALLOCATE - tst r1, #L_PTE_CACHEABLE @ cacheable? - orrne r2, r2, #PTE_EXT_TEX(1) -#else - eor r1, r1, #L_PTE_CACHEABLE - tst r1, #L_PTE_CACHEABLE | L_PTE_BUFFERABLE @ C = 1 B = 0? - orreq r2, r2, #PTE_EXT_TEX(1) @ yes -> set X (minicache) + eorne ip, r1, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE + tstne ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE #endif + orreq r2, r2, #PTE_EXT_TEX(1) + + @ + @ Erratum 40: The B bit must be cleared for a user read-only + @ cacheable page. + @ + @ B = B & ~((U|E) & C & ~W) + @ + and ip, r1, #L_PTE_USER | L_PTE_EXEC | L_PTE_WRITE | L_PTE_CACHEABLE + teq ip, #L_PTE_USER | L_PTE_CACHEABLE + teqne ip, #L_PTE_EXEC | L_PTE_CACHEABLE + teqne ip, #L_PTE_USER | L_PTE_EXEC | L_PTE_CACHEABLE + biceq r2, r2, #PTE_BUFFERABLE - tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young? + tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young? movne r2, #0 @ no -> fault str r2, [r0] @ hardware version - mov r0, r0 + mov ip, #0 mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer mov pc, lr @@ -743,11 +717,6 @@ .word cpu_xscale_icache_invalidate_range .word cpu_xscale_icache_invalidate_page - /* tlb */ - .word cpu_xscale_tlb_invalidate_all - .word cpu_xscale_tlb_invalidate_range - .word cpu_xscale_tlb_invalidate_page - /* pgtable */ .word cpu_xscale_set_pgd .word cpu_xscale_set_pmd @@ -795,6 +764,7 @@ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP .long cpu_80200_info .long xscale_processor_functions + .long v4wbi_tlb_fns .size __80200_proc_info, . - __80200_proc_info .type __cotulla_proc_info,#object @@ -808,5 +778,6 @@ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP .long cpu_cotulla_info .long xscale_processor_functions + .long v4wbi_tlb_fns .size __cotulla_proc_info, . - __cotulla_proc_info diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/tlb-v3.S linux-2.5/arch/arm/mm/tlb-v3.S --- linux-2.5.5/arch/arm/mm/tlb-v3.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/tlb-v3.S Fri Mar 1 15:07:37 2002 @@ -0,0 +1,88 @@ +/* + * linux/arch/arm/mm/tlbv3.S + * + * Copyright (C) 1997-2002 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ARM architecture version 3 TLB handling functions. + * + * Processors: ARM610, ARM710. + */ +#include +#include +#include "proc-macros.S" + + .align 5 +/* + * v3_flush_user_tlb_mm(mm) + * + * Invalidate all TLB entries in a particular address space + * + * - mm - mm_struct describing address space + */ +ENTRY(v3_flush_user_tlb_mm) + act_mm r1 @ get current->active_mm + teq r0, r1 @ == mm ? + movne pc, lr @ no, we dont do anything + +/* + * v3_flush_kern_tlb_all() + * + * Invalidate the entire TLB + */ +ENTRY(v3_flush_kern_tlb_all) + mov r0, #0 + mcr p15, 0, r0, c5, c0, 0 @ invalidate TLB + mov pc, lr + +/* + * v3_flush_user_tlb_range(start, end, mm) + * + * Invalidate a range of TLB entries in the specified address space. + * + * - start - range start address + * - end - range end address + * - mm - mm_struct describing address space + */ + .align 5 +ENTRY(v3_flush_user_tlb_range) + vma_vm_mm r2, r2 + act_mm r3 @ get current->active_mm + teq r2, r3 @ == mm ? + movne pc, lr @ no, we dont do anything + bic r0, r0, #0x0ff + bic r0, r0, #0xf00 +1: mcr p15, 0, r0, c6, c0, 0 @ invalidate TLB entry + add r0, r0, #PAGE_SZ + cmp r0, r1 + blo 1b + mov pc, lr + +/* + * v3_flush_user_tlb_page(vaddr,vma) + * + * Invalidate the specified page in the specified address space. + * + * - vaddr - virtual address (may not be aligned) + * - vma - vma_struct describing address range + */ + .align 5 +ENTRY(v3_flush_user_tlb_page) + vma_vm_mm r2, r1 @ get vma->vm_mm + act_mm r3 @ get current->active_mm + teq r2, r3 @ equal + movne pc, lr @ no +ENTRY(v3_flush_kern_tlb_page) + mcr p15, 0, r0, c6, c0, 0 @ invalidate TLB entry + mov pc, lr + +ENTRY(v3_tlb_fns) + .word v3_flush_kern_tlb_all + .word v3_flush_user_tlb_mm + .word v3_flush_user_tlb_range + .word v3_flush_user_tlb_page + .word v3_flush_kern_tlb_page + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/tlb-v4.S linux-2.5/arch/arm/mm/tlb-v4.S --- linux-2.5.5/arch/arm/mm/tlb-v4.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/tlb-v4.S Fri Mar 1 15:07:37 2002 @@ -0,0 +1,106 @@ +/* + * linux/arch/arm/mm/tlbv4.S + * + * Copyright (C) 1997-2002 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ARM architecture version 4 TLB handling functions. + * These assume a split I/D TLBs, and no write buffer. + * + * Processors: ARM720T + */ +#include +#include +#include "proc-macros.S" + + .align 5 +/* + * v4_flush_user_tlb_mm(mm) + * + * Invalidate all TLB entries in a particular address space + * + * - mm - mm_struct describing address space + */ +ENTRY(v4_flush_user_tlb_mm) + act_mm r1 @ get current->active_mm + teq r0, r1 @ == mm ? + movne pc, lr @ no, we dont do anything + +/* + * v4_flush_kern_tlb_all() + * + * Invalidate the entire TLB + */ +ENTRY(v4_flush_kern_tlb_all) + mov r0, #0 + mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs + mov pc, lr + +/* + * v4_flush_user_tlb_range(start, end, mm) + * + * Invalidate a range of TLB entries in the specified address space. + * + * - start - range start address + * - end - range end address + * - mm - mm_struct describing address space + */ + .align 5 +ENTRY(v4_flush_user_tlb_range) + vma_vm_mm ip, r2 + act_mm r3 @ get current->active_mm + eors r3, ip, r3 @ == mm ? + movne pc, lr @ no, we dont do anything + vma_vm_flags ip, r2 + bic r0, r0, #0x0ff + bic r0, r0, #0xf00 +1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + add r0, r0, #PAGE_SZ + cmp r0, r1 + blo 1b + tst ip, #VM_EXEC + mcrne p15, 0, r3, c8, c5, 0 @ invalidate I TLB + mov pc, lr + +/* + * v4_flush_user_tlb_page(vaddr,vma) + * + * Invalidate the specified page in the specified address space. + * + * - vaddr - virtual address (may not be aligned) + * - vma - vma_struct describing address range + */ + .align 5 +ENTRY(v4_flush_user_tlb_page) + vma_vm_mm r2, r1 @ get vma->vm_mm + act_mm r3 @ get current->active_mm + teq r2, r3 @ equal + movne pc, lr @ no + vma_vm_flags r2, r1 + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + tst r2, #VM_EXEC + mcrne p15, 0, r3, c8, c5, 0 @ invalidate I TLB + mov pc, lr + +/* + * v4_flush_kern_tlb_page(kaddr) + * + * Invalidate the TLB entry for the specified page. The address + * will be in the kernels virtual memory space. Current uses + * only require the D-TLB to be invalidated. + * + * - kaddr - Kernel virtual memory address + */ +ENTRY(v4_flush_kern_tlb_page) + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mov pc, lr + +ENTRY(v4_tlb_fns) + .word v4_flush_kern_tlb_all + .word v4_flush_user_tlb_mm + .word v4_flush_user_tlb_range + .word v4_flush_user_tlb_page + .word v4_flush_kern_tlb_page diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/mm/tlb-v4wb.S linux-2.5/arch/arm/mm/tlb-v4wb.S --- linux-2.5.5/arch/arm/mm/tlb-v4wb.S Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/arm/mm/tlb-v4wb.S Fri Mar 1 15:07:37 2002 @@ -0,0 +1,160 @@ +/* + * linux/arch/arm/mm/tlbv4wb.S + * + * Copyright (C) 1997-2002 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ARM architecture version 4 and version 5 TLB handling functions. + * These assume a split I/D TLBs, with a write buffer. + * + * Processors: ARM920 ARM922 ARM926 SA110 SA1100 SA1110 XScale + */ +#include +#include +#include "proc-macros.S" + + .align 5 +/* + * v4wb_flush_user_tlb_mm(mm) + * + * Invalidate all TLB entries in a particular address space + * + * - mm - mm_struct describing address space + */ +ENTRY(v4wb_flush_user_tlb_mm) +ENTRY(v4wbi_flush_user_tlb_mm) + act_mm r1 @ get current->active_mm + teq r0, r1 @ == mm ? + movne pc, lr @ no, we dont do anything + +/* + * v4wb_flush_tlb_all() + * + * Invalidate the entire TLB + */ +ENTRY(v4wb_flush_kern_tlb_all) +ENTRY(v4wbi_flush_kern_tlb_all) + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs + mov pc, lr + +/* + * v4wb_flush_user_tlb_range(start, end, mm) + * + * Invalidate a range of TLB entries in the specified address space. + * + * - start - range start address + * - end - range end address + * - mm - mm_struct describing address space + */ + .align 5 +ENTRY(v4wb_flush_user_tlb_range) + vma_vm_mm ip, r2 + act_mm r3 @ get current->active_mm + eors r3, ip, r3 @ == mm ? + movne pc, lr @ no, we dont do anything + vma_vm_flags r2, r2 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + tst r2, #VM_EXEC + mcrne p15, 0, r3, c8, c5, 0 @ invalidate I TLB + bic r0, r0, #0x0ff + bic r0, r0, #0xf00 +1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + add r0, r0, #PAGE_SZ + cmp r0, r1 + blo 1b + mov pc, lr + +/* + * v4wb_flush_user_tlb_page(vaddr,vma) + * + * Invalidate the specified page in the specified address space. + * + * - vaddr - virtual address (may not be aligned) + * - vma - vma_struct describing address range + */ + .align 5 +ENTRY(v4wb_flush_user_tlb_page) + vma_vm_mm r2, r1 @ get vma->vm_mm + act_mm r3 @ get current->active_mm + teq r2, r3 @ equal + movne pc, lr @ no + vma_vm_flags r2, r1 + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + tst r2, #VM_EXEC + mcrne p15, 0, r3, c8, c5, 0 @ invalidate I TLB +ENTRY(v4wb_flush_kern_tlb_page) + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mov pc, lr + +/* + * These two are optimised for ARM920, ARM922, ARM926, Xscale + */ + +/* + * v4wb_flush_user_tlb_range(start, end, mm) + * + * Invalidate a range of TLB entries in the specified address space. + * + * - start - range start address + * - end - range end address + * - mm - mm_struct describing address space + */ + .align 5 +ENTRY(v4wbi_flush_user_tlb_range) + act_mm r3 @ get current->active_mm + teq r2, r3 @ == mm ? + movne pc, lr @ no, we dont do anything + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + bic r0, r0, #0x0ff + bic r0, r0, #0xf00 +1: mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + add r0, r0, #PAGE_SZ + cmp r0, r1 + blo 1b + mov pc, lr + +/* + * v4wb_flush_tlb_page(vaddr,vma) + * + * Invalidate the specified page in the specified address space. + * + * - vaddr - virtual address (may not be aligned) + * - vma - vma_struct describing address range + */ + .align 5 +ENTRY(v4wbi_flush_user_tlb_page) + vma_vm_mm r2, r1 @ get vma->vm_mm + act_mm r3 @ get current->active_mm + teq r2, r3 @ equal + movne pc, lr @ no + vma_vm_flags r2, r1 + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + tst r2, #VM_EXEC + mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry +ENTRY(v4wbi_flush_kern_tlb_page) + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mov pc, lr + +ENTRY(v4wb_tlb_fns) + .word v4wb_flush_kern_tlb_all + .word v4wb_flush_user_tlb_mm + .word v4wb_flush_user_tlb_range + .word v4wb_flush_user_tlb_page + .word v4wb_flush_kern_tlb_page + +ENTRY(v4wbi_tlb_fns) + .word v4wbi_flush_kern_tlb_all + .word v4wbi_flush_user_tlb_mm + .word v4wbi_flush_user_tlb_range + .word v4wbi_flush_user_tlb_page + .word v4wbi_flush_kern_tlb_page + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/ChangeLog linux-2.5/arch/arm/nwfpe/ChangeLog --- linux-2.5.5/arch/arm/nwfpe/ChangeLog Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/nwfpe/ChangeLog Fri Mar 1 15:07:37 2002 @@ -1,3 +1,26 @@ +2002-01-19 Russell King + + * fpa11.h - Add documentation + - remove userRegisters pointer from this structure. + - add new method to obtain integer register values. + * softfloat.c - Remove float128 + * softfloat.h - Remove float128 + * softfloat-specialize - Remove float128 + + * The FPA11 structure is not a kernel-specific data structure. + It is used by users of ptrace to examine the values of the + floating point registers. Therefore, any changes to the + FPA11 structure (size or position of elements contained + within) have to be well thought out. + + * Since 128-bit float requires the FPA11 structure to change + size, it has been removed. 128-bit float is currently unused, + and needs various things to be re-worked so that we won't + overflow the available space in the task structure. + + * The changes are designed to break any patch that goes on top + of this code, so that the authors properly review their changes. + 1999-08-19 Scott Bambrough * fpmodule.c - Changed version number to 0.95 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/double_cpdo.c linux-2.5/arch/arm/nwfpe/double_cpdo.c --- linux-2.5.5/arch/arm/nwfpe/double_cpdo.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/nwfpe/double_cpdo.c Fri Mar 1 15:07:37 2002 @@ -19,9 +19,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" #include "softfloat.h" #include "fpopcode.h" -#include "fpa11.h" float64 float64_exp(float64 Fm); float64 float64_ln(float64 Fm); @@ -165,8 +165,7 @@ case RND_CODE: case URD_CODE: - fpa11->fpreg[Fd].fDouble = - int32_to_float64(float64_to_int32(rFm)); + fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm); break; case SQT_CODE: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/entry.S linux-2.5/arch/arm/nwfpe/entry.S --- linux-2.5.5/arch/arm/nwfpe/entry.S Wed Feb 20 02:10:54 2002 +++ linux-2.5/arch/arm/nwfpe/entry.S Fri Mar 1 15:07:37 2002 @@ -52,8 +52,6 @@ 1) The kernel has created a struct pt_regs on the stack and saved the user registers into it. See /usr/include/asm/proc/ptrace.h for details. -The emulator code uses userRegisters as the base of an array of words -from which the contents of the registers can be extracted. 2) It calls EmulateAll to emulate a floating point instruction. EmulateAll returns 1 if the emulation was successful, or 0 if not. @@ -72,14 +70,9 @@ .globl nwfpe_enter nwfpe_enter: - /* ?? Could put userRegisters and fpa11 into fixed regs during - emulation. This would reduce load/store overhead at the expense - of stealing two regs from the register allocator. Not sure if - it's worth it. */ - str sp, [r10] @ Store the user registers pointer in the fpa11 structure. mov r4, lr @ save the failure-return addresses + mov sl, sp - mov r0, r10 bl FPA11_CheckInit @ check to see if we are initialised ldr r5, [sp, #60] @ get contents of PC; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/entry26.S linux-2.5/arch/arm/nwfpe/entry26.S --- linux-2.5.5/arch/arm/nwfpe/entry26.S Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/arm/nwfpe/entry26.S Fri Mar 1 15:07:37 2002 @@ -65,18 +65,10 @@ .globl nwfpe_enter nwfpe_enter: - ldr r4, =userRegisters - str sp, [r4] @ save pointer to user regs + mov sl, sp + bl FPA11_CheckInit @ check to see if we are initialised - mov r10, sp, lsr #13 @ find workspace - mov r10, r10, lsl #13 - add r10, r10, #TSS_FPESAVE - - ldr r4, =fpa11 - str r10, [r4] @ store pointer to our state - mov r4, sp @ use r4 for local pointer - - ldr r5, [r4, #60] @ get contents of PC + ldr r5, [sp, #60] @ get contents of PC bic r5, r5, #0xfc000003 ldr r0, [r5, #-4] @ get actual instruction into r0 bl EmulateAll @ emulate the instruction @@ -93,10 +85,10 @@ teqne r2, #0x0E000000 bne ret_from_exception @ return ok if not a fp insn - ldr r9, [r4, #60] @ get new condition codes + ldr r9, [sp, #60] @ get new condition codes and r9, r9, #0xfc000003 orr r7, r5, r9 - str r7, [r4, #60] @ update PC copy in regs + str r7, [sp, #60] @ update PC copy in regs mov r0, r6 @ save a copy mov r1, r9 @ fetch the condition codes diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/extended_cpdo.c linux-2.5/arch/arm/nwfpe/extended_cpdo.c --- linux-2.5.5/arch/arm/nwfpe/extended_cpdo.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/arm/nwfpe/extended_cpdo.c Fri Mar 1 15:07:37 2002 @@ -19,9 +19,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" #include "softfloat.h" #include "fpopcode.h" -#include "fpa11.h" floatx80 floatx80_exp(floatx80 Fm); floatx80 floatx80_ln(floatx80 Fm); @@ -157,8 +157,7 @@ case RND_CODE: case URD_CODE: - fpa11->fpreg[Fd].fExtended = - int32_to_floatx80(floatx80_to_int32(rFm)); + fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm); break; case SQT_CODE: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/fpa11.c linux-2.5/arch/arm/nwfpe/fpa11.c --- linux-2.5.5/arch/arm/nwfpe/fpa11.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/arm/nwfpe/fpa11.c Fri Mar 1 15:07:37 2002 @@ -18,8 +18,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include #include "fpa11.h" #include "fpopcode.h" @@ -27,6 +25,9 @@ #include "fpmodule.h" #include "fpmodule.inl" +#include +#include + /* forward declarations */ unsigned int EmulateCPDO(const unsigned int); unsigned int EmulateCPDT(const unsigned int); @@ -56,6 +57,7 @@ void SetRoundingMode(const unsigned int opcode) { #if MAINTAIN_FPCR + FPA11 *fpa11 = GET_FPA11(); fpa11->fpcr &= ~MASK_ROUNDING_MODE; #endif switch (opcode & MASK_ROUNDING_MODE) @@ -94,6 +96,7 @@ void SetRoundingPrecision(const unsigned int opcode) { #if MAINTAIN_FPCR + FPA11 *fpa11 = GET_FPA11(); fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; #endif switch (opcode & MASK_ROUNDING_PRECISION) @@ -123,8 +126,9 @@ } } -void FPA11_CheckInit(FPA11 *fpa11) +void FPA11_CheckInit(void) { + FPA11 *fpa11 = GET_FPA11(); if (unlikely(fpa11->initflag == 0)) { resetFPA11(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/fpa11.h linux-2.5/arch/arm/nwfpe/fpa11.h --- linux-2.5.5/arch/arm/nwfpe/fpa11.h Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/arm/nwfpe/fpa11.h Fri Mar 1 15:07:37 2002 @@ -22,45 +22,66 @@ #ifndef __FPA11_H__ #define __FPA11_H__ +#define GET_FPA11() ((FPA11 *)(¤t_thread_info()->fpstate)) + +/* + * The processes registers are always at the very top of the 8K + * stack+task struct. Use the same method as 'current' uses to + * reach them. + */ +register unsigned int *user_registers asm("sl"); + +#define GET_USERREG() (user_registers) + +#include + /* includes */ #include "fpsr.h" /* FP control and status register definitions */ #include "softfloat.h" -/* Need task_struct */ -#include - #define typeNone 0x00 #define typeSingle 0x01 #define typeDouble 0x02 #define typeExtended 0x03 +/* + * This must be no more and no less than 12 bytes. + */ typedef union tagFPREG { - float32 fSingle; - float64 fDouble; floatx80 fExtended; + float64 fDouble; + float32 fSingle; } FPREG; -/* FPA11 device model */ +/* + * FPA11 device model. + * + * This structure is exported to user space. Do not re-order. + * Only add new stuff to the end, and do not change the size of + * any element. Elements of this structure are used by user + * space, and must match struct user_fp in include/asm-arm/user.h. + * We include the byte offsets below for documentation purposes. + * + * The size of this structure and FPREG are checked by fpmodule.c + * on initialisation. If the rules have been broken, NWFPE will + * not initialise. + */ typedef struct tagFPA11 { - unsigned int *userRegisters; - FPREG fpreg[8]; /* 8 floating point registers */ - FPSR fpsr; /* floating point status register */ - FPCR fpcr; /* floating point control register */ - unsigned char fType[8]; /* type of floating point value held in - floating point registers. One of none - single, double or extended. */ - int initflag; /* this is special. The kernel guarantees - to set it to 0 when a thread is launched, - so we can use it to detect whether this - instance of the emulator needs to be - initialised. */ +/* 0 */ FPREG fpreg[8]; /* 8 floating point registers */ +/* 96 */ FPSR fpsr; /* floating point status register */ +/* 100 */ FPCR fpcr; /* floating point control register */ +/* 104 */ unsigned char fType[8]; /* type of floating point value held in + floating point registers. One of none + single, double or extended. */ +/* 112 */ int initflag; /* this is special. The kernel guarantees + to set it to 0 when a thread is launched, + so we can use it to detect whether this + instance of the emulator needs to be + initialised. */ } FPA11; extern void resetFPA11(void); extern void SetRoundingMode(const unsigned int); extern void SetRoundingPrecision(const unsigned int); - -#define GET_FPA11() ((FPA11 *)(¤t->thread.fpstate)) -#define GET_USERREG() (GET_FPA11()->userRegisters) #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/fpa11_cpdt.c linux-2.5/arch/arm/nwfpe/fpa11_cpdt.c --- linux-2.5.5/arch/arm/nwfpe/fpa11_cpdt.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/arm/nwfpe/fpa11_cpdt.c Fri Mar 1 15:07:37 2002 @@ -20,9 +20,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" #include "softfloat.h" #include "fpopcode.h" -#include "fpa11.h" #include "fpmodule.h" #include "fpmodule.inl" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/fpa11_cprt.c linux-2.5/arch/arm/nwfpe/fpa11_cprt.c --- linux-2.5.5/arch/arm/nwfpe/fpa11_cprt.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/arm/nwfpe/fpa11_cprt.c Fri Mar 1 15:07:37 2002 @@ -20,10 +20,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" #include "milieu.h" #include "softfloat.h" #include "fpopcode.h" -#include "fpa11.h" #include "fpa11.inl" #include "fpmodule.h" #include "fpmodule.inl" @@ -82,8 +82,7 @@ unsigned int nRc = 1; SetRoundingMode(opcode); - SetRoundingPrecision(opcode); - + switch (opcode & MASK_ROUNDING_PRECISION) { case ROUND_SINGLE: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/fpmodule.c linux-2.5/arch/arm/nwfpe/fpmodule.c --- linux-2.5.5/arch/arm/nwfpe/fpmodule.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/arm/nwfpe/fpmodule.c Fri Mar 1 15:07:37 2002 @@ -21,6 +21,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" + #include #include #include @@ -36,7 +38,6 @@ #include "softfloat.h" #include "fpopcode.h" #include "fpmodule.h" -#include "fpa11.h" #include "fpa11.inl" /* kernel symbols required for signal handling */ @@ -83,6 +84,11 @@ { if (sizeof(FPA11) > sizeof(union fp_state)) { printk(KERN_ERR "nwfpe: bad structure size\n"); + return -EINVAL; + } + + if (sizeof(FPREG) != 12) { + printk(KERN_ERR "nwfpe: bad register size\n"); return -EINVAL; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/fpopcode.c linux-2.5/arch/arm/nwfpe/fpopcode.c --- linux-2.5.5/arch/arm/nwfpe/fpopcode.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/arm/nwfpe/fpopcode.c Fri Mar 1 15:07:37 2002 @@ -19,10 +19,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" #include "softfloat.h" #include "fpopcode.h" #include "fpsr.h" -#include "fpa11.h" #include "fpmodule.h" #include "fpmodule.inl" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/single_cpdo.c linux-2.5/arch/arm/nwfpe/single_cpdo.c --- linux-2.5.5/arch/arm/nwfpe/single_cpdo.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/arm/nwfpe/single_cpdo.c Fri Mar 1 15:07:37 2002 @@ -19,9 +19,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "fpa11.h" #include "softfloat.h" #include "fpopcode.h" -#include "fpa11.h" float32 float32_exp(float32 Fm); float32 float32_ln(float32 Fm); @@ -139,8 +139,7 @@ case RND_CODE: case URD_CODE: - fpa11->fpreg[Fd].fSingle = - int32_to_float32(float32_to_int32(rFm)); + fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm); break; case SQT_CODE: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/softfloat-specialize linux-2.5/arch/arm/nwfpe/softfloat-specialize --- linux-2.5.5/arch/arm/nwfpe/softfloat-specialize Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/arm/nwfpe/softfloat-specialize Fri Mar 1 15:07:37 2002 @@ -364,108 +364,3 @@ } #endif - -#ifdef FLOAT128 - -/* -------------------------------------------------------------------------------- -The pattern for a default generated quadruple-precision NaN. The `high' and -`low' values hold the most- and least-significant bits, respectively. -------------------------------------------------------------------------------- -*/ -#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF ) -#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is a NaN; -otherwise returns 0. -------------------------------------------------------------------------------- -*/ -flag float128_is_nan( float128 a ) -{ - - return - ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) - && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is a -signaling NaN; otherwise returns 0. -------------------------------------------------------------------------------- -*/ -flag float128_is_signaling_nan( float128 a ) -{ - - return - ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) - && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the quadruple-precision floating-point NaN -`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid -exception is raised. -------------------------------------------------------------------------------- -*/ -static commonNaNT float128ToCommonNaN( float128 a ) -{ - commonNaNT z; - - if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); - z.sign = a.high>>63; - shortShift128Left( a.high, a.low, 16, &z.high, &z.low ); - return z; - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the canonical NaN `a' to the quadruple- -precision floating-point format. -------------------------------------------------------------------------------- -*/ -static float128 commonNaNToFloat128( commonNaNT a ) -{ - float128 z; - - shift128Right( a.high, a.low, 16, &z.high, &z.low ); - z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 ); - return z; - -} - -/* -------------------------------------------------------------------------------- -Takes two quadruple-precision floating-point values `a' and `b', one of -which is a NaN, and returns the appropriate NaN result. If either `a' or -`b' is a signaling NaN, the invalid exception is raised. -------------------------------------------------------------------------------- -*/ -static float128 propagateFloat128NaN( float128 a, float128 b ) -{ - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; - - aIsNaN = float128_is_nan( a ); - aIsSignalingNaN = float128_is_signaling_nan( a ); - bIsNaN = float128_is_nan( b ); - bIsSignalingNaN = float128_is_signaling_nan( b ); - a.high |= LIT64( 0x0000800000000000 ); - b.high |= LIT64( 0x0000800000000000 ); - if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); - if ( aIsNaN ) { - return ( aIsSignalingNaN & bIsNaN ) ? b : a; - } - else { - return b; - } - -} - -#endif - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/softfloat.c linux-2.5/arch/arm/nwfpe/softfloat.c --- linux-2.5.5/arch/arm/nwfpe/softfloat.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/arm/nwfpe/softfloat.c Fri Mar 1 15:07:37 2002 @@ -28,6 +28,7 @@ =============================================================================== */ +#include "fpa11.h" #include "milieu.h" #include "softfloat.h" @@ -753,277 +754,6 @@ #endif -#ifdef FLOAT128 - -/* -------------------------------------------------------------------------------- -Returns the least-significant 64 fraction bits of the quadruple-precision -floating-point value `a'. -------------------------------------------------------------------------------- -*/ -INLINE bits64 extractFloat128Frac1( float128 a ) -{ - - return a.low; - -} - -/* -------------------------------------------------------------------------------- -Returns the most-significant 48 fraction bits of the quadruple-precision -floating-point value `a'. -------------------------------------------------------------------------------- -*/ -INLINE bits64 extractFloat128Frac0( float128 a ) -{ - - return a.high & LIT64( 0x0000FFFFFFFFFFFF ); - -} - -/* -------------------------------------------------------------------------------- -Returns the exponent bits of the quadruple-precision floating-point value -`a'. -------------------------------------------------------------------------------- -*/ -INLINE int32 extractFloat128Exp( float128 a ) -{ - - return ( a.high>>48 ) & 0x7FFF; - -} - -/* -------------------------------------------------------------------------------- -Returns the sign bit of the quadruple-precision floating-point value `a'. -------------------------------------------------------------------------------- -*/ -INLINE flag extractFloat128Sign( float128 a ) -{ - - return a.high>>63; - -} - -/* -------------------------------------------------------------------------------- -Normalizes the subnormal quadruple-precision floating-point value -represented by the denormalized significand formed by the concatenation of -`aSig0' and `aSig1'. The normalized exponent is stored at the location -pointed to by `zExpPtr'. The most significant 49 bits of the normalized -significand are stored at the location pointed to by `zSig0Ptr', and the -least significant 64 bits of the normalized significand are stored at the -location pointed to by `zSig1Ptr'. -------------------------------------------------------------------------------- -*/ -static void - normalizeFloat128Subnormal( - bits64 aSig0, - bits64 aSig1, - int32 *zExpPtr, - bits64 *zSig0Ptr, - bits64 *zSig1Ptr - ) -{ - int8 shiftCount; - - if ( aSig0 == 0 ) { - shiftCount = countLeadingZeros64( aSig1 ) - 15; - if ( shiftCount < 0 ) { - *zSig0Ptr = aSig1>>( - shiftCount ); - *zSig1Ptr = aSig1<<( shiftCount & 63 ); - } - else { - *zSig0Ptr = aSig1<>= shiftCount; - z = aSig0; - if ( aSign ) z = - z; - if ( ( z < 0 ) ^ aSign ) { - invalid: - float_exception_flags |= float_flag_invalid; - return aSign ? 0x80000000 : 0x7FFFFFFF; - } - if ( ( aSig0<>1, &z.high, &z.low ); - if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; - } - else { - if ( (sbits64) z.low < 0 ) { - ++z.high; - if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1; - } - } - } - else if ( roundingMode != float_round_to_zero ) { - if ( extractFloat128Sign( z ) - ^ ( roundingMode == float_round_up ) ) { - add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low ); - } - } - z.low &= ~ roundBitsMask; - } - else { - if ( aExp <= 0x3FFE ) { - if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a; - float_exception_flags |= float_flag_inexact; - aSign = extractFloat128Sign( a ); - switch ( float_rounding_mode ) { - case float_round_nearest_even: - if ( ( aExp == 0x3FFE ) - && ( extractFloat128Frac0( a ) - | extractFloat128Frac1( a ) ) - ) { - return packFloat128( aSign, 0x3FFF, 0, 0 ); - } - break; - case float_round_down: - return - aSign ? packFloat128( 1, 0x3FFF, 0, 0 ) - : packFloat128( 0, 0, 0, 0 ); - case float_round_up: - return - aSign ? packFloat128( 1, 0, 0, 0 ) - : packFloat128( 0, 0x3FFF, 0, 0 ); - } - return packFloat128( aSign, 0, 0, 0 ); - } - lastBitMask = 1; - lastBitMask <<= 0x402F - aExp; - roundBitsMask = lastBitMask - 1; - z.low = 0; - z.high = a.high; - roundingMode = float_rounding_mode; - if ( roundingMode == float_round_nearest_even ) { - z.high += lastBitMask>>1; - if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) { - z.high &= ~ lastBitMask; - } - } - else if ( roundingMode != float_round_to_zero ) { - if ( extractFloat128Sign( z ) - ^ ( roundingMode == float_round_up ) ) { - z.high |= ( a.low != 0 ); - z.high += roundBitsMask; - } - } - z.high &= ~ roundBitsMask; - } - if ( ( z.low != a.low ) || ( z.high != a.high ) ) { - float_exception_flags |= float_flag_inexact; - } - return z; - -} - -/* -------------------------------------------------------------------------------- -Returns the result of adding the absolute values of the quadruple-precision -floating-point values `a' and `b'. If `zSign' is true, the sum is negated -before being returned. `zSign' is ignored if the result is a NaN. The -addition is performed according to the IEC/IEEE Standard for Binary -Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -static float128 addFloat128Sigs( float128 a, float128 b, flag zSign ) -{ - int32 aExp, bExp, zExp; - bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; - int32 expDiff; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - expDiff = aExp - bExp; - if ( 0 < expDiff ) { - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); - return a; - } - if ( bExp == 0 ) { - --expDiff; - } - else { - bSig0 |= LIT64( 0x0001000000000000 ); - } - shift128ExtraRightJamming( - bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 ); - zExp = aExp; - } - else if ( expDiff < 0 ) { - if ( bExp == 0x7FFF ) { - if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - if ( aExp == 0 ) { - ++expDiff; - } - else { - aSig0 |= LIT64( 0x0001000000000000 ); - } - shift128ExtraRightJamming( - aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 ); - zExp = bExp; - } - else { - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 | bSig0 | bSig1 ) { - return propagateFloat128NaN( a, b ); - } - return a; - } - add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 ); - zSig2 = 0; - zSig0 |= LIT64( 0x0002000000000000 ); - zExp = aExp; - goto shiftRight1; - } - aSig0 |= LIT64( 0x0001000000000000 ); - add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - --zExp; - if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack; - ++zExp; - shiftRight1: - shift128ExtraRightJamming( - zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); - roundAndPack: - return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of subtracting the absolute values of the quadruple- -precision floating-point values `a' and `b'. If `zSign' is true, the -difference is negated before being returned. `zSign' is ignored if the -result is a NaN. The subtraction is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -static float128 subFloat128Sigs( float128 a, float128 b, flag zSign ) -{ - int32 aExp, bExp, zExp; - bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1; - int32 expDiff; - float128 z; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - expDiff = aExp - bExp; - shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); - shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 ); - if ( 0 < expDiff ) goto aExpBigger; - if ( expDiff < 0 ) goto bExpBigger; - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 | bSig0 | bSig1 ) { - return propagateFloat128NaN( a, b ); - } - float_raise( float_flag_invalid ); - z.low = float128_default_nan_low; - z.high = float128_default_nan_high; - return z; - } - if ( aExp == 0 ) { - aExp = 1; - bExp = 1; - } - if ( bSig0 < aSig0 ) goto aBigger; - if ( aSig0 < bSig0 ) goto bBigger; - if ( bSig1 < aSig1 ) goto aBigger; - if ( aSig1 < bSig1 ) goto bBigger; - return packFloat128( float_rounding_mode == float_round_down, 0, 0, 0 ); - bExpBigger: - if ( bExp == 0x7FFF ) { - if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); - return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 ); - } - if ( aExp == 0 ) { - ++expDiff; - } - else { - aSig0 |= LIT64( 0x4000000000000000 ); - } - shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); - bSig0 |= LIT64( 0x4000000000000000 ); - bBigger: - sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 ); - zExp = bExp; - zSign ^= 1; - goto normalizeRoundAndPack; - aExpBigger: - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); - return a; - } - if ( bExp == 0 ) { - --expDiff; - } - else { - bSig0 |= LIT64( 0x4000000000000000 ); - } - shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 ); - aSig0 |= LIT64( 0x4000000000000000 ); - aBigger: - sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - zExp = aExp; - normalizeRoundAndPack: - --zExp; - return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of adding the quadruple-precision floating-point values -`a' and `b'. The operation is performed according to the IEC/IEEE Standard -for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float128 float128_add( float128 a, float128 b ) -{ - flag aSign, bSign; - - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign == bSign ) { - return addFloat128Sigs( a, b, aSign ); - } - else { - return subFloat128Sigs( a, b, aSign ); - } - -} - -/* -------------------------------------------------------------------------------- -Returns the result of subtracting the quadruple-precision floating-point -values `a' and `b'. The operation is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float128 float128_sub( float128 a, float128 b ) -{ - flag aSign, bSign; - - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign == bSign ) { - return subFloat128Sigs( a, b, aSign ); - } - else { - return addFloat128Sigs( a, b, aSign ); - } - -} - -/* -------------------------------------------------------------------------------- -Returns the result of multiplying the quadruple-precision floating-point -values `a' and `b'. The operation is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float128 float128_mul( float128 a, float128 b ) -{ - flag aSign, bSign, zSign; - int32 aExp, bExp, zExp; - bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3; - float128 z; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - bSign = extractFloat128Sign( b ); - zSign = aSign ^ bSign; - if ( aExp == 0x7FFF ) { - if ( ( aSig0 | aSig1 ) - || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { - return propagateFloat128NaN( a, b ); - } - if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid; - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - if ( bExp == 0x7FFF ) { - if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); - if ( ( aExp | aSig0 | aSig1 ) == 0 ) { - invalid: - float_raise( float_flag_invalid ); - z.low = float128_default_nan_low; - z.high = float128_default_nan_high; - return z; - } - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - if ( aExp == 0 ) { - if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); - normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); - } - if ( bExp == 0 ) { - if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); - normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); - } - zExp = aExp + bExp - 0x4000; - aSig0 |= LIT64( 0x0001000000000000 ); - shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 ); - mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 ); - add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 ); - zSig2 |= ( zSig3 != 0 ); - if ( LIT64( 0x0002000000000000 ) <= zSig0 ) { - shift128ExtraRightJamming( - zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); - ++zExp; - } - return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of dividing the quadruple-precision floating-point value -`a' by the corresponding value `b'. The operation is performed according to -the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float128 float128_div( float128 a, float128 b ) -{ - flag aSign, bSign, zSign; - int32 aExp, bExp, zExp; - bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; - bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; - float128 z; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - bSign = extractFloat128Sign( b ); - zSign = aSign ^ bSign; - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); - if ( bExp == 0x7FFF ) { - if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); - goto invalid; - } - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - if ( bExp == 0x7FFF ) { - if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); - return packFloat128( zSign, 0, 0, 0 ); - } - if ( bExp == 0 ) { - if ( ( bSig0 | bSig1 ) == 0 ) { - if ( ( aExp | aSig0 | aSig1 ) == 0 ) { - invalid: - float_raise( float_flag_invalid ); - z.low = float128_default_nan_low; - z.high = float128_default_nan_high; - return z; - } - float_raise( float_flag_divbyzero ); - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); - } - if ( aExp == 0 ) { - if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); - normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); - } - zExp = aExp - bExp + 0x3FFD; - shortShift128Left( - aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 ); - shortShift128Left( - bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); - if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) { - shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 ); - ++zExp; - } - zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 ); - mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 ); - sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 ); - while ( (sbits64) rem0 < 0 ) { - --zSig0; - add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 ); - } - zSig1 = estimateDiv128To64( rem1, rem2, bSig0 ); - if ( ( zSig1 & 0x3FFF ) <= 4 ) { - mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 ); - sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 ); - while ( (sbits64) rem1 < 0 ) { - --zSig1; - add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 ); - } - zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); - } - shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 ); - return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the remainder of the quadruple-precision floating-point value `a' -with respect to the corresponding value `b'. The operation is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float128 float128_rem( float128 a, float128 b ) -{ - flag aSign, bSign, zSign; - int32 aExp, bExp, expDiff; - bits64 aSig0, aSig1, bSig0, bSig1; - bits64 q, term0, term1, term2, allZero, alternateASig0, alternateASig1; - bits64 sigMean1; - sbits64 sigMean0; - float128 z; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - bSign = extractFloat128Sign( b ); - if ( aExp == 0x7FFF ) { - if ( ( aSig0 | aSig1 ) - || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { - return propagateFloat128NaN( a, b ); - } - goto invalid; - } - if ( bExp == 0x7FFF ) { - if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); - return a; - } - if ( bExp == 0 ) { - if ( ( bSig0 | bSig1 ) == 0 ) { - invalid: - float_raise( float_flag_invalid ); - z.low = float128_default_nan_low; - z.high = float128_default_nan_high; - return z; - } - normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); - } - if ( aExp == 0 ) { - if ( ( aSig0 | aSig1 ) == 0 ) return a; - normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); - } - expDiff = aExp - bExp; - if ( expDiff < -1 ) return a; - shortShift128Left( - aSig0 | LIT64( 0x0001000000000000 ), - aSig1, - 15 - ( expDiff < 0 ), - &aSig0, - &aSig1 - ); - shortShift128Left( - bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); - q = le128( bSig0, bSig1, aSig0, aSig1 ); - if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); - expDiff -= 64; - while ( 0 < expDiff ) { - q = estimateDiv128To64( aSig0, aSig1, bSig0 ); - q = ( 4 < q ) ? q - 4 : 0; - mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); - shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero ); - shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero ); - sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 ); - expDiff -= 61; - } - if ( -64 < expDiff ) { - q = estimateDiv128To64( aSig0, aSig1, bSig0 ); - q = ( 4 < q ) ? q - 4 : 0; - q >>= - expDiff; - shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); - expDiff += 52; - if ( expDiff < 0 ) { - shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); - } - else { - shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 ); - } - mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); - sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 ); - } - else { - shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 ); - shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); - } - do { - alternateASig0 = aSig0; - alternateASig1 = aSig1; - ++q; - sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); - } while ( 0 <= (sbits64) aSig0 ); - add128( - aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 ); - if ( ( sigMean0 < 0 ) - || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) { - aSig0 = alternateASig0; - aSig1 = alternateASig1; - } - zSign = ( (sbits64) aSig0 < 0 ); - if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 ); - return - normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the square root of the quadruple-precision floating-point value `a'. -The operation is performed according to the IEC/IEEE Standard for Binary -Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float128 float128_sqrt( float128 a ) -{ - flag aSign; - int32 aExp, zExp; - bits64 aSig0, aSig1, zSig0, zSig1, zSig2; - bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; - bits64 shiftedRem0, shiftedRem1; - float128 z; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a ); - if ( ! aSign ) return a; - goto invalid; - } - if ( aSign ) { - if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a; - invalid: - float_raise( float_flag_invalid ); - z.low = float128_default_nan_low; - z.high = float128_default_nan_high; - return z; - } - if ( aExp == 0 ) { - if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 ); - normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); - } - zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE; - aSig0 |= LIT64( 0x0001000000000000 ); - zSig0 = estimateSqrt32( aExp, aSig0>>17 ); - zSig0 <<= 31; - shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 ); - zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4; - if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF ); - shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 ); - mul64To128( zSig0, zSig0, &term0, &term1 ); - sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); - while ( (sbits64) rem0 < 0 ) { - --zSig0; - shortShift128Left( 0, zSig0, 1, &term0, &term1 ); - term1 |= 1; - add128( rem0, rem1, term0, term1, &rem0, &rem1 ); - } - shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 ); - zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 ); - if ( ( zSig1 & 0x3FFF ) <= 5 ) { - if ( zSig1 == 0 ) zSig1 = 1; - mul64To128( zSig0, zSig1, &term1, &term2 ); - shortShift128Left( term1, term2, 1, &term1, &term2 ); - sub128( rem1, 0, term1, term2, &rem1, &rem2 ); - mul64To128( zSig1, zSig1, &term2, &term3 ); - sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); - while ( (sbits64) rem1 < 0 ) { - --zSig1; - shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 ); - term3 |= 1; - add192( - rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 ); - } - zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); - } - shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 ); - return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is equal to -the corresponding value `b', and 0 otherwise. The comparison is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float128_eq( float128 a, float128 b ) -{ - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - if ( float128_is_signaling_nan( a ) - || float128_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - return - ( a.low == b.low ) - && ( ( a.high == b.high ) - || ( ( a.low == 0 ) - && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) - ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is less than -or equal to the corresponding value `b', and 0 otherwise. The comparison -is performed according to the IEC/IEEE Standard for Binary Floating-point -Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float128_le( float128 a, float128 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign != bSign ) { - return - aSign - || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - == 0 ); - } - return - aSign ? le128( b.high, b.low, a.high, a.low ) - : le128( a.high, a.low, b.high, b.low ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is less than -the corresponding value `b', and 0 otherwise. The comparison is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float128_lt( float128 a, float128 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign != bSign ) { - return - aSign - && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - != 0 ); - } - return - aSign ? lt128( b.high, b.low, a.high, a.low ) - : lt128( a.high, a.low, b.high, b.low ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is equal to -the corresponding value `b', and 0 otherwise. The invalid exception is -raised if either operand is a NaN. Otherwise, the comparison is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float128_eq_signaling( float128 a, float128 b ) -{ - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - return - ( a.low == b.low ) - && ( ( a.high == b.high ) - || ( ( a.low == 0 ) - && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) - ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is less than -or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not -cause an exception. Otherwise, the comparison is performed according to the -IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float128_le_quiet( float128 a, float128 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - if ( float128_is_signaling_nan( a ) - || float128_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign != bSign ) { - return - aSign - || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - == 0 ); - } - return - aSign ? le128( b.high, b.low, a.high, a.low ) - : le128( a.high, a.low, b.high, b.low ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the quadruple-precision floating-point value `a' is less than -the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an -exception. Otherwise, the comparison is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float128_lt_quiet( float128 a, float128 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) - || ( ( extractFloat128Exp( b ) == 0x7FFF ) - && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) - ) { - if ( float128_is_signaling_nan( a ) - || float128_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign != bSign ) { - return - aSign - && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) != 0 ); } return diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/nwfpe/softfloat.h linux-2.5/arch/arm/nwfpe/softfloat.h --- linux-2.5.5/arch/arm/nwfpe/softfloat.h Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/arm/nwfpe/softfloat.h Fri Mar 1 15:07:37 2002 @@ -37,12 +37,10 @@ The macro `FLOATX80' must be defined to enable the extended double-precision floating-point format `floatx80'. If this macro is not defined, the `floatx80' type will not be defined, and none of the functions that either -input or output the `floatx80' type will be defined. The same applies to -the `FLOAT128' macro and the quadruple-precision format `float128'. +input or output the `floatx80' type will be defined. ------------------------------------------------------------------------------- */ #define FLOATX80 -/* #define FLOAT128 */ /* ------------------------------------------------------------------------------- @@ -51,17 +49,10 @@ */ typedef unsigned long int float32; typedef unsigned long long float64; -#ifdef FLOATX80 typedef struct { unsigned short high; unsigned long long low; } floatx80; -#endif -#ifdef FLOAT128 -typedef struct { - unsigned long long high, low; -} float128; -#endif /* ------------------------------------------------------------------------------- @@ -131,9 +122,6 @@ #ifdef FLOATX80 floatx80 int32_to_floatx80( signed int ); #endif -#ifdef FLOAT128 -float128 int32_to_float128( signed int ); -#endif /* ------------------------------------------------------------------------------- @@ -146,9 +134,6 @@ #ifdef FLOATX80 floatx80 float32_to_floatx80( float32 ); #endif -#ifdef FLOAT128 -float128 float32_to_float128( float32 ); -#endif /* ------------------------------------------------------------------------------- @@ -181,9 +166,6 @@ #ifdef FLOATX80 floatx80 float64_to_floatx80( float64 ); #endif -#ifdef FLOAT128 -float128 float64_to_float128( float64 ); -#endif /* ------------------------------------------------------------------------------- @@ -216,9 +198,6 @@ signed int floatx80_to_int32_round_to_zero( floatx80 ); float32 floatx80_to_float32( floatx80 ); float64 floatx80_to_float64( floatx80 ); -#ifdef FLOAT128 -float128 floatx80_to_float128( floatx80 ); -#endif /* ------------------------------------------------------------------------------- @@ -247,43 +226,6 @@ char floatx80_le_quiet( floatx80, floatx80 ); char floatx80_lt_quiet( floatx80, floatx80 ); char floatx80_is_signaling_nan( floatx80 ); - -#endif - -#ifdef FLOAT128 - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE quadruple-precision conversion routines. -------------------------------------------------------------------------------- -*/ -signed int float128_to_int32( float128 ); -signed int float128_to_int32_round_to_zero( float128 ); -float32 float128_to_float32( float128 ); -float64 float128_to_float64( float128 ); -#ifdef FLOATX80 -floatx80 float128_to_floatx80( float128 ); -#endif - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE quadruple-precision operations. -------------------------------------------------------------------------------- -*/ -float128 float128_round_to_int( float128 ); -float128 float128_add( float128, float128 ); -float128 float128_sub( float128, float128 ); -float128 float128_mul( float128, float128 ); -float128 float128_div( float128, float128 ); -float128 float128_rem( float128, float128 ); -float128 float128_sqrt( float128 ); -char float128_eq( float128, float128 ); -char float128_le( float128, float128 ); -char float128_lt( float128, float128 ); -char float128_eq_signaling( float128, float128 ); -char float128_le_quiet( float128, float128 ); -char float128_lt_quiet( float128, float128 ); -char float128_is_signaling_nan( float128 ); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/tools/getconstants.c linux-2.5/arch/arm/tools/getconstants.c --- linux-2.5.5/arch/arm/tools/getconstants.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/arm/tools/getconstants.c Tue Feb 26 21:24:48 2002 @@ -32,23 +32,21 @@ #endif #define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n) +#define OFF_VMA(n) (unsigned long)&(((struct vm_area_struct *)0)->n) #define DEFN(name,off) asm("\n#define "name" %0" :: "I" (off)) void func(void) { -#error DEFN("TSK_SIGPENDING", OFF_TSK(sigpending)); -DEFN("TSK_ADDR_LIMIT", OFF_TSK(addr_limit)); -#error DEFN("TSK_NEED_RESCHED", OFF_TSK(need_resched)); -#error DEFN("TSK_PTRACE", OFF_TSK(ptrace)); DEFN("TSK_USED_MATH", OFF_TSK(used_math)); +DEFN("TSK_ACTIVE_MM", OFF_TSK(active_mm)); -DEFN("TSS_SAVE", OFF_TSK(thread.save)); -DEFN("TSS_FPESAVE", OFF_TSK(thread.fpstate.soft.save)); +DEFN("VMA_VM_MM", OFF_VMA(vm_mm)); +DEFN("VMA_VM_FLAGS", OFF_VMA(vm_flags)); -#ifdef CONFIG_CPU_32 -DEFN("TSS_DOMAIN", OFF_TSK(thread.domain)); +DEFN("VM_EXEC", VM_EXEC); +#ifdef CONFIG_CPU_32 DEFN("HPTE_TYPE_SMALL", PTE_TYPE_SMALL); DEFN("HPTE_AP_READ", PTE_AP_READ); DEFN("HPTE_AP_WRITE", PTE_AP_WRITE); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/arm/tools/mach-types linux-2.5/arch/arm/tools/mach-types --- linux-2.5.5/arch/arm/tools/mach-types Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/arm/tools/mach-types Fri Mar 1 15:07:37 2002 @@ -6,7 +6,7 @@ # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Fri Jan 4 10:27:21 2002 +# Last update: Sun Feb 24 17:43:42 2002 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -118,10 +118,10 @@ cdb89712 ARCH_CDB89712 CDB89712 107 graphicsmaster SA1100_GRAPHICSMASTER GRAPHICSMASTER 108 adsbitsy SA1100_ADSBITSY ADSBITSY 109 -cotulla_idp ARCH_COTULLA_IDP COTULLA_IDP 110 +pxa_idp ARCH_PXA_IDP PXA_IDP 110 plce ARCH_PLCE PLCE 111 pt_system3 SA1100_PT_SYSTEM3 PT_SYSTEM3 112 -medalb ARCH_MEDALB MEDALB 113 +murphy ARCH_MEDALB MEDALB 113 eagle ARCH_EAGLE EAGLE 114 dsc21 ARCH_DSC21 DSC21 115 dsc24 ARCH_DSC24 DSC24 116 @@ -162,3 +162,15 @@ cep SA1100_CEP CEP 151 fortunet ARCH_FORTUNET FORTUNET 152 vc547x ARCH_VC547X VC547X 153 +filewalker SA1100_FILEWALKER FILEWALKER 154 +netgateway SA1100_NETGATEWAY NETGATEWAY 155 +symbol2800 SA1100_SYMBOL2800 SYMBOL2800 156 +suns SA1100_SUNS SUNS 157 +frodo SA1100_FRODO FRODO 158 +ms301 SA1100_MACH_TYTE_MS301 MACH_TYTE_MS301 159 +mx1ads ARCH_MX1ADS MX1ADS 160 +h7201 ARCH_H7201 H7201 161 +h7202 ARCH_H7202 H7202 162 +amico ARCH_AMICO AMICO 163 +iam SA1100_IAM IAM 164 +tt530 SA1100_TT530 TT530 165 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/cris/boot/Makefile linux-2.5/arch/cris/boot/Makefile --- linux-2.5.5/arch/cris/boot/Makefile Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/cris/boot/Makefile Fri Feb 8 03:15:29 2002 @@ -8,6 +8,8 @@ @$(MAKE) -C compressed vmlinuz dep: + @$(MAKE) -C compressed depend + @$(MAKE) -C rescue depend clean: rm -f zImage tools/build compressed/vmlinux.out diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/cris/boot/compressed/Makefile linux-2.5/arch/cris/boot/compressed/Makefile --- linux-2.5.5/arch/cris/boot/compressed/Makefile Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/cris/boot/compressed/Makefile Fri Feb 8 03:15:29 2002 @@ -4,6 +4,13 @@ # create a compressed vmlinux image from the original vmlinux files and romfs # +ifndef TOPDIR +TOPDIR = ../../../.. +HPATH = $(TOPDIR)/include +export HPATH +endif + + CC = gcc-cris -melf -I $(TOPDIR)/include CFLAGS = -O2 LD = ld-cris @@ -37,4 +44,10 @@ clean: rm -f piggy.img vmlinuz vmlinuz.o + +depend: + $(CC) -M *.S *.c > .depend + +-include .depend + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/cris/boot/rescue/Makefile linux-2.5/arch/cris/boot/rescue/Makefile --- linux-2.5.5/arch/cris/boot/rescue/Makefile Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/cris/boot/rescue/Makefile Fri Feb 8 03:15:29 2002 @@ -3,6 +3,8 @@ # ifndef TOPDIR TOPDIR = ../../../.. +HPATH = $(TOPDIR)/include +export HPATH endif CC = gcc-cris -mlinux -I $(TOPDIR)/include CFLAGS = -O2 @@ -35,7 +37,7 @@ dd if=kimagerescue_tmp.bin of=kimagerescue.bin bs=1 count=784 rm ktr.bin tmp2423 kimagerescue_tmp.bin -head.o: head.S +head.o: head.S $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o testrescue.o: testrescue.S @@ -52,3 +54,8 @@ modules: modules-install: + +depend: + $(CC) -M *.S > .depend + +-include .depend diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/cris/config.in linux-2.5/arch/cris/config.in --- linux-2.5.5/arch/cris/config.in Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/cris/config.in Thu Feb 14 02:57:57 2002 @@ -205,10 +205,8 @@ fi endmenu -# -# input before char - char/joystick depends on it. As does USB. -# source drivers/input/Config.in + source drivers/char/Config.in #source drivers/misc/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/cris/drivers/ethernet.c linux-2.5/arch/cris/drivers/ethernet.c --- linux-2.5.5/arch/cris/drivers/ethernet.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/cris/drivers/ethernet.c Fri Feb 8 03:15:29 2002 @@ -530,6 +530,15 @@ IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | IO_STATE(R_NETWORK_GEN_CONFIG, enable, on); + *R_NETWORK_TR_CTRL = + IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr) | + IO_STATE(R_NETWORK_TR_CTRL, delay, none) | + IO_STATE(R_NETWORK_TR_CTRL, cancel, dont) | + IO_STATE(R_NETWORK_TR_CTRL, cd, enable) | + IO_STATE(R_NETWORK_TR_CTRL, retry, enable) | + IO_STATE(R_NETWORK_TR_CTRL, pad, enable) | + IO_STATE(R_NETWORK_TR_CTRL, crc, enable); + save_flags(flags); cli(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/cris/drivers/gpio.c linux-2.5/arch/cris/drivers/gpio.c --- linux-2.5.5/arch/cris/drivers/gpio.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/cris/drivers/gpio.c Tue Jan 22 16:20:05 2002 @@ -217,7 +217,7 @@ gpio_open(struct inode *inode, struct file *filp) { struct gpio_private *priv; - int p = MINOR(inode->i_rdev); + int p = minor(inode->i_rdev); if (p >= NUM_PORTS && p != LEDS) return -EINVAL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/cris/drivers/lpslave/e100lpslavenet.c linux-2.5/arch/cris/drivers/lpslave/e100lpslavenet.c --- linux-2.5.5/arch/cris/drivers/lpslave/e100lpslavenet.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/cris/drivers/lpslave/e100lpslavenet.c Tue Feb 26 20:14:01 2002 @@ -313,7 +313,7 @@ IO_STATE(R_PAR0_CONFIG, iautofd, noninv) | /* Not used in reverse direction, don't care */ IO_STATE(R_PAR0_CONFIG, istrb, noninv) | - /* Not connected, don't care / + /* Not connected, don't care */ IO_STATE(R_PAR0_CONFIG, iinit, noninv) | /* perror is GND and reverse wants 0, noninv */ IO_STATE(R_PAR0_CONFIG, iperr, noninv) | diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/cris/drivers/serial.c linux-2.5/arch/cris/drivers/serial.c --- linux-2.5.5/arch/cris/drivers/serial.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/cris/drivers/serial.c Fri Feb 8 03:15:29 2002 @@ -363,8 +363,7 @@ #define TTY_THROTTLE_LIMIT (TTY_FLIPBUF_SIZE/10) -#define SERIAL_RECV_SIZE 4096 -#define SERIAL_DESCR_BUF_SIZE 512 +#define SERIAL_DESCR_BUF_SIZE 256 /* Add an x here to log a lot of timer stuff */ #define TIMERD(x) @@ -1260,15 +1259,56 @@ #define START_FLUSH_FAST_TIMER(info, string) #endif +static struct etrax_recv_buffer * +alloc_recv_buffer(unsigned int size) +{ + struct etrax_recv_buffer *buffer; + + if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC))) + return NULL; + + buffer->next = NULL; + buffer->length = 0; + buffer->error = TTY_NORMAL; + + return buffer; +} + +static void +append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + if (!info->first_recv_buffer) + info->first_recv_buffer = buffer; + else + info->last_recv_buffer->next = buffer; + + info->last_recv_buffer = buffer; + + info->recv_cnt += buffer->length; + if (info->recv_cnt > info->max_recv_cnt) + info->max_recv_cnt = info->recv_cnt; + + restore_flags(flags); +} + static int add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag) { - if (!CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE)) + struct etrax_recv_buffer *buffer; + + if (!(buffer = alloc_recv_buffer(4))) return 0; - info->recv.buf[info->recv.head] = data; - info->flag_buf[info->recv.head] = flag; - info->recv.head = (info->recv.head + 1) & (SERIAL_RECV_SIZE - 1); + buffer->length = 1; + buffer->error = flag; + buffer->buffer[0] = data; + + append_recv_buffer(info, buffer); info->icount.rx++; @@ -1276,33 +1316,33 @@ } static _INLINE_ unsigned int -copy_descr_data(struct e100_serial *info, unsigned int recvl, unsigned char *buf) +handle_descr_data(struct e100_serial *info, struct etrax_dma_descr *descr, unsigned int recvl) { - unsigned int count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); - unsigned int length = 0; - - while (length < recvl && count) { - if (length + count > recvl) - count = recvl - length; - - memcpy(info->recv.buf + info->recv.head, buf + length, count); - memset(info->flag_buf + info->recv.head, '\0', count); - info->recv.head = (info->recv.head + count) & (SERIAL_RECV_SIZE - 1); - length += count; + struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer; - count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); + if (info->recv_cnt + recvl > 65536) { + printk(__FUNCTION__ ": Too much pending incoming serial data! Dropping %u bytes.\n", recvl); + return 0; } - if (length != recvl) { - printk(__FUNCTION__ ": Buffer overflow! %d byte(s) did not fit.\n", recvl - length); - PROCSTAT(ser_stat[info->line].overrun_cnt += recvl - length); - } + buffer->length = recvl; + + if (info->errorcode == ERRCODE_SET_BREAK) + buffer->error = TTY_BREAK; + info->errorcode = 0; - return length; + append_recv_buffer(info, buffer); + + if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + panic(__FUNCTION__ ": Failed to allocate memory for receive buffer!\n"); + + descr->buf = virt_to_phys(buffer->buffer); + + return recvl; } static _INLINE_ unsigned int -copy_all_descr_data(struct e100_serial *info) +handle_all_descr_data(struct e100_serial *info) { struct etrax_dma_descr *descr; unsigned int recvl; @@ -1336,7 +1376,7 @@ /* update stats */ info->icount.rx += recvl; - ret += copy_descr_data(info, recvl, phys_to_virt(descr->buf)); + ret += handle_descr_data(info, descr, recvl); } return ret; @@ -1347,7 +1387,6 @@ { struct tty_struct *tty; unsigned char rstat; - unsigned int old_head; #ifdef CONFIG_SVINTO_SIM /* No receive in the simulator. Will probably be when the rest of @@ -1372,12 +1411,7 @@ if (info->errorcode == ERRCODE_INSERT_BREAK) add_char_and_flag(info, '\0', TTY_BREAK); - old_head = info->recv.head; - - if (copy_all_descr_data(info) && info->errorcode == ERRCODE_SET_BREAK) - info->flag_buf[old_head] = TTY_BREAK; - - info->errorcode = 0; + handle_all_descr_data(info); /* Read the status register to detect errors */ rstat = info->port[REG_STATUS]; @@ -1400,10 +1434,6 @@ add_char_and_flag(info, data, TTY_FRAME); } - if (!E100_RTS_GET(info) && - CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) < TTY_THROTTLE_LIMIT) - info->tty->driver.throttle(info->tty); - START_FLUSH_FAST_TIMER(info, "receive_chars"); /* Restart the receiving DMA */ @@ -1414,19 +1444,20 @@ start_recv_dma(struct e100_serial *info) { struct etrax_dma_descr *descr = info->rec_descr; - unsigned char *buf = info->recv.buf + 2*SERIAL_RECV_SIZE; + struct etrax_recv_buffer *buffer; int i; /* Set up the receiving descriptors */ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) { + if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + panic(__FUNCTION__ ": Failed to allocate memory for receive buffer!\n"); + descr[i].ctrl = d_int; - descr[i].buf = virt_to_phys(buf); + descr[i].buf = virt_to_phys(buffer->buffer); descr[i].sw_len = SERIAL_DESCR_BUF_SIZE; descr[i].hw_len = 0; descr[i].status = 0; descr[i].next = virt_to_phys(&descr[i+1]); - - buf += SERIAL_DESCR_BUF_SIZE; } /* Link the last descriptor to the first */ @@ -1618,11 +1649,11 @@ flush_to_flip_buffer(struct e100_serial *info) { struct tty_struct *tty = info->tty; - unsigned int count = CIRC_CNT_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); + struct etrax_recv_buffer *buffer; unsigned int length; unsigned long flags; - if (!count) + if (!info->first_recv_buffer) return; save_flags(flags); @@ -1630,19 +1661,31 @@ length = tty->flip.count; - do { + while ((buffer = info->first_recv_buffer) && length < TTY_FLIPBUF_SIZE) { + unsigned int count = buffer->length; + if (length + count > TTY_FLIPBUF_SIZE) count = TTY_FLIPBUF_SIZE - length; - memcpy(tty->flip.char_buf_ptr + length, info->recv.buf + info->recv.tail, count); - memcpy(tty->flip.flag_buf_ptr + length, info->flag_buf + info->recv.tail, count); - info->recv.tail = ((info->recv.tail + count) & (SERIAL_RECV_SIZE-1)); + memcpy(tty->flip.char_buf_ptr + length, buffer->buffer, count); + memset(tty->flip.flag_buf_ptr + length, TTY_NORMAL, count); + tty->flip.flag_buf_ptr[length] = buffer->error; + length += count; - - count = CIRC_CNT_TO_END(info->recv.head, - info->recv.tail, - SERIAL_RECV_SIZE); - } while (length < TTY_FLIPBUF_SIZE && count); + info->recv_cnt -= count; + + if (count == buffer->length) { + info->first_recv_buffer = buffer->next; + kfree(buffer); + } else { + buffer->length -= count; + memmove(buffer->buffer, buffer->buffer + count, buffer->length); + buffer->error = TTY_NORMAL; + } + } + + if (!info->first_recv_buffer) + info->last_recv_buffer = NULL; tty->flip.count = length; @@ -1654,11 +1697,6 @@ #else queue_task_irq_off(&tty->flip.tqueue, &tq_timer); #endif - - /* unthrottle if we have throttled */ - if (E100_RTS_GET(info) && - CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) > TTY_THROTTLE_LIMIT) - tty->driver.unthrottle(info->tty); } static _INLINE_ void @@ -1668,7 +1706,7 @@ flush_to_flip_buffer(info); - if (CIRC_CNT(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE)) + if (info->first_recv_buffer) START_FLUSH_FAST_TIMER(info, "flip"); } @@ -2005,18 +2043,12 @@ { unsigned long flags; unsigned long xmit_page; - unsigned char *recv_page; + int i; xmit_page = get_zeroed_page(GFP_KERNEL); if (!xmit_page) return -ENOMEM; - recv_page = kmalloc(2 * SERIAL_RECV_SIZE + SERIAL_RECV_DESCRIPTORS * SERIAL_DESCR_BUF_SIZE, GFP_KERNEL); - if (!recv_page) { - free_page(xmit_page); - return -ENOMEM; - } - save_flags(flags); cli(); /* if it was already initialized, skip this */ @@ -2024,7 +2056,6 @@ if (info->flags & ASYNC_INITIALIZED) { restore_flags(flags); free_page(xmit_page); - kfree(recv_page); return 0; } @@ -2033,13 +2064,6 @@ else info->xmit.buf = (unsigned char *) xmit_page; - if (info->recv.buf) - kfree(recv_page); - else { - info->recv.buf = (unsigned char *) recv_page; - info->flag_buf = info->recv.buf + SERIAL_RECV_SIZE; - } - #ifdef SERIAL_DEBUG_OPEN printk("starting up ttyS%d (xmit_buf 0x%p, recv_buf 0x%p)...\n", info->line, info->xmit.buf, info->recv.buf); #endif @@ -2050,8 +2074,13 @@ right? */ if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit.head = info->xmit.tail = 0; - info->recv.head = info->recv.tail = 0; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; + + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + info->rec_descr[i].buf = NULL; /* No real action in the simulator, but may set info important to ioctl. */ @@ -2090,8 +2119,12 @@ clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit.head = info->xmit.tail = 0; - info->recv.head = info->recv.tail = 0; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + info->rec_descr[i].buf = 0; + /* * and set the speed and other flags of the serial port * this will start the rx/tx as well @@ -2143,6 +2176,9 @@ shutdown(struct e100_serial * info) { unsigned long flags; + struct etrax_dma_descr *descr = info->rec_descr; + struct etrax_recv_buffer *buffer; + int i; #ifndef CONFIG_SVINTO_SIM /* shut down the transmitter and receiver */ @@ -2179,11 +2215,12 @@ info->xmit.buf = NULL; } - if (info->recv.buf) { - kfree(info->recv.buf); - info->recv.buf = NULL; - info->flag_buf = NULL; - } + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + if (descr[i].buf) { + buffer = phys_to_virt(descr[i].buf) - sizeof *buffer; + kfree(buffer); + descr[i].buf = 0; + } if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { /* hang up DTR and RTS if HUPCL is enabled */ @@ -3413,6 +3450,10 @@ (unsigned long)info->icount.tx, (unsigned long)info->icount.rx); + ret += sprintf(buf+ret, " rx_pend:%lu/%lu", + (unsigned long)info->recv_cnt, + (unsigned long)info->max_recv_cnt); + if (info->icount.frame) ret += sprintf(buf+ret, " fe:%lu", (unsigned long)info->icount.frame); @@ -3581,9 +3622,8 @@ init_waitqueue_head(&info->close_wait); info->xmit.buf = NULL; info->xmit.tail = info->xmit.head = 0; - info->recv.buf = NULL; - info->recv.tail = info->recv.head = 0; - info->flag_buf = NULL; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; info->last_tx_active_usec = 0; info->last_tx_active = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/cris/drivers/serial.h linux-2.5/arch/cris/drivers/serial.h --- linux-2.5.5/arch/cris/drivers/serial.h Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/cris/drivers/serial.h Fri Feb 8 03:15:29 2002 @@ -25,6 +25,15 @@ #define SERIAL_RECV_DESCRIPTORS 8 +struct etrax_recv_buffer { + struct etrax_recv_buffer *next; + unsigned short length; + unsigned char error; + unsigned char pad; + + unsigned char buffer[0]; +}; + struct e100_serial { int baud; volatile u8 *port; /* R_SERIALx_CTRL */ @@ -81,8 +90,10 @@ long session; /* Session of opening process */ long pgrp; /* pgrp of opening process */ struct circ_buf xmit; - struct circ_buf recv; - unsigned char *flag_buf; + struct etrax_recv_buffer *first_recv_buffer; + struct etrax_recv_buffer *last_recv_buffer; + unsigned int recv_cnt; + unsigned int max_recv_cnt; struct tq_struct tqueue; struct async_icount icount; /* error-statistics etc.*/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/cris/kernel/ksyms.c linux-2.5/arch/cris/kernel/ksyms.c --- linux-2.5.5/arch/cris/kernel/ksyms.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/cris/kernel/ksyms.c Mon Feb 18 21:47:24 2002 @@ -38,9 +38,7 @@ /* String functions */ EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strpbrk); -EXPORT_SYMBOL(simple_strtol); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strchr); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/Config.help linux-2.5/arch/i386/Config.help --- linux-2.5.5/arch/i386/Config.help Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/i386/Config.help Mon Mar 4 01:22:55 2002 @@ -128,6 +128,12 @@ If unsure, say "off". +CONFIG_HIGHPTE + The VM uses one page table entry for each page of physical memory. + For systems with a lot of RAM, this can be wasteful of precious + low memory. Setting this option will put user-space page table + entries in high memory. + CONFIG_HIGHMEM4G Select this if you have a 32-bit processor and between 1 and 4 gigabytes of physical RAM. @@ -798,6 +804,20 @@ a work-around for a number of buggy BIOSes. Switch this option on if your computer crashes instead of powering off properly. +CONFIG_X86_MCE + Machine Check Exception support allows the processor to notify the + kernel if it detects a problem (e.g. overheating, component failure). + The action the kernel takes depends on the severity of the problem, + ranging from a warning message on the console, to halting the machine. + Your processor must be a Pentium or newer to support this - check the + flags in /proc/cpuinfo for mce. Note that some older Pentium systems + have a design flaw which leads to false MCE events - hence MCE is + disabled on all P5 processors, unless explicitly enabled with "mce" + as a boot argument. Similarly, if MCE is built in and creates a + problem on some new non-standard machine, you can boot with "nomce" + to disable it. MCE support simply ignores non-MCE processors like + the 386 and 486, so nearly everyone can say Y here. + CONFIG_TOSHIBA This adds a driver to safely access the System Management Mode of the CPU on Toshiba portables with a genuine Toshiba BIOS. It does @@ -932,3 +952,6 @@ of the BUG call as well as the EIP and oops trace. This aids debugging but costs about 70-100K of memory. +CONFIG_DEBUG_OBSOLETE + Say Y here if you want to reduce the chances of the tree compiling, + and are prepared to dig into driver internals to fix compile errors. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/boot/setup.S linux-2.5/arch/i386/boot/setup.S --- linux-2.5.5/arch/i386/boot/setup.S Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/i386/boot/setup.S Thu Jan 24 19:36:18 2002 @@ -42,6 +42,9 @@ * if CX/DX have been changed in the e801 call and if so use AX/BX . * Michael Miller, April 2001 * + * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes + * by Robert Schwebel, December 2001 + * */ #include @@ -544,7 +547,7 @@ cmpw $0, %cs:realmode_swtch jz rmodeswtch_normal - lcall *%cs:realmode_swtch + lcall %cs:realmode_swtch jmp rmodeswtch_end @@ -651,7 +654,18 @@ # # Enable A20. This is at the very best an annoying procedure. # A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin. +# AMD Elan bug fix by Robert Schwebel. # + +#if defined(CONFIG_MELAN) + movb $0x02, %al # alternate A20 gate + outb %al, $0x92 # this works on SC410/SC520 +a20_elan_wait: + call a20_test + jz a20_elan_wait + jmp a20_done +#endif + A20_TEST_LOOPS = 32 # Iterations per wait A20_ENABLE_LOOPS = 255 # Total loops to try diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/config.in linux-2.5/arch/i386/config.in --- linux-2.5.5/arch/i386/config.in Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/i386/config.in Mon Mar 4 01:22:55 2002 @@ -25,6 +25,7 @@ Pentium-4 CONFIG_MPENTIUM4 \ K6/K6-II/K6-III CONFIG_MK6 \ Athlon/Duron/K7 CONFIG_MK7 \ + Elan CONFIG_MELAN \ Crusoe CONFIG_MCRUSOE \ Winchip-C6 CONFIG_MWINCHIPC6 \ Winchip-2 CONFIG_MWINCHIP2 \ @@ -114,6 +115,11 @@ define_bool CONFIG_X86_PGE y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y fi +if [ "$CONFIG_MELAN" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_SHIFT 4 + define_bool CONFIG_X86_USE_STRING_486 y + define_bool CONFIG_X86_ALIGNMENT_16 y +fi if [ "$CONFIG_MCYRIXIII" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 define_bool CONFIG_X86_TSC y @@ -145,6 +151,9 @@ define_bool CONFIG_X86_USE_PPRO_CHECKSUM y define_bool CONFIG_X86_OOSTORE y fi + +bool 'Machine Check Exception' CONFIG_X86_MCE + tristate 'Toshiba Laptop support' CONFIG_TOSHIBA tristate 'Dell laptop support' CONFIG_I8K @@ -155,25 +164,20 @@ choice 'High Memory Support' \ "off CONFIG_NOHIGHMEM \ 4GB CONFIG_HIGHMEM4G \ - 4GB-highpte CONFIG_HIGHMEM4G_HIGHPTE \ - 64GB CONFIG_HIGHMEM64G \ - 64GB-highpte CONFIG_HIGHMEM64G_HIGHPTE" off -if [ "$CONFIG_HIGHMEM4G" = "y" ]; then - define_bool CONFIG_HIGHMEM y + 64GB CONFIG_HIGHMEM64G" off + +if [ "$CONFIG_HIGHMEM4G" = "y" -o "$CONFIG_HIGHMEM64G" = "y" ]; then + bool 'Use high memory pte support' CONFIG_HIGHPTE fi -if [ "$CONFIG_HIGHMEM4G_HIGHPTE" = "y" ]; then + +if [ "$CONFIG_HIGHMEM4G" = "y" ]; then define_bool CONFIG_HIGHMEM y - define_bool CONFIG_HIGHPTE y fi + if [ "$CONFIG_HIGHMEM64G" = "y" ]; then define_bool CONFIG_HIGHMEM y define_bool CONFIG_X86_PAE y fi -if [ "$CONFIG_HIGHMEM64G_HIGHPTE" = "y" ]; then - define_bool CONFIG_HIGHMEM y - define_bool CONFIG_HIGHPTE y - define_bool CONFIG_X86_PAE y -fi bool 'Math emulation' CONFIG_MATH_EMULATION bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR @@ -364,10 +368,8 @@ fi endmenu -# -# input before char - char/joystick depends on it. As does USB. -# source drivers/input/Config.in + source drivers/char/Config.in #source drivers/misc/Config.in @@ -408,10 +410,12 @@ bool 'Kernel debugging' CONFIG_DEBUG_KERNEL if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then + bool ' Disable obsolete code' CONFIG_DEBUG_OBSOLETE bool ' Debug memory allocations' CONFIG_DEBUG_SLAB bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK + bool ' Debug 486 string copies' CONFIG_DEBUG_486_STRING if [ "$CONFIG_HIGHMEM" = "y" ]; then bool ' Highmem debugging' CONFIG_DEBUG_HIGHMEM fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/defconfig linux-2.5/arch/i386/defconfig --- linux-2.5.5/arch/i386/defconfig Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/i386/defconfig Sun Mar 3 17:54:35 2002 @@ -57,6 +57,7 @@ CONFIG_X86_GOOD_APIC=y CONFIG_X86_PGE=y CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_MCE=y # CONFIG_TOSHIBA is not set # CONFIG_I8K is not set # CONFIG_MICROCODE is not set @@ -105,6 +106,7 @@ # CONFIG_HOTPLUG_PCI is not set # CONFIG_HOTPLUG_PCI_COMPAQ is not set # CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_IBM is not set CONFIG_KCORE_ELF=y # CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_AOUT=y @@ -121,7 +123,18 @@ # # Parallel port support # -# CONFIG_PARPORT is not set +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y +CONFIG_PARPORT_PC_CML1=y +# CONFIG_PARPORT_SERIAL is not set +# CONFIG_PARPORT_PC_PCMCIA is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_1284 is not set # # Plug and Play configuration @@ -333,6 +346,8 @@ # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_SYM53C8XX_2 is not set @@ -454,6 +469,7 @@ # # CONFIG_ACENIC is not set # CONFIG_DL2K is not set +# CONFIG_E1000 is not set # CONFIG_MYRI_SBUS is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set @@ -488,10 +504,10 @@ # CONFIG_PCMCIA_3C574 is not set # CONFIG_PCMCIA_FMVJ18X is not set CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_AXNET is not set # CONFIG_PCMCIA_NMCLAN is not set # CONFIG_PCMCIA_SMC91C92 is not set # CONFIG_PCMCIA_XIRC2PS is not set -# CONFIG_PCMCIA_AXNET is not set # CONFIG_ARCNET_COM20020_CS is not set # CONFIG_PCMCIA_IBMTR is not set # CONFIG_PCMCIA_XIRCOM is not set @@ -523,21 +539,61 @@ # # Input device support # -# CONFIG_INPUT is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=y +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set # CONFIG_GAMEPORT is not set CONFIG_SOUND_GAMEPORT=y # CONFIG_GAMEPORT_NS558 is not set # CONFIG_GAMEPORT_L4 is not set # CONFIG_INPUT_EMU10K1 is not set -# CONFIG_GAMEPORT_PCIGAME is not set # CONFIG_GAMEPORT_FM801 is not set # CONFIG_GAMEPORT_CS461x is not set -# CONFIG_SERIO is not set -# CONFIG_SERIO_SERPORT is not set +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_PS2SERKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_SERIAL=y +# CONFIG_MOUSE_GUNZE is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE_USB is not set +# CONFIG_JOYSTICK_IFORCE_232 is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDDLER is not set +# CONFIG_JOYSTICK_DB9 is not set +# CONFIG_JOYSTICK_GAMECON is not set +# CONFIG_JOYSTICK_TURBOGRAFX is not set # # Character devices @@ -550,20 +606,14 @@ # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_PRINTER=y +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set # # I2C support # # CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -CONFIG_MOUSE=y -CONFIG_PSMOUSE=y -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set # CONFIG_QIC02_TAPE is not set # @@ -596,6 +646,7 @@ CONFIG_DRM_RADEON=y # CONFIG_DRM_I810 is not set # CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set # # PCMCIA character devices @@ -668,6 +719,7 @@ # CONFIG_ROOT_NFS is not set CONFIG_NFSD=y # CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set @@ -710,19 +762,28 @@ # Advanced Linux Sound Architecture # CONFIG_SND=y -# CONFIG_SND_RTCTIMER is not set CONFIG_SND_SEQUENCER=y # CONFIG_SND_SEQ_DUMMY is not set CONFIG_SND_OSSEMUL=y CONFIG_SND_MIXER_OSS=y CONFIG_SND_PCM_OSS=y CONFIG_SND_SEQUENCER_OSS=y +# CONFIG_SND_RTCTIMER is not set +# CONFIG_SND_VERBOSE_PRINTK is not set # CONFIG_SND_DEBUG is not set + +# +# Generic devices +# # CONFIG_SND_DUMMY is not set # CONFIG_SND_VIRMIDI is not set # CONFIG_SND_MTPAV is not set # CONFIG_SND_SERIAL_U16550 is not set # CONFIG_SND_MPU401 is not set + +# +# ISA devices +# # CONFIG_SND_AD1816A is not set # CONFIG_SND_AD1848 is not set # CONFIG_SND_CS4231 is not set @@ -749,6 +810,10 @@ # CONFIG_SND_DT0197H is not set # CONFIG_SND_OPL3SA2 is not set # CONFIG_SND_SGALAXY is not set + +# +# PCI devices +# # CONFIG_SND_ALI5451 is not set # CONFIG_SND_CS46XX is not set # CONFIG_SND_EMU10K1 is not set @@ -791,7 +856,7 @@ # CONFIG_USB_EHCI_HCD is not set # CONFIG_USB_OHCI_HCD is not set CONFIG_USB_UHCI_ALT=y -# CONFIG_USB_OHCI is not set +CONFIG_USB_OHCI=y # # USB Device Class drivers @@ -813,10 +878,9 @@ # # USB Human Interface Devices (HID) # - -# -# Input core support is needed for USB HID -# +CONFIG_USB_HID=y +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_WACOM is not set # # USB Imaging devices diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/Makefile linux-2.5/arch/i386/kernel/Makefile --- linux-2.5.5/arch/i386/kernel/Makefile Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/i386/kernel/Makefile Sat Jan 26 03:55:51 2002 @@ -18,7 +18,8 @@ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ - pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o + pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o \ + bootflag.o ifdef CONFIG_PCI @@ -31,6 +32,7 @@ endif obj-$(CONFIG_MCA) += mca.o +obj-$(CONFIG_EISA) += eisa.o obj-$(CONFIG_MTRR) += mtrr.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/acpitable.c linux-2.5/arch/i386/kernel/acpitable.c --- linux-2.5.5/arch/i386/kernel/acpitable.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/i386/kernel/acpitable.c Thu Jan 17 11:56:13 2002 @@ -172,40 +172,41 @@ /* - * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_0, + * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END, * to map the target physical address. The problem is that set_fixmap() * provides a single page, and it is possible that the page is not * sufficient. * By using this area, we can map up to MAX_IO_APICS pages temporarily, * i.e. until the next __va_range() call. + * + * Important Safety Note: The fixed I/O APIC page numbers are *subtracted* + * from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and + * count idx down while incrementing the phys address. */ -static __inline__ char * +static __init char * __va_range(unsigned long phys, unsigned long size) { - unsigned long base, offset, mapped_size, mapped_phys = phys; - int idx = FIX_IO_APIC_BASE_0; + unsigned long base, offset, mapped_size; + int idx; offset = phys & (PAGE_SIZE - 1); mapped_size = PAGE_SIZE - offset; - set_fixmap(idx, mapped_phys); - base = fix_to_virt(FIX_IO_APIC_BASE_0); + set_fixmap(FIX_IO_APIC_BASE_END, phys); + base = fix_to_virt(FIX_IO_APIC_BASE_END); + dprintk("__va_range(0x%lx, 0x%lx): idx=%d mapped at %lx\n", phys, size, + FIX_IO_APIC_BASE_END, base); /* * Most cases can be covered by the below. */ - if (mapped_size >= size) - return ((unsigned char *) base + offset); - - dprintk("__va_range: mapping more than a single page, size = 0x%lx\n", - size); - - do { - if (idx++ == FIX_IO_APIC_BASE_END) + idx = FIX_IO_APIC_BASE_END; + while (mapped_size < size) { + if (--idx < FIX_IO_APIC_BASE_0) return 0; /* cannot handle this */ - mapped_phys = mapped_phys + PAGE_SIZE; - set_fixmap(idx, mapped_phys); - mapped_size = mapped_size + PAGE_SIZE; - } while (mapped_size < size); + phys += PAGE_SIZE; + set_fixmap(idx, phys); + mapped_size += PAGE_SIZE; + } return ((unsigned char *) base + offset); } @@ -267,11 +268,14 @@ } for (i = 0; i < tables; i++) { - + /* Map in header, then map in full table length. */ header = (acpi_table_header *) __va_range(saved_rsdt.entry[i], sizeof(acpi_table_header)); - + if (!header) + break; + header = (acpi_table_header *) + __va_range(saved_rsdt.entry[i], header->length); if (!header) break; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/apic.c linux-2.5/arch/i386/kernel/apic.c --- linux-2.5.5/arch/i386/kernel/apic.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/i386/kernel/apic.c Tue Jan 29 13:37:38 2002 @@ -90,7 +90,7 @@ apic_write_around(APIC_LVTPC, APIC_LVT_MASKED); v = GET_APIC_VERSION(apic_read(APIC_LVR)); if (APIC_INTEGRATED(v)) { /* !82489DX */ - if (maxlvt > 3) + if (maxlvt > 3) /* Due to Pentium errata 3AP and 11AP. */ apic_write(APIC_ESR, 0); apic_read(APIC_ESR); } @@ -582,12 +582,17 @@ * Detect and enable local APICs on non-SMP boards. * Original code written by Keir Fraser. */ +int dont_enable_local_apic __initdata = 0; static int __init detect_init_APIC (void) { u32 h, l, features; extern void get_cpu_vendor(struct cpuinfo_x86*); + /* Disabled by DMI scan or kernel option? */ + if (dont_enable_local_apic) + return -1; + /* Workaround for us being called before identify_cpu(). */ get_cpu_vendor(&boot_cpu_data); @@ -903,8 +908,14 @@ static unsigned int calibration_result; +int dont_use_local_apic_timer __initdata = 0; + void __init setup_APIC_clocks (void) { + /* Disabled by DMI scan or kernel option? */ + if (dont_use_local_apic_timer) + return; + printk("Using local APIC timer interrupts.\n"); using_apic_timer = 1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/apm.c linux-2.5/arch/i386/kernel/apm.c --- linux-2.5.5/arch/i386/kernel/apm.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/arch/i386/kernel/apm.c Wed Jan 23 01:45:56 2002 @@ -812,7 +812,7 @@ t1 = IDLE_LEAKY_MAX; - while (need_resched()) { + while (!need_resched()) { if (use_apm_idle) { unsigned int t; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/bluesmoke.c linux-2.5/arch/i386/kernel/bluesmoke.c --- linux-2.5.5/arch/i386/kernel/bluesmoke.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/i386/kernel/bluesmoke.c Tue Mar 5 13:58:36 2002 @@ -3,17 +3,20 @@ #include #include #include +#include #include #include +#ifdef CONFIG_X86_MCE + static int mce_disabled __initdata = 0; +static int banks; + /* * Machine Check Handler For PII/PIII */ -static int banks; - static void intel_machine_check(struct pt_regs * regs, long error_code) { int recover=1; @@ -41,13 +44,12 @@ if(high&(1<<27)) { rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh); - printk("[%08x%08x]", alow, ahigh); + printk("[%08x%08x]", ahigh, alow); } if(high&(1<<26)) { rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh); - printk(" at %08x%08x", - ahigh, alow); + printk(" at %08x%08x", ahigh, alow); } printk("\n"); /* Clear it */ @@ -201,33 +203,48 @@ printk(KERN_INFO "Winchip machine check reporting enabled on CPU#%d.\n", smp_processor_id()); } +struct timer_list mce_timer; + +static void K7_mce_timer (unsigned long data) +{ + printk (KERN_WARNING "Checking for non fatal correctable error.\n"); + mce_timer.expires = jiffies + 5 * HZ; + add_timer (&mce_timer); +} /* * This has to be run for each processor */ - - void __init mcheck_init(struct cpuinfo_x86 *c) { if(mce_disabled==1) return; + /* Set the timer to check for non-fatal errors every 5 seconds */ + init_timer (&mce_timer); + mce_timer.expires = jiffies + 5 * HZ; + mce_timer.data = 0; + switch(c->x86_vendor) { case X86_VENDOR_AMD: - /* - * AMD K7 machine check is Intel like - */ - if(c->x86 == 6) + /* AMD K7 machine check is Intel like */ + if(c->x86 == 6) { intel_mcheck_init(c); + mce_timer.function = &K7_mce_timer; + add_timer (&mce_timer); + } break; + case X86_VENDOR_INTEL: intel_mcheck_init(c); break; + case X86_VENDOR_CENTAUR: winchip_mcheck_init(c); break; + default: break; } @@ -247,3 +264,8 @@ __setup("nomce", mcheck_disable); __setup("mce", mcheck_enable); + +#else +asmlinkage void do_machine_check(struct pt_regs * regs, long error_code) {} +void __init mcheck_init(struct cpuinfo_x86 *c) {} +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/bootflag.c linux-2.5/arch/i386/kernel/bootflag.c --- linux-2.5.5/arch/i386/kernel/bootflag.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/i386/kernel/bootflag.c Mon Dec 31 18:32:31 2001 @@ -0,0 +1,253 @@ +/* + * Implement 'Simple Boot Flag Specification 1.0' + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#define SBF_RESERVED (0x78) +#define SBF_PNPOS (1<<0) +#define SBF_BOOTING (1<<1) +#define SBF_DIAG (1<<2) +#define SBF_PARITY (1<<7) + + +struct sbf_boot +{ + u8 sbf_signature[4]; + u32 sbf_len; + u8 sbf_revision __attribute((packed)); + u8 sbf_csum __attribute((packed)); + u8 sbf_oemid[6] __attribute((packed)); + u8 sbf_oemtable[8] __attribute((packed)); + u8 sbf_revdata[4] __attribute((packed)); + u8 sbf_creator[4] __attribute((packed)); + u8 sbf_crearev[4] __attribute((packed)); + u8 sbf_cmos __attribute((packed)); + u8 sbf_spare[3] __attribute((packed)); +}; + + +static int sbf_port __initdata = -1; + +static int __init sbf_struct_valid(unsigned long tptr) +{ + u8 *ap; + u8 v; + unsigned int i; + struct sbf_boot sb; + + memcpy_fromio(&sb, tptr, sizeof(sb)); + + if(sb.sbf_len != 40 && sb.sbf_len != 39) + // 39 on IBM ThinkPad A21m, BIOS version 1.02b (KXET24WW; 2000-12-19). + return 0; + + ap = (u8 *)&sb; + v= 0; + + for(i=0;i>=1; + } + return x; +} + +static void __init sbf_write(u8 v) +{ + unsigned long flags; + if(sbf_port != -1) + { + v &= ~SBF_PARITY; + if(!parity(v)) + v|=SBF_PARITY; + + printk(KERN_INFO "SBF: Setting boot flags 0x%x\n",v); + + spin_lock_irqsave(&rtc_lock, flags); + CMOS_WRITE(v, sbf_port); + spin_unlock_irqrestore(&rtc_lock, flags); + } +} + +static u8 __init sbf_read(void) +{ + u8 v; + unsigned long flags; + if(sbf_port == -1) + return 0; + spin_lock_irqsave(&rtc_lock, flags); + v = CMOS_READ(sbf_port); + spin_unlock_irqrestore(&rtc_lock, flags); + return v; +} + +static int __init sbf_value_valid(u8 v) +{ + if(v&SBF_RESERVED) /* Reserved bits */ + return 0; + if(!parity(v)) + return 0; + return 1; +} + + +static void __init sbf_bootup(void) +{ + u8 v; + if(sbf_port == -1) + return; + v = sbf_read(); + if(!sbf_value_valid(v)) + printk(KERN_WARNING "SBF: Simple boot flag value 0x%x read from CMOS RAM was invalid\n",v); + v &= ~SBF_RESERVED; + v &= ~SBF_BOOTING; + v &= ~SBF_DIAG; +#if defined(CONFIG_ISAPNP) + v |= SBF_PNPOS; +#endif + sbf_write(v); +} + +static int __init sbf_init(void) +{ + unsigned int i; + void *rsdt; + u32 rsdtlen = 0; + u32 rsdtbase = 0; + u8 sum = 0; + int n; + + u8 *p; + + for(i=0xE0000; i <= 0xFFFE0; i+=16) + { + p = phys_to_virt(i); + + if(memcmp(p, "RSD PTR ", 8)) + continue; + + sum = 0; + for(n=0; n<20; n++) + sum+=p[n]; + + if(sum != 0) + continue; + + /* So it says RSD PTR and it checksums... */ + + /* + * Process the RDSP pointer + */ + + rsdtbase = *(u32 *)(p+16); + + /* + * RSDT length is ACPI 2 only, for ACPI 1 we must map + * and remap. + */ + + if(p[15]>1) + rsdtlen = *(u32 *)(p+20); + else + rsdtlen = 36; + + if(rsdtlen < 36 || rsdtlen > 1024) + continue; + break; + } + if(i>0xFFFE0) + return 0; + + + rsdt = ioremap(rsdtbase, rsdtlen); + if(rsdt == 0) + return 0; + + i = readl(rsdt + 4); + + /* + * Remap if needed + */ + + if(i > rsdtlen) + { + rsdtlen = i; + iounmap(rsdt); + rsdt = ioremap(rsdtbase, rsdtlen); + if(rsdt == 0) + return 0; + } + + for(n = 0; n < i; n++) + sum += readb(rsdt + n); + + if(sum) + { + iounmap(rsdt); + return 0; + } + + /* Ok the RSDT checksums too */ + + for(n = 36; n+3 < i; n += 4) + { + unsigned long rp = readl(rsdt+n); + int len = 4096; + + if(rp > 0xFFFFFFFFUL - len) + len = 0xFFFFFFFFUL - rp; + + /* Too close to the end!! */ + if(len < 20) + continue; + rp = (unsigned long)ioremap(rp, 4096); + if(rp == 0) + continue; + if(sbf_struct_valid(rp)) + { + /* Found the BOOT table and processed it */ + printk(KERN_INFO "SBF: Simple Boot Flag extension found and enabled.\n"); + } + iounmap((void *)rp); + } + iounmap(rsdt); + sbf_bootup(); + return 0; +} + +module_init(sbf_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/cpuid.c linux-2.5/arch/i386/kernel/cpuid.c --- linux-2.5.5/arch/i386/kernel/cpuid.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/i386/kernel/cpuid.c Mon Feb 18 03:39:04 2002 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/dmi_scan.c linux-2.5/arch/i386/kernel/dmi_scan.c --- linux-2.5.5/arch/i386/kernel/dmi_scan.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/i386/kernel/dmi_scan.c Mon Mar 4 01:05:57 2002 @@ -9,6 +9,7 @@ #include #include #include +#include unsigned long dmi_broken; int is_sony_vaio_laptop; @@ -51,7 +52,7 @@ u8 *data; int i=1; - buf = ioremap(base, len); + buf = bt_ioremap(base, len); if(buf==NULL) return -1; @@ -83,7 +84,7 @@ data+=2; i++; } - iounmap(buf); + bt_iounmap(buf, len); return 0; } @@ -155,7 +156,7 @@ return; if (dmi_ident[slot]) return; - dmi_ident[slot] = kmalloc(strlen(p)+1, GFP_KERNEL); + dmi_ident[slot] = alloc_bootmem(strlen(p)+1); if(dmi_ident[slot]) strcpy(dmi_ident[slot], p); else @@ -294,6 +295,22 @@ return 0; } +/* + * Work around broken HP Pavilion Notebooks which assign USB to + * IRQ 9 even though it is actually wired to IRQ 11 + */ +static __init int fix_broken_hp_bios_irq9(struct dmi_blacklist *d) +{ +#ifdef CONFIG_PCI + extern int broken_hp_bios_irq9; + if (broken_hp_bios_irq9 == 0) + { + broken_hp_bios_irq9 = 1; + printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); + } +#endif + return 0; +} /* * Check for clue free BIOS implementations who use @@ -416,6 +433,62 @@ return 0; } +/* + * Some machines, usually laptops, can't handle an enabled local APIC. + * The symptoms include hangs or reboots when suspending or resuming, + * attaching or detaching the power cord, or entering BIOS setup screens + * through magic key sequences. + */ +static int __init local_apic_kills_bios(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_enable_local_apic; + if (!dont_enable_local_apic) { + dont_enable_local_apic = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "Refusing to enable the local APIC.\n", + d->ident); + } +#endif + return 0; +} + +/* + * The Microstar 6163-2 (a.k.a Pro) mainboard will hang shortly after + * resumes, and also at what appears to be asynchronous APM events, + * if the local APIC is enabled. + */ +static int __init apm_kills_local_apic(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_enable_local_apic; + if (apm_info.bios.version && !dont_enable_local_apic) { + dont_enable_local_apic = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "Refusing to enable the local APIC.\n", + d->ident); + } +#endif + return 0; +} + +/* + * The Intel AL440LX mainboard will hang randomly if the local APIC + * timer is running and the APM BIOS hasn't been disabled. + */ +static int __init apm_kills_local_apic_timer(struct dmi_blacklist *d) +{ +#ifdef CONFIG_X86_LOCAL_APIC + extern int dont_use_local_apic_timer; + if (apm_info.bios.version && !dont_use_local_apic_timer) { + dont_use_local_apic_timer = 1; + printk(KERN_WARNING "%s with broken BIOS detected. " + "The local APIC timer will not be used.\n", + d->ident); + } +#endif + return 0; +} /* * Simple "print if true" callback @@ -469,6 +542,11 @@ MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), NO_MATCH, NO_MATCH } }, + { set_bios_reboot, "Dell PowerEdge 2400", { /* Handle problems with rebooting on Dell 300/800's */ + MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"), + NO_MATCH, NO_MATCH + } }, { set_apm_ints, "Dell Inspiron", { /* Allow interrupts during suspend on Dell Inspiron laptops*/ MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), MATCH(DMI_PRODUCT_NAME, "Inspiron 4000"), @@ -490,6 +568,11 @@ MATCH(DMI_PRODUCT_NAME, "Delhi3"), NO_MATCH, NO_MATCH, } }, + { apm_is_horked, "Fujitsu-Siemens", { /* APM crashes */ + MATCH(DMI_BIOS_VENDOR, "hoenix/FUJITSU SIEMENS"), + MATCH(DMI_BIOS_VERSION, "Version1.01"), + NO_MATCH, NO_MATCH, + } }, { apm_is_horked, "Sharp PC-PJ/AX", { /* APM crashes */ MATCH(DMI_SYS_VENDOR, "SHARP"), MATCH(DMI_PRODUCT_NAME, "PC-PJ/AX"), @@ -560,6 +643,36 @@ MATCH(DMI_BIOS_DATE, "09/12/00"), NO_MATCH } }, + /* Machines which have problems handling enabled local APICs */ + + { local_apic_kills_bios, "Dell Inspiron", { + MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + MATCH(DMI_PRODUCT_NAME, "Inspiron"), + NO_MATCH, NO_MATCH + } }, + + { local_apic_kills_bios, "Dell Latitude", { + MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + MATCH(DMI_PRODUCT_NAME, "Latitude"), + NO_MATCH, NO_MATCH + } }, + + { local_apic_kills_bios, "IBM Thinkpad T20", { + MATCH(DMI_BOARD_VENDOR, "IBM"), + MATCH(DMI_BOARD_NAME, "264741U"), + NO_MATCH, NO_MATCH + } }, + + { apm_kills_local_apic, "Microstar 6163", { + MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), + MATCH(DMI_BOARD_NAME, "MS-6163"), + NO_MATCH, NO_MATCH } }, + + { apm_kills_local_apic_timer, "Intel AL440LX", { + MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), + MATCH(DMI_BOARD_NAME, "AL440LX"), + NO_MATCH, NO_MATCH } }, + /* Problem Intel 440GX bioses */ { broken_pirq, "SABR1 Bios", { /* Bad $PIR */ @@ -588,7 +701,7 @@ NO_MATCH, NO_MATCH } }, - /* Intel in disgiuse - In this case they can't hide and they don't run + /* Intel in disguise - In this case they can't hide and they don't run too well either... */ { broken_pirq, "Dell PowerEdge 8450", { /* Bad $PIR */ MATCH(DMI_PRODUCT_NAME, "Dell PowerEdge 8450"), @@ -616,7 +729,14 @@ NO_MATCH, NO_MATCH } }, - + { fix_broken_hp_bios_irq9, "HP Pavilion N5400 Series Laptop", { + MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + MATCH(DMI_BIOS_VERSION, "GE.M1.03"), + MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"), + MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736") + } }, + + /* * Generic per vendor APM settings */ @@ -728,12 +848,9 @@ } } -static int __init dmi_scan_machine(void) +void __init dmi_scan_machine(void) { int err = dmi_iterate(dmi_decode); if(err == 0) dmi_check_blacklist(); - return err; } - -module_init(dmi_scan_machine); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/eisa.c linux-2.5/arch/i386/kernel/eisa.c --- linux-2.5.5/arch/i386/kernel/eisa.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/i386/kernel/eisa.c Wed Feb 20 23:18:38 2002 @@ -0,0 +1,55 @@ +/* + * linux/arch/i386/kernel/eisa.c + * + * Copyright (C) 2002 Dave Jones + * + */ + +#include +#include +#include + +struct device *eisa_iobus; + +void __init init_eisa(void) +{ + struct device *eisa_dev; + int eisa_addr=0; + int id, id2; + + return; /* this is currently broken, I'll fix it later.*/ + + if (EISA_bus==0) + return; + + eisa_iobus = kmalloc(sizeof(*(eisa_iobus)),GFP_KERNEL); + memset (eisa_iobus, 0, sizeof(*(eisa_iobus))); + sprintf (eisa_iobus->bus_id, "eisa"); + sprintf (eisa_iobus->name, "EISA bus"); + device_register(eisa_iobus); + + while (eisa_addr < 0x9000) { + + id = inw(eisa_addr+0xC80); + if (id!=0xffff) { + id2 = inw(eisa_addr+0xC81); + + eisa_dev = kmalloc (sizeof (struct device), GFP_KERNEL); + if (eisa_dev == NULL) + return; + + memset (eisa_dev, 0, sizeof(struct device)); + + /* FIXME: This should export *3* 5-bit numbers. Euch. */ + sprintf (eisa_dev->name, "EISA device %x%x", id, id2); + sprintf (eisa_dev->bus_id, "%d", eisa_addr/0x1000); + eisa_dev->parent = eisa_iobus; + device_register(eisa_dev); + } + + eisa_addr += 0x1000; + } +} + +subsys_initcall(init_eisa); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/head.S linux-2.5/arch/i386/kernel/head.S --- linux-2.5.5/arch/i386/kernel/head.S Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/i386/kernel/head.S Fri Feb 8 02:15:53 2002 @@ -82,7 +82,7 @@ * Initialize page tables */ movl $pg0-__PAGE_OFFSET,%edi /* initialize page tables */ - movl $007,%eax /* "007" doesn't mean with right to kill, but + movl $007,%eax /* "007" doesn't mean with license to kill, but PRESENT+RW+USER */ 2: stosl add $0x1000,%eax diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/i386_ksyms.c linux-2.5/arch/i386/kernel/i386_ksyms.c --- linux-2.5.5/arch/i386/kernel/i386_ksyms.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/i386/kernel/i386_ksyms.c Mon Feb 25 19:06:04 2002 @@ -32,7 +32,7 @@ extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; -#if defined(CONFIG_APM_MODULE) +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) extern void machine_real_restart(unsigned char *, int); EXPORT_SYMBOL(machine_real_restart); extern void default_idle(void); @@ -53,9 +53,7 @@ /* platform dependent support */ EXPORT_SYMBOL(boot_cpu_data); -#ifdef CONFIG_EISA EXPORT_SYMBOL(EISA_bus); -#endif EXPORT_SYMBOL(MCA_bus); EXPORT_SYMBOL(__verify_write); EXPORT_SYMBOL(dump_thread); @@ -73,6 +71,7 @@ EXPORT_SYMBOL(get_cmos_time); EXPORT_SYMBOL(apm_info); EXPORT_SYMBOL(gdt); +EXPORT_SYMBOL(empty_zero_page); #ifdef CONFIG_DEBUG_IOVIRT EXPORT_SYMBOL(__io_virt_debug); @@ -93,7 +92,6 @@ EXPORT_SYMBOL_NOVERS(__get_user_2); EXPORT_SYMBOL_NOVERS(__get_user_4); -EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/i8259.c linux-2.5/arch/i386/kernel/i8259.c --- linux-2.5.5/arch/i386/kernel/i8259.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/i386/kernel/i8259.c Tue Feb 26 21:24:48 2002 @@ -79,7 +79,6 @@ * through the ICC by us (IPIs) */ #ifdef CONFIG_SMP -BUILD_SMP_INTERRUPT(task_migration_interrupt,TASK_MIGRATION_VECTOR) BUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) @@ -473,9 +472,6 @@ * IPI, driven by wakeup. */ set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); - - /* IPI for task migration */ - set_intr_gate(TASK_MIGRATION_VECTOR, task_migration_interrupt); /* IPI for invalidation */ set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/microcode.c linux-2.5/arch/i386/kernel/microcode.c --- linux-2.5.5/arch/i386/kernel/microcode.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/i386/kernel/microcode.c Sun Mar 3 17:54:35 2002 @@ -51,6 +51,10 @@ * Bugfix for HT (Hyper-Threading) enabled processors * whereby processor resources are shared by all logical processors * in a single CPU package. + * 1.10 28 Feb 2002 Asit K Mallick and + * Tigran Aivazian , + * Serialize updates as required on HT processors due to speculative + * nature of implementation. */ #include @@ -60,12 +64,16 @@ #include #include #include +#include #include #include #include -#define MICROCODE_VERSION "1.09" + +static spinlock_t microcode_update_lock = SPIN_LOCK_UNLOCKED; + +#define MICROCODE_VERSION "1.10" MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver"); MODULE_AUTHOR("Tigran Aivazian "); @@ -195,7 +203,8 @@ struct cpuinfo_x86 *c = cpu_data + cpu_num; struct update_req *req = update_req + cpu_num; unsigned int pf = 0, val[2], rev, sig; - int i,found=0; + unsigned long flags; + int i; req->err = 1; /* assume update will fail on this cpu */ @@ -216,8 +225,9 @@ for (i=0; islot = i; + + /* serialize access to update decision */ + spin_lock_irqsave(µcode_update_lock, flags); + /* trick, to work even if there was no prior update by the BIOS */ wrmsr(MSR_IA32_UCODE_REV, 0, 0); __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx"); /* get current (on-cpu) revision into rev (ignore val[0]) */ rdmsr(MSR_IA32_UCODE_REV, val[0], rev); + if (microcode[i].rev < rev) { + spin_unlock_irqrestore(µcode_update_lock, flags); printk(KERN_ERR - "microcode: CPU%d not 'upgrading' to earlier revision" + "microcode: CPU%d not 'upgrading' to earlier revision" + " %d (current=%d)\n", cpu_num, microcode[i].rev, rev); + return; + } else if (microcode[i].rev == rev) { + /* notify the caller of success on this cpu */ + req->err = 0; + spin_unlock_irqrestore(µcode_update_lock, flags); + printk(KERN_ERR + "microcode: CPU%d already at revision" " %d (current=%d)\n", cpu_num, microcode[i].rev, rev); - } else { - int sum = 0; - struct microcode *m = µcode[i]; - unsigned int *sump = (unsigned int *)(m+1); - - while (--sump >= (unsigned int *)m) - sum += *sump; - if (sum != 0) { - printk(KERN_ERR "microcode: CPU%d aborting, " - "bad checksum\n", cpu_num); - break; - } - - /* write microcode via MSR 0x79 */ - wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0); + return; + } - /* serialize */ - __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx"); + /* Verify the checksum */ + while (--sump >= (unsigned int *)m) + sum += *sump; + if (sum != 0) { + req->err = 1; + spin_unlock_irqrestore(µcode_update_lock, flags); + printk(KERN_ERR "microcode: CPU%d aborting, " + "bad checksum\n", cpu_num); + return; + } + + /* write microcode via MSR 0x79 */ + wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0); - /* get the current revision from MSR 0x8B */ - rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); + /* serialize */ + __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx"); - /* notify the caller of success on this cpu */ - req->err = 0; - req->slot = i; + /* get the current revision from MSR 0x8B */ + rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); - printk(KERN_INFO "microcode: CPU%d updated from revision " - "%d to %d, date=%08x\n", - cpu_num, rev, val[1], m->date); - } - break; + /* notify the caller of success on this cpu */ + req->err = 0; + spin_unlock_irqrestore(µcode_update_lock, flags); + printk(KERN_INFO "microcode: CPU%d updated from revision " + "%d to %d, date=%08x\n", + cpu_num, rev, val[1], microcode[i].date); + return; } - - if(!found) - printk(KERN_ERR "microcode: CPU%d no microcode found! (sig=%x, pflags=%d)\n", - cpu_num, sig, pf); + + printk(KERN_ERR + "microcode: CPU%d no microcode found! (sig=%x, pflags=%d)\n", + cpu_num, sig, pf); } + static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/mpparse.c linux-2.5/arch/i386/kernel/mpparse.c --- linux-2.5.5/arch/i386/kernel/mpparse.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/i386/kernel/mpparse.c Sun Mar 3 17:54:35 2002 @@ -37,6 +37,8 @@ int apic_version [MAX_APICS]; int mp_bus_id_to_type [MAX_MP_BUSSES]; int mp_bus_id_to_node [MAX_MP_BUSSES]; +int mp_bus_id_to_local [MAX_MP_BUSSES]; +int quad_local_to_mp_bus_id [NR_CPUS/4][4]; int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; int mp_current_pci_id; @@ -241,13 +243,17 @@ static void __init MP_bus_info (struct mpc_config_bus *m) { char str[7]; + int quad; memcpy(str, m->mpc_bustype, 6); str[6] = 0; if (clustered_apic_mode) { - mp_bus_id_to_node[m->mpc_busid] = translation_table[mpc_record]->trans_quad; - printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, mp_bus_id_to_node[m->mpc_busid]); + quad = translation_table[mpc_record]->trans_quad; + mp_bus_id_to_node[m->mpc_busid] = quad; + mp_bus_id_to_local[m->mpc_busid] = translation_table[mpc_record]->trans_local; + quad_local_to_mp_bus_id[quad][translation_table[mpc_record]->trans_local] = m->mpc_busid; + printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, quad); } else { Dprintk("Bus #%d is %s\n", m->mpc_busid, str); } @@ -324,13 +330,14 @@ static void __init MP_translation_info (struct mpc_config_translation *m) { - printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, - m->trans_quad, m->trans_global, m->trans_local); + printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, m->trans_quad, m->trans_global, m->trans_local); if (mpc_record >= MAX_MPC_ENTRY) printk("MAX_MPC_ENTRY exceeded!\n"); else translation_table[mpc_record] = m; /* stash this for later */ + if (m->trans_quad+1 > numnodes) + numnodes = m->trans_quad+1; } /* @@ -495,10 +502,6 @@ } ++mpc_record; } - if (clustered_apic_mode && nr_ioapics > 2) { - /* don't initialise IO apics on secondary quads */ - nr_ioapics = 2; - } if (!num_processors) printk(KERN_ERR "SMP mptable: no processors registered!\n"); return num_processors; @@ -799,11 +802,13 @@ * trustworthy, simply because the SMP table may have been * stomped on during early boot. These loaders are buggy and * should be fixed. + * + * MP1.4 SPEC states to only scan first 1K of 4K EBDA. */ address = *(unsigned short *)phys_to_virt(0x40E); address <<= 4; - smp_scan_config(address, 0x1000); + smp_scan_config(address, 0x400); if (smp_found_config) printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n"); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/mtrr.c linux-2.5/arch/i386/kernel/mtrr.c --- linux-2.5.5/arch/i386/kernel/mtrr.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/arch/i386/kernel/mtrr.c Wed Jan 16 20:56:13 2002 @@ -498,7 +498,6 @@ case MTRR_IF_INTEL: rdmsr (MTRRcap_MSR, config, dummy); return (config & (1<<10)); - return 1; case MTRR_IF_AMD_K6: case MTRR_IF_CENTAUR_MCR: case MTRR_IF_CYRIX_ARR: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/nmi.c linux-2.5/arch/i386/kernel/nmi.c --- linux-2.5.5/arch/i386/kernel/nmi.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/i386/kernel/nmi.c Fri Feb 8 02:15:53 2002 @@ -8,6 +8,7 @@ * Fixes: * Mikael Pettersson : AMD K7 support for local APIC NMI watchdog. * Mikael Pettersson : Power Management for local APIC NMI watchdog. + * Mikael Pettersson : Pentium 4 support for local APIC NMI watchdog. */ #include @@ -43,6 +44,32 @@ #define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79 #define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED +#define MSR_P4_MISC_ENABLE 0x1A0 +#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7) +#define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL (1<<12) +#define MSR_P4_PERFCTR0 0x300 +#define MSR_P4_CCCR0 0x360 +#define P4_ESCR_EVENT_SELECT(N) ((N)<<25) +#define P4_ESCR_OS (1<<3) +#define P4_ESCR_USR (1<<2) +#define P4_CCCR_OVF_PMI (1<<26) +#define P4_CCCR_THRESHOLD(N) ((N)<<20) +#define P4_CCCR_COMPLEMENT (1<<19) +#define P4_CCCR_COMPARE (1<<18) +#define P4_CCCR_REQUIRED (3<<16) +#define P4_CCCR_ESCR_SELECT(N) ((N)<<13) +#define P4_CCCR_ENABLE (1<<12) +/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter + CRU_ESCR0 (with any non-null event selector) through a complemented + max threshold. [IA32-Vol3, Section 14.9.9] */ +#define MSR_P4_IQ_COUNTER0 0x30C +#define MSR_P4_IQ_CCCR0 0x36C +#define MSR_P4_CRU_ESCR0 0x3B8 +#define P4_NMI_CRU_ESCR0 (P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR) +#define P4_NMI_IQ_CCCR0 \ + (P4_CCCR_OVF_PMI|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT| \ + P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE) + int __init check_nmi_watchdog (void) { irq_cpustat_t tmp[NR_CPUS]; @@ -84,11 +111,11 @@ /* * If any other x86 CPU has a local APIC, then * please test the NMI stuff there and send me the - * missing bits. Right now Intel P6 and AMD K7 only. + * missing bits. Right now Intel P6/P4 and AMD K7 only. */ if ((nmi == NMI_LOCAL_APIC) && (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && - (boot_cpu_data.x86 == 6)) + (boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15)) nmi_watchdog = nmi; if ((nmi == NMI_LOCAL_APIC) && (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && @@ -118,7 +145,15 @@ wrmsr(MSR_K7_EVNTSEL0, 0, 0); break; case X86_VENDOR_INTEL: - wrmsr(MSR_IA32_EVNTSEL0, 0, 0); + switch (boot_cpu_data.x86) { + case 6: + wrmsr(MSR_P6_EVNTSEL0, 0, 0); + break; + case 15: + wrmsr(MSR_P4_IQ_CCCR0, 0, 0); + wrmsr(MSR_P4_CRU_ESCR0, 0, 0); + break; + } break; } } @@ -157,17 +192,22 @@ * Original code written by Keith Owens. */ +static void __pminit clear_msr_range(unsigned int base, unsigned int n) +{ + unsigned int i; + + for(i = 0; i < n; ++i) + wrmsr(base+i, 0, 0); +} + static void __pminit setup_k7_watchdog(void) { - int i; unsigned int evntsel; nmi_perfctr_msr = MSR_K7_PERFCTR0; - for(i = 0; i < 4; ++i) { - wrmsr(MSR_K7_EVNTSEL0+i, 0, 0); - wrmsr(MSR_K7_PERFCTR0+i, 0, 0); - } + clear_msr_range(MSR_K7_EVNTSEL0, 4); + clear_msr_range(MSR_K7_PERFCTR0, 4); evntsel = K7_EVNTSEL_INT | K7_EVNTSEL_OS @@ -184,27 +224,54 @@ static void __pminit setup_p6_watchdog(void) { - int i; unsigned int evntsel; - nmi_perfctr_msr = MSR_IA32_PERFCTR0; + nmi_perfctr_msr = MSR_P6_PERFCTR0; - for(i = 0; i < 2; ++i) { - wrmsr(MSR_IA32_EVNTSEL0+i, 0, 0); - wrmsr(MSR_IA32_PERFCTR0+i, 0, 0); - } + clear_msr_range(MSR_P6_EVNTSEL0, 2); + clear_msr_range(MSR_P6_PERFCTR0, 2); evntsel = P6_EVNTSEL_INT | P6_EVNTSEL_OS | P6_EVNTSEL_USR | P6_NMI_EVENT; - wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0); - Dprintk("setting IA32_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000)); - wrmsr(MSR_IA32_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0); + wrmsr(MSR_P6_EVNTSEL0, evntsel, 0); + Dprintk("setting P6_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000)); + wrmsr(MSR_P6_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0); apic_write(APIC_LVTPC, APIC_DM_NMI); evntsel |= P6_EVNTSEL0_ENABLE; - wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0); + wrmsr(MSR_P6_EVNTSEL0, evntsel, 0); +} + +static int __pminit setup_p4_watchdog(void) +{ + unsigned int misc_enable, dummy; + + rdmsr(MSR_P4_MISC_ENABLE, misc_enable, dummy); + if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL)) + return 0; + + nmi_perfctr_msr = MSR_P4_IQ_COUNTER0; + + if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL)) + clear_msr_range(0x3F1, 2); + /* MSR 0x3F0 seems to have a default value of 0xFC00, but current + docs doesn't fully define it, so leave it alone for now. */ + clear_msr_range(0x3A0, 31); + clear_msr_range(0x3C0, 6); + clear_msr_range(0x3C8, 6); + clear_msr_range(0x3E0, 2); + clear_msr_range(MSR_P4_CCCR0, 18); + clear_msr_range(MSR_P4_PERFCTR0, 18); + + wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0); + wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0); + Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000)); + wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1); + apic_write(APIC_LVTPC, APIC_DM_NMI); + wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0); + return 1; } void __pminit setup_apic_nmi_watchdog (void) @@ -216,9 +283,17 @@ setup_k7_watchdog(); break; case X86_VENDOR_INTEL: - if (boot_cpu_data.x86 != 6) + switch (boot_cpu_data.x86) { + case 6: + setup_p6_watchdog(); + break; + case 15: + if (!setup_p4_watchdog()) + return; + break; + default: return; - setup_p6_watchdog(); + } break; default: return; @@ -296,6 +371,18 @@ last_irq_sums[cpu] = sum; alert_counter[cpu] = 0; } - if (nmi_perfctr_msr) + if (nmi_perfctr_msr) { + if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) { + /* + * P4 quirks: + * - An overflown perfctr will assert its interrupt + * until the OVF flag in its CCCR is cleared. + * - LVTPC is masked on interrupt and must be + * unmasked by the LVTPC handler. + */ + wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0); + apic_write(APIC_LVTPC, APIC_DM_NMI); + } wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1); + } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/pci-irq.c linux-2.5/arch/i386/kernel/pci-irq.c --- linux-2.5.5/arch/i386/kernel/pci-irq.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/i386/kernel/pci-irq.c Mon Feb 25 19:11:32 2002 @@ -22,6 +22,8 @@ #define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) #define PIRQ_VERSION 0x0100 +int broken_hp_bios_irq9; + static struct irq_routing_table *pirq_table; /* @@ -225,12 +227,12 @@ */ static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { - return read_config_nybble(router, 0x5C, pirq-1); + return read_config_nybble(router, 0x5C, (pirq-1)^1); } static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) { - write_config_nybble(router, 0x5C, pirq-1, irq); + write_config_nybble(router, 0x5C, (pirq-1)^1, irq); return 1; } @@ -443,7 +445,12 @@ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set }, { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, pirq_piix_get, pirq_piix_set }, { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set }, + { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, pirq_piix_get, pirq_piix_set }, + { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, pirq_piix_get, pirq_piix_set }, { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set }, + { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set }, + { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set }, + { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set }, { "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set }, @@ -564,6 +571,15 @@ } DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs); mask &= pcibios_irq_mask; + + /* Work around broken HP Pavilion Notebooks which assign USB to + IRQ 9 even though it is actually wired to IRQ 11 */ + + if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) { + dev->irq = 11; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); + r->set(pirq_router_dev, dev, pirq, 11); + } /* * Find the best IRQ to assign: use the one diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/pci-pc.c linux-2.5/arch/i386/kernel/pci-pc.c --- linux-2.5.5/arch/i386/kernel/pci-pc.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/i386/kernel/pci-pc.c Sun Mar 3 17:54:35 2002 @@ -14,6 +14,7 @@ #include #include +#include #include "pci-i386.h" @@ -26,6 +27,16 @@ int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL; int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL; +#ifdef CONFIG_MULTIQUAD +#define BUS2QUAD(global) (mp_bus_id_to_node[global]) +#define BUS2LOCAL(global) (mp_bus_id_to_local[global]) +#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local]) +#else +#define BUS2QUAD(global) (0) +#define BUS2LOCAL(global) (global) +#define QUADLOCAL2BUS(quad,local) (local) +#endif + /* * This interrupt-safe spinlock protects all accesses to PCI * configuration space. @@ -39,10 +50,71 @@ #ifdef CONFIG_PCI_DIRECT +#ifdef CONFIG_MULTIQUAD +#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ + (0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) + +static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* CONFIG_MULTIQUAD */ +{ + unsigned long flags; + + if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus)); + + switch (len) { + case 1: + *value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus)); + break; + case 2: + *value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus)); + break; + case 4: + *value = inl_quad(0xCFC, BUS2QUAD(bus)); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* CONFIG_MULTIQUAD */ +{ + unsigned long flags; + + if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + return -EINVAL; + + spin_lock_irqsave(&pci_config_lock, flags); + + outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus)); + + switch (len) { + case 1: + outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus)); + break; + case 2: + outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus)); + break; + case 4: + outl_quad((u32)value, 0xCFC, BUS2QUAD(bus)); + break; + } + + spin_unlock_irqrestore(&pci_config_lock, flags); + + return 0; +} + +#else /* !CONFIG_MULTIQUAD */ #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) -static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* !CONFIG_MULTIQUAD */ { unsigned long flags; @@ -70,7 +142,7 @@ return 0; } -static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* !CONFIG_MULTIQUAD */ { unsigned long flags; @@ -98,6 +170,8 @@ return 0; } +#endif /* CONFIG_MULTIQUAD */ + #undef PCI_CONF1_ADDRESS static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value) @@ -1017,6 +1091,8 @@ */ int pxb, reg; u8 busno, suba, subb; + int quad = BUS2QUAD(d->bus->number); + printk("PCI: Searching for i450NX host bridges on %s\n", d->slot_name); reg = 0xd0; for(pxb=0; pxb<2; pxb++) { @@ -1025,9 +1101,9 @@ pci_read_config_byte(d, reg++, &subb); DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); if (busno) - pci_scan_bus(busno, pci_root_ops, NULL); /* Bus A */ + pci_scan_bus(QUADLOCAL2BUS(quad,busno), pci_root_ops, NULL); /* Bus A */ if (suba < subb) - pci_scan_bus(suba+1, pci_root_ops, NULL); /* Bus B */ + pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), pci_root_ops, NULL); /* Bus B */ } pcibios_last_bus = -1; } @@ -1129,7 +1205,8 @@ pci_read_config_byte(d, where, &v); if (v & 0xe0) { - printk("Disabling broken memory write queue.\n"); + printk("Disabling broken memory write queue: [%02x] %02x->%02x\n", + where, v, v & 0x1f); v &= 0x1f; /* clear bits 5, 6, 7 */ pci_write_config_byte(d, where, v); } @@ -1199,6 +1276,8 @@ void __init pcibios_init(void) { + int quad; + if (!pci_root_ops) pcibios_config_init(); if (!pci_root_ops) { @@ -1208,6 +1287,14 @@ printk("PCI: Probing PCI hardware\n"); pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL); + if (clustered_apic_mode && (numnodes > 1)) { + for (quad = 1; quad < numnodes; ++quad) { + printk("Scanning PCI bus %d for quad %d\n", + QUADLOCAL2BUS(quad,0), quad); + pci_scan_bus(QUADLOCAL2BUS(quad,0), + pci_root_ops, NULL); + } + } pcibios_irq_init(); pcibios_fixup_peer_bridges(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/process.c linux-2.5/arch/i386/kernel/process.c --- linux-2.5.5/arch/i386/kernel/process.c Wed Feb 20 02:10:52 2002 +++ linux-2.5/arch/i386/kernel/process.c Thu Feb 21 01:26:09 2002 @@ -42,6 +42,7 @@ #include #include #include +#include #include #ifdef CONFIG_MATH_EMULATION #include @@ -55,14 +56,6 @@ int hlt_counter; /* - * Return saved PC of a blocked thread. - */ -unsigned long thread_saved_pc(struct task_struct *tsk) -{ - return ((unsigned long *)tsk->thread.esp)[3]; -} - -/* * Powermanagement idle function, if any.. */ void (*pm_idle)(void); @@ -552,6 +545,8 @@ BUG(); } } + + release_x86_irqs(dead_task); } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/setup.c linux-2.5/arch/i386/kernel/setup.c --- linux-2.5.5/arch/i386/kernel/setup.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/i386/kernel/setup.c Thu Feb 21 01:26:09 2002 @@ -99,8 +99,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -113,6 +113,7 @@ #include #include #include + /* * Machine setup.. */ @@ -122,14 +123,7 @@ unsigned long mmu_cr4_features; -/* - * Bus types .. - */ -#ifdef CONFIG_EISA -int EISA_bus; -#endif int MCA_bus; - /* for MCA, but anyone else can use it if they want */ unsigned int machine_id; unsigned int machine_submodel_id; @@ -158,6 +152,7 @@ unsigned char aux_device_present; extern void mcheck_init(struct cpuinfo_x86 *c); +extern void dmi_scan_machine(void); extern int root_mountflags; extern char _text, _etext, _edata, _end; extern int blk_nohighio; @@ -209,6 +204,10 @@ { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, { "fpu", 0xf0, 0xff, IORESOURCE_BUSY } }; +#ifdef CONFIG_MELAN +standard_io_resources[1] = { "pic1", 0x20, 0x21, IORESOURCE_BUSY }; +standard_io_resources[5] = { "pic2", 0xa0, 0xa1, IORESOURCE_BUSY }; +#endif #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource)) @@ -907,7 +906,6 @@ */ if (smp_found_config) get_smp_config(); - init_apic_mappings(); #endif @@ -959,6 +957,7 @@ conswitchp = &dummy_con; #endif #endif + dmi_scan_machine(); } static int cachesize_override __initdata = -1; @@ -1228,7 +1227,7 @@ } /* - * Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU + * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU */ static void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) { @@ -1303,7 +1302,7 @@ static void __init check_cx686_slop(struct cpuinfo_x86 *c) { unsigned long flags; - + if (Cx86_dir0_msb == 3) { unsigned char ccr3, ccr5; @@ -1312,8 +1311,8 @@ setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ ccr5 = getCx86(CX86_CCR5); if (ccr5 & 2) - setCx86(CX86_CCR5, ccr5 & 0xfd); /* reset SLOP */ - setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ + setCx86(CX86_CCR5, ccr5 & 0xfd); /* reset SLOP */ + setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ local_irq_restore(flags); if (ccr5 & 2) { /* possible wrong calibration done */ @@ -1324,6 +1323,7 @@ } } + static void __init init_cyrix(struct cpuinfo_x86 *c) { unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0; @@ -1400,7 +1400,7 @@ same. The MediaGX has deep magic SMM stuff that handles the SB emulation. It thows away the fifo on disable_dma() which is wrong and ruins the audio. - + Bug2: VSA1 has a wrap bug so that using maximum sized DMA causes bad things. According to NatSemi VSA2 has another bug to do with 'hlt'. I've not seen any boards using VSA2 @@ -1416,14 +1416,18 @@ /* GXm supports extended cpuid levels 'ala' AMD */ if (c->cpuid_level == 2) { get_model_name(c); /* get CPU marketing name */ +#ifndef CONFIG_CS5520 clear_bit(X86_FEATURE_TSC, c->x86_capability); +#endif return; } else { /* MediaGX */ Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4'; p = Cx86_cb+2; c->x86_model = (dir1 & 0x20) ? 1 : 2; +#ifndef CONFIG_CS5520 clear_bit(X86_FEATURE_TSC, &c->x86_capability); +#endif } break; @@ -1441,7 +1445,7 @@ tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0; Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7]; p = Cx86_cb+tmp; - if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20)) + if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20)) (c->x86_model)++; /* Emulate MTRRs using Cyrix's ARRs. */ set_bit(X86_FEATURE_CYRIX_ARR, &c->x86_capability); @@ -2085,7 +2089,7 @@ } if ( l1i || l1d ) printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n", - l1i, l1d); + l1i, l1d); if ( l2 ) printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); if ( l3 ) @@ -2192,6 +2196,8 @@ c->x86_vendor = X86_VENDOR_AMD; else if (!strcmp(v, "CyrixInstead")) c->x86_vendor = X86_VENDOR_CYRIX; + else if (!strcmp(v, "Geode by NSC")) + c->x86_vendor = X86_VENDOR_NSC; else if (!strcmp(v, "UMC UMC UMC ")) c->x86_vendor = X86_VENDOR_UMC; else if (!strcmp(v, "CentaurHauls")) @@ -2535,6 +2541,10 @@ init_cyrix(c); break; + case X86_VENDOR_NSC: + init_cyrix(c); + break; + case X86_VENDOR_AMD: init_amd(c); break; @@ -2635,14 +2645,15 @@ { get_cpu_vendor(&boot_cpu_data); - if ( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) + if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) || + ( boot_cpu_data.x86_vendor == X86_VENDOR_NSC )) init_cyrix(&boot_cpu_data); } /* These need to match */ static char *cpu_vendor_names[] __initdata = { - "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" }; + "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta", "NSC" }; void __init print_cpu_info(struct cpuinfo_x86 *c) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/smp.c linux-2.5/arch/i386/kernel/smp.c --- linux-2.5.5/arch/i386/kernel/smp.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/i386/kernel/smp.c Tue Feb 26 21:24:48 2002 @@ -485,35 +485,6 @@ do_flush_tlb_all_local(); } -static spinlock_t migration_lock = SPIN_LOCK_UNLOCKED; -static task_t *new_task; - -/* - * This function sends a 'task migration' IPI to another CPU. - * Must be called from syscall contexts, with interrupts *enabled*. - */ -void smp_migrate_task(int cpu, task_t *p) -{ - /* - * The target CPU will unlock the migration spinlock: - */ - _raw_spin_lock(&migration_lock); - new_task = p; - send_IPI_mask(1 << cpu, TASK_MIGRATION_VECTOR); -} - -/* - * Task migration callback. - */ -asmlinkage void smp_task_migration_interrupt(void) -{ - task_t *p; - - ack_APIC_irq(); - p = new_task; - _raw_spin_unlock(&migration_lock); - sched_task_migrated(p); -} /* * this function sends a 'reschedule' IPI to another CPU. * it goes straight through and wastes no time serializing diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/smpboot.c linux-2.5/arch/i386/kernel/smpboot.c --- linux-2.5.5/arch/i386/kernel/smpboot.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/i386/kernel/smpboot.c Mon Mar 4 01:29:41 2002 @@ -240,7 +240,7 @@ * ^---- (this multiplication can overflow) */ -static unsigned long long div64 (unsigned long long a, unsigned long b0) +static unsigned long long __init div64 (unsigned long long a, unsigned long b0) { unsigned int a1, a2; unsigned long long res; @@ -828,7 +828,7 @@ * We remove it from the pidhash and the runqueue * once we got the process: */ - idle = init_task.prev_task; + idle = LAST_TASK; if (!idle) panic("No idle process for CPU %d", cpu); @@ -1012,11 +1012,14 @@ { int apicid, cpu, bit; - if (clustered_apic_mode) { - /* remap the 1st quad's 256k range for cross-quad I/O */ - xquad_portio = ioremap (XQUAD_PORTIO_BASE, XQUAD_PORTIO_LEN); - printk("Cross quad port I/O vaddr 0x%08lx, len %08lx\n", - (u_long) xquad_portio, (u_long) XQUAD_PORTIO_LEN); + if (clustered_apic_mode && (numnodes > 1)) { + printk("Remapping cross-quad port I/O for %d quads\n", + numnodes); + printk("xquad_portio vaddr 0x%08lx, len %08lx\n", + (u_long) xquad_portio, + (u_long) numnodes * XQUAD_PORTIO_LEN); + xquad_portio = ioremap (XQUAD_PORTIO_BASE, + numnodes * XQUAD_PORTIO_LEN); } #ifdef CONFIG_MTRR diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/time.c linux-2.5/arch/i386/kernel/time.c --- linux-2.5.5/arch/i386/kernel/time.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/i386/kernel/time.c Fri Mar 1 15:07:37 2002 @@ -28,6 +28,9 @@ * 1998-12-24 Copyright (C) 1998 Andrea Arcangeli * Fixed a xtime SMP race (we need the xtime_lock rw spinlock to * serialize accesses to xtime/lost_ticks). + * 2001-02-20 Hiroshi Miura + * Work around for Cyrix/IBM/NSC MediaGX/GXm, NSC Geode southbridge + * PIT bug. (NSC Cx5510/5520) */ #include @@ -115,6 +118,7 @@ #define TICK_SIZE tick spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED; +EXPORT_SYMBOL(i8253_lock); extern spinlock_t i8259A_lock; @@ -468,6 +472,10 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int count; +#ifdef CONFIG_CS5520 + int count1, count2, count3; + int n1, n2, n3; +#endif /* * Here we are in the timer irq handler. We just have irqs locally @@ -496,6 +504,7 @@ rdtscl(last_tsc_low); +#ifndef CONFIG_CS5520 spin_lock(&i8253_lock); outb_p(0x00, 0x43); /* latch the count ASAP */ @@ -508,6 +517,59 @@ } do_timer_interrupt(irq, NULL, regs); +#else + spin_lock(&i8253_lock); + outb_p(0x00, 0x43); /* latch the count ASAP */ +/* this codes comes from FreeBSD */ + count1 = inb_p(0x40); + count1 |= inb(0x40) << 8; + count2 = inb_p(0x40); + count2 = inb(0x40) << 8; + count3 = inb_p(0x40); + count3 = inb(0x40) << 8; + spin_unlock(&i8253_lock); + + if (count1 >= count2 && count2 >= count3 && count1 - count2 < 0x200) + count = count2; + else { + +#define _swap_val(a, b) do { \ + int c = a;\ + a = b; \ + b = c; \ +} while(0) + /* sort values */ + if (count1 < count2) + _swap_val(count1, count2); + if (count2 < count3) + _swap_val(count2, count3); + if (count1 < count2) + _swap_val(count1, count2); + + /* compare the middle value */ + if (count1 - count3 < 0x200) + count = count2; + else + { + n1 = count2 - count3; + n2 = count3 - count1 + LATCH; + n3 = count1 - count2; + count = count3; + if (n1 >= n2) { + if (n1 >= n3) + count = count1; + } else { + if (n2 >= n3) + count = count2; + } + } + } + count = ((LATCH-1) - count) * TICK_SIZE; + delay_at_last_interrupt = (count + LATCH/2) / LATCH; + } + + do_timer_interrupt(irq, NULL, regs); +#endif write_unlock(&xtime_lock); @@ -670,6 +732,9 @@ if (cpu_has_tsc) { unsigned long tsc_quotient = calibrate_tsc(); +#ifdef CONFIG_CS5520 + if (!tsc_quotient) tsc_quotient = calibrate_tsc(); +#endif if (tsc_quotient) { fast_gettimeoffset_quotient = tsc_quotient; use_tsc = 1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/traps.c linux-2.5/arch/i386/kernel/traps.c --- linux-2.5.5/arch/i386/kernel/traps.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/i386/kernel/traps.c Thu Feb 21 01:26:09 2002 @@ -25,6 +25,10 @@ #include #include +#ifdef CONFIG_EISA +#include +#endif + #ifdef CONFIG_MCA #include #include @@ -967,11 +971,24 @@ printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID)); } #endif + +int EISA_bus; +#ifdef CONFIG_EISA +static struct resource eisa_id = { "EISA ID", 0xc80, 0xc83, IORESOURCE_BUSY }; +#endif + void __init trap_init(void) { #ifdef CONFIG_EISA - if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) + if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) { EISA_bus = 1; + if (request_resource(&ioport_resource, &eisa_id) == -EBUSY) + printk ("EISA port was EBUSY :-(\n"); + } +#endif + +#ifdef CONFIG_X86_LOCAL_APIC + init_apic_mappings(); #endif set_trap_gate(0,÷_error); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/kernel/vm86.c linux-2.5/arch/i386/kernel/vm86.c --- linux-2.5.5/arch/i386/kernel/vm86.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/i386/kernel/vm86.c Thu Feb 21 01:26:09 2002 @@ -16,6 +16,7 @@ #include #include #include +#include /* * Known problems: @@ -613,6 +614,14 @@ } read_unlock(&tasklist_lock); return ret; +} + +void release_x86_irqs(struct task_struct *task) +{ + int i; + for (i=3; i<16; i++) + if (vm86_irqs[i].tsk == task) + free_vm86_irq(i); } static inline void handle_irq_zombies(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/math-emu/fpu_system.h linux-2.5/arch/i386/math-emu/fpu_system.h --- linux-2.5.5/arch/i386/math-emu/fpu_system.h Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/i386/math-emu/fpu_system.h Tue Feb 19 15:29:33 2002 @@ -20,6 +20,8 @@ of the stack frame of math_emulate() */ #define SETUP_DATA_AREA(arg) FPU_info = (struct info *) &arg +/* s is always from a cpu register, and the cpu does bounds checking + * during register load --> no further bounds checks needed */ #define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.segments)[(s) >> 3]) #define SEG_D_SIZE(x) ((x).b & (3 << 21)) #define SEG_G_BIT(x) ((x).b & (1 << 23)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/math-emu/reg_add_sub.c linux-2.5/arch/i386/math-emu/reg_add_sub.c --- linux-2.5.5/arch/i386/math-emu/reg_add_sub.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/i386/math-emu/reg_add_sub.c Sun Mar 3 17:54:35 2002 @@ -140,7 +140,7 @@ FPU_REG const *a, *b; FPU_REG *dest; u_char taga, tagb, signa, signb, saved_sign, sign; - int diff, tag, expa, expb, deststnr; + int diff, tag = 0, expa, expb, deststnr; a = &st(0); taga = FPU_gettag0(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/math-emu/reg_compare.c linux-2.5/arch/i386/math-emu/reg_compare.c --- linux-2.5.5/arch/i386/math-emu/reg_compare.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/i386/math-emu/reg_compare.c Sun Mar 3 17:54:35 2002 @@ -174,7 +174,7 @@ /* This function requires that st(0) is not empty */ int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag) { - int f, c; + int f = 0, c; c = compare(loaded_data, loaded_tag); @@ -216,7 +216,7 @@ static int compare_st_st(int nr) { - int f, c; + int f = 0, c; FPU_REG *st_ptr; if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) ) @@ -268,7 +268,7 @@ static int compare_u_st_st(int nr) { - int f, c; + int f = 0, c; FPU_REG *st_ptr; if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/math-emu/reg_divide.c linux-2.5/arch/i386/math-emu/reg_divide.c --- linux-2.5.5/arch/i386/math-emu/reg_divide.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/i386/math-emu/reg_divide.c Sun Mar 3 17:54:35 2002 @@ -203,4 +203,5 @@ } #endif /* PARANOID */ + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/math-emu/reg_ld_str.c linux-2.5/arch/i386/math-emu/reg_ld_str.c --- linux-2.5.5/arch/i386/math-emu/reg_ld_str.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/i386/math-emu/reg_ld_str.c Sun Mar 3 17:54:35 2002 @@ -632,7 +632,7 @@ /* Put a float into user memory */ int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single) { - long templ; + long templ = 0; unsigned long increment = 0; /* avoid gcc warnings */ int precision_loss; int exp; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/math-emu/reg_mul.c linux-2.5/arch/i386/math-emu/reg_mul.c --- linux-2.5.5/arch/i386/math-emu/reg_mul.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/i386/math-emu/reg_mul.c Sun Mar 3 17:54:35 2002 @@ -128,4 +128,5 @@ } #endif /* PARANOID */ + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/mm/fault.c linux-2.5/arch/i386/mm/fault.c --- linux-2.5.5/arch/i386/mm/fault.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/i386/mm/fault.c Thu Feb 21 01:26:09 2002 @@ -27,8 +27,6 @@ extern void die(const char *,struct pt_regs *,long); -extern int console_loglevel; - /* * Ugly, ugly, but the goto's result in better assembly.. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/mm/init.c linux-2.5/arch/i386/mm/init.c --- linux-2.5.5/arch/i386/mm/init.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/i386/mm/init.c Thu Feb 21 01:26:09 2002 @@ -105,7 +105,6 @@ static inline void set_pte_phys (unsigned long vaddr, unsigned long phys, pgprot_t flags) { - pgprot_t prot; pgd_t *pgd; pmd_t *pmd; pte_t *pte; @@ -121,10 +120,8 @@ return; } pte = pte_offset_kernel(pmd, vaddr); - if (pte_val(*pte)) - pte_ERROR(*pte); - pgprot_val(prot) = pgprot_val(PAGE_KERNEL) | pgprot_val(flags); - set_pte(pte, mk_pte_phys(phys, prot)); + /* stored as-is, to permit clearing entries */ + set_pte(pte, mk_pte_phys(phys, flags)); /* * It's enough to flush this one mapping. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/i386/mm/ioremap.c linux-2.5/arch/i386/mm/ioremap.c --- linux-2.5.5/arch/i386/mm/ioremap.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/i386/mm/ioremap.c Tue Mar 5 23:46:14 2002 @@ -11,6 +11,7 @@ #include #include #include +#include static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, unsigned long phys_addr, unsigned long flags) @@ -160,4 +161,69 @@ { if (addr > high_memory) return vfree((void *) (PAGE_MASK & (unsigned long) addr)); +} + +void __init *bt_ioremap(unsigned long phys_addr, unsigned long size) +{ + unsigned long offset, last_addr; + unsigned int nrpages; + enum fixed_addresses idx; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; + + /* + * Don't remap the low PCI/ISA area, it's always mapped.. + */ + if (phys_addr >= 0xA0000 && last_addr < 0x100000) + return phys_to_virt(phys_addr); + + /* + * Mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr) - phys_addr; + + /* + * Mappings have to fit in the FIX_BTMAP area. + */ + nrpages = size >> PAGE_SHIFT; + if (nrpages > NR_FIX_BTMAPS) + return NULL; + + /* + * Ok, go for it.. + */ + idx = FIX_BTMAP_BEGIN; + while (nrpages > 0) { + set_fixmap(idx, phys_addr); + phys_addr += PAGE_SIZE; + --idx; + --nrpages; + } + return (void*) (offset + fix_to_virt(FIX_BTMAP_BEGIN)); +} + +void __init bt_iounmap(void *addr, unsigned long size) +{ + unsigned long virt_addr; + unsigned long offset; + unsigned int nrpages; + enum fixed_addresses idx; + + virt_addr = (unsigned long)addr; + if (virt_addr < fix_to_virt(FIX_BTMAP_BEGIN)) + return; + offset = virt_addr & ~PAGE_MASK; + nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT; + + idx = FIX_BTMAP_BEGIN; + while (nrpages > 0) { + __set_fixmap(idx, 0, __pgprot(0)); + --idx; + --nrpages; + } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ia64/boot/Makefile linux-2.5/arch/ia64/boot/Makefile --- linux-2.5.5/arch/ia64/boot/Makefile Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/ia64/boot/Makefile Sun Feb 3 18:03:58 2002 @@ -23,7 +23,7 @@ all: $(targets-y) bootloader: $(OBJECTS) - $(LD) $(LINKFLAGS) $(OBJECTS) $(TOPDIR)/lib/lib.a $(TOPDIR)/arch/$(ARCH)/lib/lib.a \ + $(LD) $(LINKFLAGS) $(OBJECTS) $(TOPDIR)/lib/lib.o $(TOPDIR)/arch/$(ARCH)/lib/lib.a \ -o bootloader clean: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ia64/config.in linux-2.5/arch/ia64/config.in --- linux-2.5.5/arch/ia64/config.in Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/ia64/config.in Thu Feb 14 02:57:57 2002 @@ -182,10 +182,8 @@ fi # !HP_SIM -# -# input before char - char/joystick depends on it. As does USB. -# source drivers/input/Config.in + source drivers/char/Config.in #source drivers/misc/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ia64/kernel/ia64_ksyms.c linux-2.5/arch/ia64/kernel/ia64_ksyms.c --- linux-2.5.5/arch/ia64/kernel/ia64_ksyms.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/ia64/kernel/ia64_ksyms.c Mon Feb 18 21:47:31 2002 @@ -23,7 +23,6 @@ EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(strtok); #include EXPORT_SYMBOL(isa_irq_to_vector_map); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ia64/kernel/perfmon.c linux-2.5/arch/ia64/kernel/perfmon.c --- linux-2.5.5/arch/ia64/kernel/perfmon.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/ia64/kernel/perfmon.c Tue Feb 26 21:24:48 2002 @@ -251,7 +251,7 @@ #define DBprintk(a) \ do { \ if (pfm_debug >0) { printk(__FUNCTION__" %d: ", __LINE__); printk a; } \ - } while (0); + } while (0) static void ia64_reset_pmu(void); @@ -282,7 +282,7 @@ /* * helper macros */ -#define SET_PMU_OWNER(t) do { pmu_owners[smp_processor_id()].owner = (t); } while(0); +#define SET_PMU_OWNER(t) do { pmu_owners[smp_processor_id()].owner = (t); } while(0) #define PMU_OWNER() pmu_owners[smp_processor_id()].owner #ifdef CONFIG_SMP @@ -332,35 +332,8 @@ return ia64_get_itc(); } -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long -uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if (pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - } - } - } - DBprintk(("uv2kva(%lx-->%lx)\n", adr, ret)); - return ret; -} - - /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) @@ -374,19 +347,15 @@ rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; + unsigned long adr; - /* XXX: may have to revisit this part because - * vmalloc() does not necessarily return a page-aligned buffer. - * This maybe a security problem when mapped at user level - */ + size=PAGE_ALIGN(size); mem=vmalloc(size); if (mem) { memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -397,13 +366,12 @@ static void rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (mem) { adr=(unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -515,7 +483,6 @@ vma->vm_file = NULL; vma->vm_raend = 0; - /* XXX: see rvmalloc() for page alignment problem */ smpl_buf = rvmalloc(size); if (smpl_buf == NULL) goto no_buffer; @@ -1867,6 +1834,8 @@ */ perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL); } +subsys_initcall(perfmon_init); + void perfmon_init_percpu (void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ia64/kernel/smpboot.c linux-2.5/arch/ia64/kernel/smpboot.c --- linux-2.5.5/arch/ia64/kernel/smpboot.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/ia64/kernel/smpboot.c Mon Mar 4 01:29:41 2002 @@ -412,7 +412,7 @@ * We remove it from the pidhash and the runqueue * once we got the process: */ - idle = init_task.prev_task; + idle = LAST_TASK; if (!idle) panic("No idle process for CPU %d", cpu); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/m68k/amiga/config.c linux-2.5/arch/m68k/amiga/config.c --- linux-2.5.5/arch/m68k/amiga/config.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/arch/m68k/amiga/config.c Thu Feb 14 00:58:44 2002 @@ -69,11 +69,13 @@ extern char m68k_debug_device[]; static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *)); +#ifndef CONFIG_KEYBOARD_AMIGA /* amiga specific keyboard functions */ extern int amiga_keyb_init(void); extern int amiga_kbdrate (struct kbd_repeat *); extern int amiga_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode); +#endif /* amiga specific irq functions */ extern void amiga_init_IRQ (void); extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); @@ -389,9 +391,11 @@ request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); mach_sched_init = amiga_sched_init; +#ifndef CONFIG_KEYBOARD_AMIGA mach_keyb_init = amiga_keyb_init; mach_kbdrate = amiga_kbdrate; mach_kbd_translate = amiga_kbd_translate; +#endif SYSRQ_KEY = 0xff; mach_init_IRQ = amiga_init_IRQ; mach_default_handler = &amiga_default_handler; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/m68k/atari/config.c linux-2.5/arch/m68k/atari/config.c --- linux-2.5.5/arch/m68k/atari/config.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/m68k/atari/config.c Thu Feb 21 02:25:24 2002 @@ -205,14 +205,16 @@ char switches[len+1]; char *p; int ovsc_shift; + char *args = switches; - /* copy string to local array, strtok works destructively... */ + /* copy string to local array, strsep works destructively... */ strncpy( switches, str, len ); switches[len] = 0; atari_switches = 0; /* parse the options */ - for( p = strtok( switches, "," ); p; p = strtok( NULL, "," ) ) { + while ((p = strsep(&args, ",")) != NULL) { + if (!*p) continue; ovsc_shift = 0; if (strncmp( p, "ov_", 3 ) == 0) { p += 3; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/m68k/kernel/m68k_ksyms.c linux-2.5/arch/m68k/kernel/m68k_ksyms.c --- linux-2.5.5/arch/m68k/kernel/m68k_ksyms.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/m68k/kernel/m68k_ksyms.c Mon Feb 18 21:47:39 2002 @@ -54,7 +54,6 @@ EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(kernel_thread); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/mips/Config.help linux-2.5/arch/mips/Config.help --- linux-2.5.5/arch/mips/Config.help Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/mips/Config.help Mon Feb 11 02:04:57 2002 @@ -904,3 +904,9 @@ would like kernel messages to be formatted into GDB $O packets so that GDB prints them as program output, say 'Y'. +CONFIG_ARC_CONSOLE + Support for the PROM-based console on MIPS machines built according + to the Advanced Risc Computing specification, which is now (2001) + dead. These included boxes from Deskstation, Acer, Olivetti and + NEC. There is a history at . + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/mips/au1000/common/serial.c linux-2.5/arch/mips/au1000/common/serial.c --- linux-2.5.5/arch/mips/au1000/common/serial.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/mips/au1000/common/serial.c Sun Mar 3 23:50:41 2002 @@ -433,7 +433,7 @@ if (break_pressed && info->line == sercons.index) { if (ch != 0 && time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); break_pressed = 0; goto ignore_char; } @@ -2606,7 +2606,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_AU1000_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/mips/baget/vacserial.c linux-2.5/arch/mips/baget/vacserial.c --- linux-2.5.5/arch/mips/baget/vacserial.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/mips/baget/vacserial.c Sun Dec 30 13:55:22 2001 @@ -2373,7 +2373,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/mips/config.in linux-2.5/arch/mips/config.in --- linux-2.5.5/arch/mips/config.in Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/mips/config.in Thu Feb 14 02:57:57 2002 @@ -408,6 +408,8 @@ fi endmenu +source drivers/input/Config.in + source drivers/char/Config.in source drivers/media/Config.in @@ -493,7 +495,6 @@ fi source drivers/usb/Config.in -source drivers/input/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/mips/kernel/mips_ksyms.c linux-2.5/arch/mips/kernel/mips_ksyms.c --- linux-2.5.5/arch/mips/kernel/mips_ksyms.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/mips/kernel/mips_ksyms.c Mon Feb 18 20:50:38 2002 @@ -51,7 +51,6 @@ EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memmove); -EXPORT_SYMBOL(simple_strtol); EXPORT_SYMBOL_NOVERS(strcat); EXPORT_SYMBOL_NOVERS(strchr); EXPORT_SYMBOL_NOVERS(strlen); @@ -60,7 +59,7 @@ EXPORT_SYMBOL_NOVERS(strnlen); EXPORT_SYMBOL_NOVERS(strrchr); EXPORT_SYMBOL_NOVERS(strstr); -EXPORT_SYMBOL_NOVERS(strtok); +EXPORT_SYMBOL_NOVERS(strsep); EXPORT_SYMBOL(_clear_page); EXPORT_SYMBOL(enable_irq); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/mips/kernel/signal.c linux-2.5/arch/mips/kernel/signal.c --- linux-2.5.5/arch/mips/kernel/signal.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/mips/kernel/signal.c Thu Feb 14 02:57:57 2002 @@ -204,7 +204,7 @@ #define restore_gp_reg(i) do { \ err |= __get_user(reg, &sc->sc_regs[i]); \ regs->regs[i] = reg; \ -} while(0); +} while(0) restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/mips/kernel/smp.c linux-2.5/arch/mips/kernel/smp.c --- linux-2.5.5/arch/mips/kernel/smp.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/mips/kernel/smp.c Mon Mar 4 01:29:41 2002 @@ -123,7 +123,7 @@ /* Spawn a new process normally. Grab a pointer to its task struct so we can mess with it */ do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); - p = init_task.prev_task; + p = LAST_TASK; /* Schedule the first task manually */ p->processor = i; @@ -152,11 +152,11 @@ * Linux can schedule processes on this slave. */ kernel_thread(0, NULL, CLONE_PID); - p = init_task.prev_task; + p = LAST_TASK; sprintf(p->comm, "%s%d", "Idle", i); init_tasks[i] = p; p->processor = i; - p->cpus_runnable = 1 << i; /* we schedule the first task manually * + p->cpus_runnable = 1 << i; /* we schedule the first task manually */ del_from_runqueue(p); unhash_process(p); /* Attach to the address space of init_task. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/mips/sni/pci.c linux-2.5/arch/mips/sni/pci.c --- linux-2.5.5/arch/mips/sni/pci.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/mips/sni/pci.c Thu Feb 14 00:36:31 2002 @@ -25,7 +25,7 @@ ((dev->bus->number & 0xff) << 0x10) | \ ((dev->devfn & 0xff) << 0x08) | \ (where & 0xfc); \ -} while(0); +} while(0) #if 0 /* To do: Bring this uptodate ... */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/mips64/Config.help linux-2.5/arch/mips64/Config.help --- linux-2.5.5/arch/mips64/Config.help Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/mips64/Config.help Mon Feb 11 02:04:57 2002 @@ -442,3 +442,9 @@ This allows you to run 32-bit Linux/ELF binaries on your Ultra. Everybody wants this; say Y. +CONFIG_ARC_CONSOLE + Support for the PROM-based console on MIPS machines built according + to the Advanced Risc Computing specification, which is now (2001) + dead. These included boxes from Deskstation, Acer, Olivetti and + NEC. There is a history at . + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/mips64/config.in linux-2.5/arch/mips64/config.in --- linux-2.5.5/arch/mips64/config.in Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/mips64/config.in Thu Feb 14 02:57:57 2002 @@ -202,6 +202,8 @@ fi endmenu +source drivers/input/Config.in + source drivers/char/Config.in #source drivers/misc/Config.in @@ -243,7 +245,6 @@ fi source drivers/usb/Config.in -source drivers/input/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/mips64/kernel/mips64_ksyms.c linux-2.5/arch/mips64/kernel/mips64_ksyms.c --- linux-2.5.5/arch/mips64/kernel/mips64_ksyms.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/mips64/kernel/mips64_ksyms.c Mon Feb 18 20:50:38 2002 @@ -48,14 +48,13 @@ EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memmove); -EXPORT_SYMBOL(simple_strtol); EXPORT_SYMBOL_NOVERS(strcat); EXPORT_SYMBOL_NOVERS(strchr); EXPORT_SYMBOL_NOVERS(strlen); EXPORT_SYMBOL_NOVERS(strncat); EXPORT_SYMBOL_NOVERS(strnlen); EXPORT_SYMBOL_NOVERS(strrchr); -EXPORT_SYMBOL_NOVERS(strtok); +EXPORT_SYMBOL_NOVERS(strsep); EXPORT_SYMBOL_NOVERS(strpbrk); EXPORT_SYMBOL(_clear_page); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/mips64/math-emu/cp1emu.c linux-2.5/arch/mips64/math-emu/cp1emu.c --- linux-2.5.5/arch/mips64/math-emu/cp1emu.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/mips64/math-emu/cp1emu.c Tue Feb 26 20:14:01 2002 @@ -29,7 +29,7 @@ * Notes: * 1) the IEEE754 library (-le) performs the actual arithmetic; * 2) if you know that you won't have an fpu, then you'll get much - * better performance by compiling with -msoft-float! */ + * better performance by compiling with -msoft-float! * * Nov 7, 2000 * Massive changes to integrate with Linux kernel. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/mips64/sgi-ip27/ip27-init.c linux-2.5/arch/mips64/sgi-ip27/ip27-init.c --- linux-2.5.5/arch/mips64/sgi-ip27/ip27-init.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/mips64/sgi-ip27/ip27-init.c Mon Mar 4 01:29:41 2002 @@ -491,7 +491,7 @@ * Linux can schedule processes on this slave. */ kernel_thread(0, NULL, CLONE_PID); - p = init_task.prev_task; + p = LAST_TASK; sprintf(p->comm, "%s%d", "Idle", num_cpus); init_tasks[num_cpus] = p; alloc_cpupda(cpu, num_cpus); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/parisc/config.in linux-2.5/arch/parisc/config.in --- linux-2.5.5/arch/parisc/config.in Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/parisc/config.in Thu Feb 14 02:57:57 2002 @@ -162,6 +162,7 @@ endmenu fi +source drivers/input/Config.in source drivers/char/Config.in source fs/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/parisc/kernel/parisc_ksyms.c linux-2.5/arch/parisc/kernel/parisc_ksyms.c --- linux-2.5.5/arch/parisc/kernel/parisc_ksyms.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/parisc/kernel/parisc_ksyms.c Mon Feb 18 21:48:08 2002 @@ -20,7 +20,6 @@ EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(strncpy); -EXPORT_SYMBOL(strtok); #include EXPORT_SYMBOL(hppa_dma_ops); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/parisc/kernel/pdc_cons.c linux-2.5/arch/parisc/kernel/pdc_cons.c --- linux-2.5.5/arch/parisc/kernel/pdc_cons.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/parisc/kernel/pdc_cons.c Mon Feb 25 18:54:26 2002 @@ -137,9 +137,8 @@ --pdc_console_initialized; #ifdef CONFIG_VT_CONSOLE - schedule_console_callback(); + schedule_task(&vt_cons->vt_tq); #endif - unregister_console(&pdc_cons); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/parisc/kernel/traps.c linux-2.5/arch/parisc/kernel/traps.c --- linux-2.5.5/arch/parisc/kernel/traps.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/parisc/kernel/traps.c Thu Dec 27 16:32:30 2001 @@ -43,7 +43,6 @@ static inline void console_verbose(void) { - extern int console_loglevel; console_loglevel = 15; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/4xx_io/serial_sicc.c linux-2.5/arch/ppc/4xx_io/serial_sicc.c --- linux-2.5.5/arch/ppc/4xx_io/serial_sicc.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/ppc/4xx_io/serial_sicc.c Sun Mar 3 23:50:41 2002 @@ -462,7 +462,7 @@ #ifdef SUPPORT_SYSRQ if (info->sysrq) { if (ch && time_before(jiffies, info->sysrq)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); info->sysrq = 0; goto ignore_char; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/4xx_io/stb_kb.c linux-2.5/arch/ppc/4xx_io/stb_kb.c --- linux-2.5.5/arch/ppc/4xx_io/stb_kb.c Wed Feb 20 02:10:52 2002 +++ linux-2.5/arch/ppc/4xx_io/stb_kb.c Fri Feb 15 18:02:37 2002 @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include /* the following are borrowed from pc_keyb.c, thanks to those involved! */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/8260_io/uart.c linux-2.5/arch/ppc/8260_io/uart.c --- linux-2.5.5/arch/ppc/8260_io/uart.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/ppc/8260_io/uart.c Thu Feb 14 04:11:07 2002 @@ -2538,7 +2538,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_8xx_open; serial_driver.close = rs_8xx_close; serial_driver.write = rs_8xx_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/8xx_io/uart.c linux-2.5/arch/ppc/8xx_io/uart.c --- linux-2.5.5/arch/ppc/8xx_io/uart.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/ppc/8xx_io/uart.c Sun Mar 3 23:50:41 2002 @@ -485,7 +485,7 @@ if (break_pressed && info->line == sercons.index) { if (ch != 0 && time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); break_pressed = 0; goto ignore_char; } else @@ -2586,7 +2586,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_8xx_open; serial_driver.close = rs_8xx_close; serial_driver.write = rs_8xx_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/amiga/config.c linux-2.5/arch/ppc/amiga/config.c --- linux-2.5.5/arch/ppc/amiga/config.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/ppc/amiga/config.c Thu Feb 14 02:57:57 2002 @@ -76,9 +76,11 @@ extern char m68k_debug_device[]; static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *)); +#ifndef CONFIG_KEYBOARD_AMIGA /* amiga specific keyboard functions */ extern int amiga_keyb_init(void); extern int amiga_kbdrate (struct kbd_repeat *); +#endif /* amiga specific irq functions */ extern void amiga_init_IRQ (void); extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); @@ -407,8 +409,10 @@ request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); mach_sched_init = amiga_sched_init; +#ifndef CONFIG_KEYBOARD_AMIGA mach_keyb_init = amiga_keyb_init; mach_kbdrate = amiga_kbdrate; +#endif mach_init_IRQ = amiga_init_IRQ; #ifndef CONFIG_APUS mach_default_handler = &amiga_default_handler; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/boot/chrp/Makefile linux-2.5/arch/ppc/boot/chrp/Makefile --- linux-2.5.5/arch/ppc/boot/chrp/Makefile Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/ppc/boot/chrp/Makefile Thu Feb 14 02:57:57 2002 @@ -13,7 +13,7 @@ OBJS = ../common/crt0.o start.o main.o misc.o ../common/string.o image.o \ ../common/ofcommon.o -LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a +LIBS = $(TOPDIR)/lib/lib.o ../lib/zlib.a ADDNOTE = ../utils/addnote PIGGYBACK = ../utils/piggyback diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/boot/utils/offset linux-2.5/arch/ppc/boot/utils/offset --- linux-2.5.5/arch/ppc/boot/utils/offset Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/ppc/boot/utils/offset Thu Dec 27 16:32:30 2001 @@ -0,0 +1,4 @@ +#!/bin/sh + +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $6}'` +echo "0x"$OFFSET diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/boot/utils/sioffset linux-2.5/arch/ppc/boot/utils/sioffset --- linux-2.5.5/arch/ppc/boot/utils/sioffset Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/ppc/boot/utils/sioffset Thu Dec 27 16:32:30 2001 @@ -0,0 +1,4 @@ +#!/bin/sh + +OFFSET=`grep $1 sImage.map | awk '{print $2}'` +echo "0x"$OFFSET diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/boot/utils/sisize linux-2.5/arch/ppc/boot/utils/sisize --- linux-2.5.5/arch/ppc/boot/utils/sisize Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/ppc/boot/utils/sisize Thu Dec 27 16:32:30 2001 @@ -0,0 +1,4 @@ +#!/bin/sh + +OFFSET=`grep $1 sImage.map | awk '{print $3}'` +echo "0x"$OFFSET diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/boot/utils/size linux-2.5/arch/ppc/boot/utils/size --- linux-2.5.5/arch/ppc/boot/utils/size Thu Jan 1 00:00:00 1970 +++ linux-2.5/arch/ppc/boot/utils/size Thu Dec 27 16:32:30 2001 @@ -0,0 +1,4 @@ +#!/bin/sh + +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'` +echo "0x"$OFFSET diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/iSeries/iSeries_irq.c linux-2.5/arch/ppc/iSeries/iSeries_irq.c --- linux-2.5.5/arch/ppc/iSeries/iSeries_irq.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/ppc/iSeries/iSeries_irq.c Fri Feb 15 18:02:45 2002 @@ -36,7 +36,7 @@ #include #include -#include +#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/kernel/ppc_ksyms.c linux-2.5/arch/ppc/kernel/ppc_ksyms.c --- linux-2.5.5/arch/ppc/kernel/ppc_ksyms.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/ppc/kernel/ppc_ksyms.c Mon Feb 18 21:48:19 2002 @@ -123,7 +123,6 @@ EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strpbrk); -EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strnlen); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/kernel/smp.c linux-2.5/arch/ppc/kernel/smp.c --- linux-2.5.5/arch/ppc/kernel/smp.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/ppc/kernel/smp.c Mon Mar 4 01:29:41 2002 @@ -364,7 +364,7 @@ memset(®s, 0, sizeof(struct pt_regs)); if (do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0) < 0) panic("failed fork for CPU %d", i); - p = init_task.prev_task; + p = LAST_TASK; if (!p) panic("No idle task for CPU %d", i); init_idle(p, i); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/math-emu/op-4.h linux-2.5/arch/ppc/math-emu/op-4.h --- linux-2.5.5/arch/ppc/math-emu/op-4.h Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/ppc/math-emu/op-4.h Thu Feb 14 00:36:31 2002 @@ -279,7 +279,7 @@ X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \ X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \ X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \ - } while (0); + } while (0) #define _FP_FRAC_CONV_4_1(dfs, sfs, D, S) \ do { \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc/mm/pgtable.c linux-2.5/arch/ppc/mm/pgtable.c --- linux-2.5.5/arch/ppc/mm/pgtable.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/ppc/mm/pgtable.c Thu Feb 14 02:57:58 2002 @@ -39,6 +39,11 @@ unsigned long ioremap_bot; int io_bat_index; +/* Maximum 768Mb of lowmem. On SMP, this value will be + * trimmed down to whatever can be covered by BATs though. + */ +#define MAX_LOW_MEM 0x30000000 + #ifndef CONFIG_SMP struct pgtable_cache_struct quicklists; #endif @@ -47,6 +52,10 @@ #define HAVE_BATS 1 #endif +#ifdef HAVE_BATS +static unsigned long __bat2, __bat3; +#endif + extern char etext[], _stext[]; #ifdef HAVE_BATS @@ -184,6 +193,65 @@ return err; } +void __init +adjust_total_lowmem(void) +{ + unsigned long max_low_mem = MAX_LOW_MEM; + +#ifdef HAVE_BATS + unsigned long bat_max = 0x10000000; + unsigned long align; + unsigned long ram = total_lowmem; + int is601 = 0; + + /* 601s have smaller BATs */ + if (PVR_VER(mfspr(PVR)) == 1) { + bat_max = 0x00800000; + is601 = 1; + } + + /* Make sure we don't map a block larger than the + smallest alignment of the physical address. */ + /* alignment of ram_phys_base */ + align = ~(ram_phys_base-1) & ram_phys_base; + /* set BAT block size to MIN(max_size, align) */ + if (align && align < bat_max) + bat_max = align; + + /* Calculate BAT values */ + __bat2 = 1UL << __ilog2(ram); + if (__bat2 > bat_max) + __bat2 = bat_max; + ram -= __bat2; + if (ram) { + __bat3 = 1UL << __ilog2(ram); + if (__bat3 > bat_max) + __bat3 = bat_max; + ram -= __bat3; + } + + printk(KERN_INFO "Memory BAT mapping: BAT2=%ldMb, BAT3=%ldMb, residual: %ldMb\n", + __bat2 >> 20, __bat3 >> 20, ram >> 20); + + /* On SMP, we limit the lowmem to the area mapped with BATs. + * We also assume nobody will do SMP with 601s + */ +#ifdef CONFIG_SMP + if (!is601) + max_low_mem = __bat2 + __bat3; +#endif /* CONFIG_SMP */ + +#endif /* HAVE_BATS */ + if (total_lowmem > max_low_mem) { + total_lowmem = max_low_mem; +#ifndef CONFIG_HIGHMEM + printk(KERN_INFO "Warning, memory limited to %ld Mb, use CONFIG_HIGHMEM" + " to reach %ld Mb\n", max_low_mem >> 20, total_lowmem >> 20); + total_memory = total_lowmem; +#endif /* CONFIG_HIGHMEM */ + } +} + /* * Map in all of physical memory starting at KERNELBASE. */ @@ -193,7 +261,7 @@ #ifdef HAVE_BATS if (!__map_without_bats) - bat_mapin_ram(); + bat_mapin_ram(__bat2, __bat3); #endif /* HAVE_BATS */ v = KERNELBASE; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc64/kernel/smp.c linux-2.5/arch/ppc64/kernel/smp.c --- linux-2.5.5/arch/ppc64/kernel/smp.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/ppc64/kernel/smp.c Mon Mar 4 01:29:41 2002 @@ -669,7 +669,7 @@ if (do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0) < 0) panic("failed fork for CPU %d", i); - p = init_task.prev_task; + p = LAST_TASK; if (!p) panic("No idle task for CPU %d", i); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/ppc64/kernel/sys_ppc32.c linux-2.5/arch/ppc64/kernel/sys_ppc32.c --- linux-2.5.5/arch/ppc64/kernel/sys_ppc32.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/ppc64/kernel/sys_ppc32.c Fri Mar 1 15:07:37 2002 @@ -924,143 +924,65 @@ -static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf) +static int cp_new_stat32(struct kstat *stat, struct stat32 *statbuf) { - unsigned long ino, blksize, blocks; - kdev_t dev, rdev; - umode_t mode; - nlink_t nlink; - uid_t uid; - gid_t gid; - off_t size; - time_t atime, mtime, ctime; int err; - /* Stream the loads of inode data into the load buffer, - * then we push it all into the store buffer below. This - * should give optimal cache performance. - */ - ino = inode->i_ino; - dev = inode->i_dev; - mode = inode->i_mode; - nlink = inode->i_nlink; - uid = inode->i_uid; - gid = inode->i_gid; - rdev = inode->i_rdev; - size = inode->i_size; - atime = inode->i_atime; - mtime = inode->i_mtime; - ctime = inode->i_ctime; - blksize = inode->i_blksize; - blocks = inode->i_blocks; - - err = put_user(kdev_t_to_nr(dev), &statbuf->st_dev); - err |= put_user(ino, &statbuf->st_ino); - err |= put_user(mode, &statbuf->st_mode); - err |= put_user(nlink, &statbuf->st_nlink); - err |= put_user(uid, &statbuf->st_uid); - err |= put_user(gid, &statbuf->st_gid); - err |= put_user(kdev_t_to_nr(rdev), &statbuf->st_rdev); - err |= put_user(size, &statbuf->st_size); - err |= put_user(atime, &statbuf->st_atime); + err = put_user(stat->dev, &statbuf->st_dev); + err |= put_user(stat->ino, &statbuf->st_ino); + err |= put_user(stat->mode, &statbuf->st_mode); + err |= put_user(stat->nlink, &statbuf->st_nlink); + err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid); + err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid); + err |= put_user(stat->rdev, &statbuf->st_rdev); + if (stat->size > MAX_NON_LFS) + return -EOVERFLOW; + err |= put_user(stat->size, &statbuf->st_size); + err |= put_user(stat->atime, &statbuf->st_atime); err |= put_user(0, &statbuf->__unused1); - err |= put_user(mtime, &statbuf->st_mtime); + err |= put_user(stat->mtime, &statbuf->st_mtime); err |= put_user(0, &statbuf->__unused2); - err |= put_user(ctime, &statbuf->st_ctime); + err |= put_user(stat->ctime, &statbuf->st_ctime); err |= put_user(0, &statbuf->__unused3); - if (blksize) { - err |= put_user(blksize, &statbuf->st_blksize); - err |= put_user(blocks, &statbuf->st_blocks); - } else { - unsigned int tmp_blocks; - -#define D_B 7 -#define I_B (BLOCK_SIZE / sizeof(unsigned short)) - tmp_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE; - if (tmp_blocks > D_B) { - unsigned int indirect; - - indirect = (tmp_blocks - D_B + I_B - 1) / I_B; - tmp_blocks += indirect; - if (indirect > 1) { - indirect = (indirect - 1 + I_B - 1) / I_B; - tmp_blocks += indirect; - if (indirect > 1) - tmp_blocks++; - } - } - err |= put_user(BLOCK_SIZE, &statbuf->st_blksize); - err |= put_user((BLOCK_SIZE / 512) * tmp_blocks, &statbuf->st_blocks); -#undef D_B -#undef I_B - } + err |= put_user(stat->blksize, &statbuf->st_blksize); + err |= put_user(stat->blocks, &statbuf->st_blocks); err |= put_user(0, &statbuf->__unused4[0]); err |= put_user(0, &statbuf->__unused4[1]); return err; } -static __inline__ int -do_revalidate(struct dentry *dentry) -{ - struct inode * inode = dentry->d_inode; - if (inode->i_op && inode->i_op->revalidate) - return inode->i_op->revalidate(dentry); - return 0; -} - asmlinkage long sys32_newstat(char* filename, struct stat32* statbuf) { - struct nameidata nd; - int error; + struct kstat stat; + int error = vfs_stat(filename, &stat); - PPCDBG(PPCDBG_SYS32X, "sys32_newstat - running - filename=%s, statbuf=%p, pid=%ld, comm=%s\n", filename, statbuf, current->pid, current->comm); + if (!error) + error = cp_new_stat32(&stat, statbuf); - error = user_path_walk(filename, &nd); - if (!error) { - error = do_revalidate(nd.dentry); - if (!error) - error = cp_new_stat32(nd.dentry->d_inode, statbuf); - path_release(&nd); - } return error; } asmlinkage long sys32_newlstat(char * filename, struct stat32 *statbuf) { - struct nameidata nd; - int error; + struct kstat stat; + int error = vfs_lstat(filename, &stat); - PPCDBG(PPCDBG_SYS32X, "sys32_newlstat - running - fn=%s, pid=%ld, comm=%s\n", filename, current->pid, current->comm); + if (!error) + error = cp_new_stat32(&stat, statbuf); - error = user_path_walk_link(filename, &nd); - if (!error) { - error = do_revalidate(nd.dentry); - if (!error) - error = cp_new_stat32(nd.dentry->d_inode, statbuf); - - path_release(&nd); - } return error; } asmlinkage long sys32_newfstat(unsigned int fd, struct stat32 *statbuf) { - struct file *f; - int err = -EBADF; + struct kstat stat; + int error = vfs_fstat(fd, &stat); - PPCDBG(PPCDBG_SYS32X, "sys32_newfstat - running - fd=%x, pid=%ld, comm=%s\n", fd, current->pid, current->comm); + if (!error) + error = cp_new_stat32(&stat, statbuf); - f = fget(fd); - if (f) { - struct dentry * dentry = f->f_dentry; - - err = do_revalidate(dentry); - if (!err) - err = cp_new_stat32(dentry->d_inode, statbuf); - fput(f); - } - return err; + return error; } static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) @@ -3104,7 +3026,7 @@ /* stat syscall methods. */ extern asmlinkage int sys_stat(char* filename, struct __old_kernel_stat* statbuf); -static int cp_old_stat32(struct inode* inode, struct __old_kernel_stat32* statbuf) +static int cp_old_stat32(struct kstat *stat, struct __old_kernel_stat32* statbuf) { static int warncount = 5; struct __old_kernel_stat32 tmp; @@ -3115,79 +3037,51 @@ current->comm); } - tmp.st_dev = kdev_t_to_nr(inode->i_dev); - tmp.st_ino = inode->i_ino; - tmp.st_mode = inode->i_mode; - tmp.st_nlink = inode->i_nlink; - SET_OLDSTAT_UID(tmp, inode->i_uid); - SET_OLDSTAT_GID(tmp, inode->i_gid); - tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); - tmp.st_size = inode->i_size; - tmp.st_atime = inode->i_atime; - tmp.st_mtime = inode->i_mtime; - tmp.st_ctime = inode->i_ctime; + tmp.st_dev = stat->dev; + tmp.st_ino = stat->ino; + tmp.st_mode = stat->mode; + tmp.st_nlink = stat->nlink; + SET_OLDSTAT_UID(tmp, stat->uid); + SET_OLDSTAT_GID(tmp, stat->gid); + tmp.st_rdev = stat->rdev; + if (stat->size > MAX_NON_LFS) + return -EOVERFLOW; + tmp.st_size = stat->size; + tmp.st_atime = stat->atime; + tmp.st_mtime = stat->mtime; + tmp.st_ctime = stat->ctime; return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; } asmlinkage long sys32_stat(char* filename, struct __old_kernel_stat32* statbuf) { - struct nameidata nd; - int error; - - PPCDBG(PPCDBG_SYS32X, "sys32_stat - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); - - error = user_path_walk(filename, &nd); - if (!error) { - error = do_revalidate(nd.dentry); - if (!error) - error = cp_old_stat32(nd.dentry->d_inode, statbuf); - path_release(&nd); - } + struct kstat stat; + int error = vfs_stat(filename, &stat); - PPCDBG(PPCDBG_SYS32X, "sys32_stat - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + if (!error) + error = cp_old_stat32(&stat, statbuf); return error; } asmlinkage long sys32_fstat(unsigned int fd, struct __old_kernel_stat32* statbuf) { - struct file *f; - int err = -EBADF; - - PPCDBG(PPCDBG_SYS32X, "sys32_fstat - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); - - f = fget(fd); - if (f) { - struct dentry * dentry = f->f_dentry; - - err = do_revalidate(dentry); - if (!err) - err = cp_old_stat32(dentry->d_inode, statbuf); - fput(f); - } + struct kstat stat; + int error = vfs_fstat(fd, &stat); - PPCDBG(PPCDBG_SYS32X, "sys32_fstat - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + if (!error) + error = cp_old_stat32(&stat, statbuf); - return err; + return error; } asmlinkage long sys32_lstat(char* filename, struct __old_kernel_stat32* statbuf) { - struct nameidata nd; - int error; - - PPCDBG(PPCDBG_SYS32X, "sys32_lstat - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); - - error = user_path_walk_link(filename, &nd); - if (!error) { - error = do_revalidate(nd.dentry); - if (!error) - error = cp_old_stat32(nd.dentry->d_inode, statbuf); - - path_release(&nd); - } + struct kstat stat; + int error = vfs_lstat(filename, &stat); - PPCDBG(PPCDBG_SYS32X, "sys32_lstat - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); + if (!error) + error = cp_old_stat32(&stat, statbuf); return error; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/s390/kernel/smp.c linux-2.5/arch/s390/kernel/smp.c --- linux-2.5.5/arch/s390/kernel/smp.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/s390/kernel/smp.c Mon Mar 4 01:29:41 2002 @@ -528,7 +528,7 @@ * We remove it from the pidhash and the runqueue * once we got the process: */ - idle = init_task.prev_task; + idle = LAST_TASK; if (!idle) panic("No idle process for CPU %d",cpu); idle->processor = cpu; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/s390x/kernel/smp.c linux-2.5/arch/s390x/kernel/smp.c --- linux-2.5.5/arch/s390x/kernel/smp.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/s390x/kernel/smp.c Mon Mar 4 01:29:41 2002 @@ -507,7 +507,7 @@ * We remove it from the pidhash and the runqueue * once we got the process: */ - idle = init_task.prev_task; + idle = LAST_TASK; if (!idle) panic("No idle process for CPU %d",cpu); idle->processor = cpu; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sh/config.in linux-2.5/arch/sh/config.in --- linux-2.5.5/arch/sh/config.in Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/sh/config.in Thu Feb 14 02:57:58 2002 @@ -258,15 +258,12 @@ fi endmenu -# -# input before char - char/joystick depends on it. As does USB. -# -source drivers/input/Config.in - if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then source drivers/maple/Config.in fi +source drivers/input/Config.in + mainmenu_option next_comment comment 'Character devices' @@ -295,20 +292,6 @@ "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then bool 'Heartbeat LED' CONFIG_HEARTBEAT fi - -if [ "$CONFIG_SH_DREAMCAST" = "y" -a "$CONFIG_MAPLE" != "n" ]; then - mainmenu_option next_comment - comment 'Maple Bus input peripherals' - if [ "$CONFIG_INPUT" != "n" ]; then - dep_tristate ' Maple Bus keyboard support' CONFIG_MAPLE_KEYBOARD $CONFIG_INPUT - dep_tristate ' Maple Bus mouse support' CONFIG_MAPLE_MOUSE $CONFIG_INPUT - else - comment 'Input core support is required for Maple input peripherals' - fi - endmenu -fi - -source drivers/char/joystick/Config.in if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sh/kernel/sh_ksyms.c linux-2.5/arch/sh/kernel/sh_ksyms.c --- linux-2.5.5/arch/sh/kernel/sh_ksyms.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/sh/kernel/sh_ksyms.c Mon Feb 18 21:48:35 2002 @@ -39,9 +39,6 @@ /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); -EXPORT_SYMBOL(simple_strtol); - -EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strlen); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc/Makefile linux-2.5/arch/sparc/Makefile --- linux-2.5.5/arch/sparc/Makefile Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/sparc/Makefile Sun Feb 3 18:03:58 2002 @@ -41,7 +41,7 @@ CORE_FILES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(CORE_FILES) \ arch/sparc/math-emu/math-emu.o -LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \ +LIBS := $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \ $(TOPDIR)/arch/sparc/lib/lib.a # This one has to come last diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc/defconfig linux-2.5/arch/sparc/defconfig --- linux-2.5.5/arch/sparc/defconfig Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/sparc/defconfig Tue Jan 29 13:37:38 2002 @@ -377,6 +377,7 @@ # CONFIG_NLS_CODEPAGE_949 is not set # CONFIG_NLS_CODEPAGE_874 is not set # CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc/kernel/sparc_ksyms.c linux-2.5/arch/sparc/kernel/sparc_ksyms.c --- linux-2.5.5/arch/sparc/kernel/sparc_ksyms.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/sparc/kernel/sparc_ksyms.c Mon Feb 18 21:48:37 2002 @@ -250,7 +250,6 @@ EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strpbrk); -EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(page_kernel); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc/kernel/sun4d_smp.c linux-2.5/arch/sparc/kernel/sun4d_smp.c --- linux-2.5.5/arch/sparc/kernel/sun4d_smp.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/sparc/kernel/sun4d_smp.c Mon Mar 4 01:29:41 2002 @@ -220,7 +220,7 @@ cpucount++; - p = init_task.prev_task; + p = LAST_TASK; p->cpu = i; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc/kernel/sun4m_smp.c linux-2.5/arch/sparc/kernel/sun4m_smp.c --- linux-2.5.5/arch/sparc/kernel/sun4m_smp.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/sparc/kernel/sun4m_smp.c Mon Mar 4 01:29:41 2002 @@ -193,7 +193,7 @@ cpucount++; - p = init_task.prev_task; + p = LAST_TASK; p->cpu = i; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc/kernel/sunos_ioctl.c linux-2.5/arch/sparc/kernel/sunos_ioctl.c --- linux-2.5.5/arch/sparc/kernel/sunos_ioctl.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/sparc/kernel/sunos_ioctl.c Mon Jan 14 22:39:45 2002 @@ -39,8 +39,12 @@ { int ret = -EBADF; - if (fd >= SUNOS_NR_OPEN || !fcheck(fd)) + read_lock(¤t->files->file_lock); + if (fd >= SUNOS_NR_OPEN || !fcheck(fd)) { + read_unlock(¤t->files->file_lock); goto out; + } + read_unlock(¤t->files->file_lock); /* First handle an easy compat. case for tty ldisc. */ if(cmd == TIOCSETD) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc/mm/srmmu.c linux-2.5/arch/sparc/mm/srmmu.c --- linux-2.5.5/arch/sparc/mm/srmmu.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/arch/sparc/mm/srmmu.c Thu Feb 14 00:36:31 2002 @@ -1963,7 +1963,7 @@ iaddr = &(insn); \ daddr = &(dest); \ *iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \ - } while(0); + } while(0) static void __init patch_window_trap_handlers(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc/mm/sun4c.c linux-2.5/arch/sparc/mm/sun4c.c --- linux-2.5.5/arch/sparc/mm/sun4c.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/sparc/mm/sun4c.c Mon Feb 18 03:39:04 2002 @@ -425,7 +425,7 @@ daddr = &(dst); \ iaddr = &(src); \ *daddr = *iaddr; \ - } while (0); + } while (0) static void patch_kernel_fault_handler(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/Makefile linux-2.5/arch/sparc64/Makefile --- linux-2.5.5/arch/sparc64/Makefile Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/sparc64/Makefile Mon Feb 11 23:59:45 2002 @@ -69,7 +69,7 @@ CORE_FILES += arch/sparc64/math-emu/math-emu.o -LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \ +LIBS := $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \ $(TOPDIR)/arch/sparc64/lib/lib.a vmlinux.aout: vmlinux diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/config.in linux-2.5/arch/sparc64/config.in --- linux-2.5.5/arch/sparc64/config.in Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/sparc64/config.in Thu Feb 14 02:57:58 2002 @@ -291,5 +291,3 @@ fi endmenu - -source lib/Config.in diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/kernel/binfmt_elf32.c linux-2.5/arch/sparc64/kernel/binfmt_elf32.c --- linux-2.5.5/arch/sparc64/kernel/binfmt_elf32.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/sparc64/kernel/binfmt_elf32.c Thu Feb 14 00:36:31 2002 @@ -43,7 +43,7 @@ dest[34] = (unsigned int) src->tnpc; \ dest[35] = src->y; \ dest[36] = dest[37] = 0; /* XXX */ \ -} while(0); +} while(0) typedef struct { union { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/kernel/irq.c linux-2.5/arch/sparc64/kernel/irq.c --- linux-2.5.5/arch/sparc64/kernel/irq.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/sparc64/kernel/irq.c Tue Jan 15 12:22:31 2002 @@ -830,6 +830,11 @@ kbd_pt_regs = regs; #endif +#ifdef CONFIG_PCI + if (irq == 9) + kbd_pt_regs = regs; +#endif + /* Sliiiick... */ #ifndef CONFIG_SMP bp = ((irq != 0) ? diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/kernel/pci.c linux-2.5/arch/sparc64/kernel/pci.c --- linux-2.5.5/arch/sparc64/kernel/pci.c Wed Feb 20 02:10:52 2002 +++ linux-2.5/arch/sparc64/kernel/pci.c Mon Feb 25 22:20:45 2002 @@ -418,7 +418,7 @@ enum pci_mmap_state mmap_state) { unsigned long user_offset = vma->vm_pgoff << PAGE_SHIFT; - unsigned long user32 = user_offset & 0xffffffffUL; + unsigned long user32 = user_offset & pci_memspace_mask; unsigned long largest_base, this_base, addr32; int i; @@ -448,7 +448,7 @@ this_base = rp->start; - addr32 = (this_base & PAGE_MASK) & 0xffffffffUL; + addr32 = (this_base & PAGE_MASK) & pci_memspace_mask; if (mmap_state == pci_mmap_io) addr32 &= 0xffffff; @@ -464,7 +464,7 @@ if (mmap_state == pci_mmap_io) vma->vm_pgoff = (((largest_base & ~0xffffffUL) | user32) >> PAGE_SHIFT); else - vma->vm_pgoff = (((largest_base & ~0xffffffffUL) | user32) >> PAGE_SHIFT); + vma->vm_pgoff = (((largest_base & ~(pci_memspace_mask)) | user32) >> PAGE_SHIFT); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/kernel/pci_common.c linux-2.5/arch/sparc64/kernel/pci_common.c --- linux-2.5.5/arch/sparc64/kernel/pci_common.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/sparc64/kernel/pci_common.c Mon Feb 11 23:59:45 2002 @@ -684,6 +684,20 @@ return; } + /* If this is an empty EBUS device, sometimes OBP fails to + * give it a valid fully specified interrupts property. + * The EBUS hooked up to SunHME on PCI I/O boards of + * Ex000 systems is one such case. + * + * The interrupt is not important so just ignore it. + */ + if (pdev->vendor == PCI_VENDOR_ID_SUN && + pdev->device == PCI_DEVICE_ID_SUN_EBUS && + !prom_getchild(prom_node)) { + pdev->irq = 0; + return; + } + err = prom_getproperty(prom_node, "interrupts", (char *)&prom_irq, sizeof(prom_irq)); if (err == 0 || err == -1) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/kernel/rtrap.S linux-2.5/arch/sparc64/kernel/rtrap.S --- linux-2.5.5/arch/sparc64/kernel/rtrap.S Wed Feb 20 02:11:02 2002 +++ linux-2.5/arch/sparc64/kernel/rtrap.S Mon Feb 11 23:59:45 2002 @@ -42,7 +42,8 @@ __handle_user_windows: call fault_in_user_windows wrpr %g0, RTRAP_PSTATE, %pstate - wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate + ba,pt %xcc, __handle_user_windows_continue + wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate /* Redo sched+sig checks */ ldx [%g6 + TI_FLAGS], %l0 andcc %l0, _TIF_NEED_RESCHED, %g0 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/kernel/smp.c linux-2.5/arch/sparc64/kernel/smp.c --- linux-2.5.5/arch/sparc64/kernel/smp.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/sparc64/kernel/smp.c Mon Mar 4 01:29:41 2002 @@ -270,7 +270,7 @@ kernel_thread(NULL, NULL, CLONE_PID); cpucount++; - p = init_task.prev_task; + p = LAST_TASK; init_idle(p, i); @@ -689,14 +689,14 @@ if (page->mapping != NULL) data0 |= ((u64)1 << 32); spitfire_xcall_deliver(data0, - __pa(page->virtual), - (u64) page->virtual, - mask); + __pa(page->virtual), + (u64) page->virtual, + mask); } else { data0 = ((u64)&xcall_flush_dcache_page_cheetah); cheetah_xcall_deliver(data0, - __pa(page->virtual), - 0, mask); + __pa(page->virtual), + 0, mask); } #ifdef CONFIG_DEBUG_DCFLUSH atomic_inc(&dcpage_flushes_xcall); @@ -815,11 +815,9 @@ } } -void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, +void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - struct mm_struct *mm = vma->vm_mm; - { u32 ctx = CTX_HWBITS(mm->context); int cpu = smp_processor_id(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/kernel/sparc64_ksyms.c linux-2.5/arch/sparc64/kernel/sparc64_ksyms.c --- linux-2.5.5/arch/sparc64/kernel/sparc64_ksyms.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/sparc64/kernel/sparc64_ksyms.c Mon Feb 18 21:48:40 2002 @@ -298,7 +298,6 @@ EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strpbrk); -EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strstr); #ifdef CONFIG_SOLARIS_EMUL_MODULE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/kernel/sunos_ioctl32.c linux-2.5/arch/sparc64/kernel/sunos_ioctl32.c --- linux-2.5.5/arch/sparc64/kernel/sunos_ioctl32.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/arch/sparc64/kernel/sunos_ioctl32.c Mon Jan 14 22:39:45 2002 @@ -100,8 +100,12 @@ if(fd >= SUNOS_NR_OPEN) goto out; - if(!fcheck(fd)) + read_lock(¤t->files->file_lock); + if(!fcheck(fd)) { + read_unlock(¤t->files->file_lock); goto out; + } + read_unlock(¤t->files->file_lock); if(cmd == TIOCSETD) { mm_segment_t old_fs = get_fs(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/kernel/sys_sparc32.c linux-2.5/arch/sparc64/kernel/sys_sparc32.c --- linux-2.5.5/arch/sparc64/kernel/sys_sparc32.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/arch/sparc64/kernel/sys_sparc32.c Fri Mar 1 15:07:37 2002 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -1067,16 +1068,20 @@ /* First get the "struct iovec" from user memory and * verify all the pointers */ + retval = 0; if (!count) - return 0; + goto out_nofree; + retval = -EFAULT; if (verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count)) - return -EFAULT; + goto out_nofree; + retval = -EINVAL; if (count > UIO_MAXIOV) - return -EINVAL; + goto out_nofree; if (count > UIO_FASTIOV) { + retval = -ENOMEM; iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); if (!iov) - return -ENOMEM; + goto out_nofree; } tot_len = 0; @@ -1136,6 +1141,11 @@ out: if (iov != iovstack) kfree(iov); +out_nofree: + /* VERIFY_WRITE actually means a read, as we write to user space */ + if ((retval + (type == VERIFY_WRITE)) > 0) + dnotify_parent(file->f_dentry, + (type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS); return retval; } @@ -1471,6 +1481,8 @@ err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid); err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid); err |= put_user(stat->rdev, &statbuf->st_rdev); + if (stat->size > MAX_NON_LFS) + return -EOVERFLOW; err |= put_user(stat->size, &statbuf->st_size); err |= put_user(stat->atime, &statbuf->st_atime); err |= put_user(0, &statbuf->__unused1); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/mm/init.c linux-2.5/arch/sparc64/mm/init.c --- linux-2.5.5/arch/sparc64/mm/init.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/sparc64/mm/init.c Mon Feb 11 23:59:45 2002 @@ -589,6 +589,10 @@ remap_func(((tte_data + 0x400000) & _PAGE_PADDR), (unsigned long) KERNBASE + 0x400000, prom_get_mmu_ihandle()); + if (bigkernel) + remap_func(((tte_data + 0x400000) & _PAGE_PADDR), + (unsigned long) KERNBASE + 0x400000, prom_get_mmu_ihandle()); + /* Flush out that temporary mapping. */ spitfire_flush_dtlb_nucleus_page(0x0); spitfire_flush_itlb_nucleus_page(0x0); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/solaris/ioctl.c linux-2.5/arch/sparc64/solaris/ioctl.c --- linux-2.5.5/arch/sparc64/solaris/ioctl.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/sparc64/solaris/ioctl.c Mon Feb 11 23:59:45 2002 @@ -289,11 +289,15 @@ { struct inode *ino; /* I wonder which of these tests are superfluous... --patrik */ + read_lock(¤t->files->file_lock); if (! current->files->fd[fd] || ! current->files->fd[fd]->f_dentry || ! (ino = current->files->fd[fd]->f_dentry->d_inode) || - ! ino->i_sock) + ! ino->i_sock) { + read_unlock(¤t->files->file_lock); return TBADF; + } + read_unlock(¤t->files->file_lock); switch (cmd & 0xff) { case 109: /* SI_SOCKPARAMS */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/sparc64/solaris/timod.c linux-2.5/arch/sparc64/solaris/timod.c --- linux-2.5.5/arch/sparc64/solaris/timod.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/sparc64/solaris/timod.c Mon Feb 11 23:59:45 2002 @@ -149,7 +149,9 @@ struct socket *sock; SOLD("wakeing socket"); + read_lock(¤t->files->file_lock); sock = SOCKET_I(current->files->fd[fd]->f_dentry->d_inode); + read_unlock(¤t->files->file_lock); wake_up_interruptible(&sock->wait); read_lock(&sock->sk->callback_lock); if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) @@ -163,7 +165,9 @@ struct sol_socket_struct *sock; SOLD("queuing primsg"); + read_lock(¤t->files->file_lock); sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data; + read_unlock(¤t->files->file_lock); it->next = sock->pfirst; sock->pfirst = it; if (!sock->plast) @@ -177,7 +181,9 @@ struct sol_socket_struct *sock; SOLD("queuing primsg at end"); + read_lock(¤t->files->file_lock); sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data; + read_unlock(¤t->files->file_lock); it->next = NULL; if (sock->plast) sock->plast->next = it; @@ -355,7 +361,11 @@ (int (*)(int, unsigned long *))SYS(socketcall); int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int) = (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int))SYS(sendto); - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); + if (!filp) + return -EBADF; ino = filp->f_dentry->d_inode; sock = (struct sol_socket_struct *)filp->private_data; SOLD("entry"); @@ -636,7 +646,11 @@ SOLD("entry"); SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p)); - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); + if (!filp) + return -EBADF; ino = filp->f_dentry->d_inode; sock = (struct sol_socket_struct *)filp->private_data; SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL)); @@ -847,7 +861,9 @@ lock_kernel(); if(fd >= NR_OPEN) goto out; - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); if(!filp) goto out; ino = filp->f_dentry->d_inode; @@ -914,7 +930,9 @@ lock_kernel(); if(fd >= NR_OPEN) goto out; - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); if(!filp) goto out; ino = filp->f_dentry->d_inode; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/config.in linux-2.5/arch/x86_64/config.in --- linux-2.5.5/arch/x86_64/config.in Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/x86_64/config.in Fri Mar 1 15:07:37 2002 @@ -29,7 +29,7 @@ define_int CONFIG_X86_L1_CACHE_SHIFT 6 define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_GOOD_APIC y -define_bool CONFIG_X86_CMPXCHG +define_bool CONFIG_X86_CMPXCHG y tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID @@ -72,6 +72,7 @@ if [ "$CONFIG_HOTPLUG" = "y" ] ; then source drivers/pcmcia/Config.in + source drivers/hotplug/Config.in else define_bool CONFIG_PCMCIA n fi @@ -80,8 +81,8 @@ define_bool CONFIG_KCORE_ELF y fi # We probably are not going to support a.out, are we? Or should we support a.out in i386 compatibility mode? -#tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF + #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 bool 'Power Management support' CONFIG_PM diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/defconfig linux-2.5/arch/x86_64/defconfig --- linux-2.5.5/arch/x86_64/defconfig Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/x86_64/defconfig Fri Mar 1 15:07:37 2002 @@ -37,6 +37,7 @@ CONFIG_X86_L1_CACHE_SHIFT=6 CONFIG_X86_TSC=y CONFIG_X86_GOOD_APIC=y +CONFIG_X86_CMPXCHG=y CONFIG_X86_MSR=y CONFIG_X86_CPUID=y # CONFIG_MATH_EMULATION is not set @@ -59,16 +60,7 @@ # CONFIG_BINFMT_MISC is not set CONFIG_PM=y CONFIG_IA32_EMULATION=y -CONFIG_ACPI=y -CONFIG_ACPI_DEBUG=y -CONFIG_ACPI_BUSMGR=y -CONFIG_ACPI_SYS=y -CONFIG_ACPI_CPU=y -CONFIG_ACPI_BUTTON=y -CONFIG_ACPI_AC=y -CONFIG_ACPI_EC=y -CONFIG_ACPI_CMBATT=y -CONFIG_ACPI_THERMAL=y +# CONFIG_ACPI is not set # # Memory Technology Devices (MTD) @@ -99,9 +91,8 @@ # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set # # Multi-device support (RAID and LVM) @@ -388,7 +379,6 @@ # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set # CONFIG_UFS_FS_WRITE is not set -CONFIG_SIMICSFS=y # # Network File Systems diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/ia32/ia32_binfmt.c linux-2.5/arch/x86_64/ia32/ia32_binfmt.c --- linux-2.5.5/arch/x86_64/ia32/ia32_binfmt.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/arch/x86_64/ia32/ia32_binfmt.c Fri Mar 1 15:07:37 2002 @@ -12,6 +12,9 @@ #include #include +struct file; +struct elf_phdr; + #define IA32_EMULATOR 1 #define IA32_PAGE_OFFSET 0xE0000000 @@ -77,7 +80,6 @@ __asm__("movl %0,%%fs": :"r" (0)); \ __asm__("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \ wrmsrl(MSR_KERNEL_GS_BASE, 0); \ - set_thread_flag(TIF_IA32); \ (regs)->rip = (new_rip); \ (regs)->rsp = (new_rsp); \ (regs)->eflags = 0x200; \ @@ -87,6 +89,8 @@ } while(0) +#define elf_map elf32_map + MODULE_DESCRIPTION("Binary format loader for compatibility with IA32 ELF binaries."); MODULE_AUTHOR("Eric Youngdale, Andi Kleen"); @@ -102,6 +106,7 @@ static void elf32_init(struct pt_regs *regs) { + struct task_struct *me = current; regs->rdi = 0; regs->rsi = 0; regs->rdx = 0; @@ -109,9 +114,13 @@ regs->rax = 0; regs->rbx = 0; regs->rbp = 0; - current->thread.fs = 0; current->thread.gs = 0; - current->thread.fsindex = 0; current->thread.gsindex = 0; - current->thread.ds = __USER_DS; current->thread.es == __USER_DS; + me->thread.fs = 0; + me->thread.gs = 0; + me->thread.fsindex = 0; + me->thread.gsindex = 0; + me->thread.ds = __USER_DS; + me->thread.es = __USER_DS; + set_thread_flag(TIF_IA32); } extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address); @@ -161,5 +170,18 @@ up_write(¤t->mm->mmap_sem); return 0; +} +static unsigned long +elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) +{ + unsigned long map_addr; + struct task_struct *me = current; + + down_write(&me->mm->mmap_sem); + map_addr = do_mmap(filep, ELF_PAGESTART(addr), + eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type|MAP_32BIT, + eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); + up_write(&me->mm->mmap_sem); + return(map_addr); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/ia32/ia32_ioctl.c linux-2.5/arch/x86_64/ia32/ia32_ioctl.c --- linux-2.5.5/arch/x86_64/ia32/ia32_ioctl.c Wed Feb 20 02:10:52 2002 +++ linux-2.5/arch/x86_64/ia32/ia32_ioctl.c Fri Mar 1 15:07:37 2002 @@ -3083,8 +3083,6 @@ COMPATIBLE_IOCTL(BLKROGET) COMPATIBLE_IOCTL(BLKRRPART) COMPATIBLE_IOCTL(BLKFLSBUF) -COMPATIBLE_IOCTL(BLKRASET) -COMPATIBLE_IOCTL(BLKFRASET) COMPATIBLE_IOCTL(BLKSECTSET) COMPATIBLE_IOCTL(BLKSSZGET) @@ -3596,10 +3594,8 @@ HANDLE_IOCTL(SIOCRTMSG, ret_einval) HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo) -HANDLE_IOCTL(BLKRAGET, w_long) HANDLE_IOCTL(BLKGETSIZE, w_long) HANDLE_IOCTL(0x1260, broken_blkgetsize) -HANDLE_IOCTL(BLKFRAGET, w_long) HANDLE_IOCTL(BLKSECTGET, w_long) HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans) HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/ia32/ia32_signal.c linux-2.5/arch/x86_64/ia32/ia32_signal.c --- linux-2.5.5/arch/x86_64/ia32/ia32_signal.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/arch/x86_64/ia32/ia32_signal.c Fri Mar 1 15:07:37 2002 @@ -82,7 +82,7 @@ spin_lock_irq(¤t->sigmask_lock); saveset = current->blocked; siginitset(¤t->blocked, mask); - recalc_sigpending(current); + recalc_sigpending(); spin_unlock_irq(¤t->sigmask_lock); regs.rax = -EINTR; @@ -225,7 +225,7 @@ sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); current->blocked = set; - recalc_sigpending(current); + recalc_sigpending(); spin_unlock_irq(¤t->sigmask_lock); if (restore_sigcontext(®s, &frame->sc, &eax)) @@ -252,7 +252,7 @@ sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); current->blocked = set; - recalc_sigpending(current); + recalc_sigpending(); spin_unlock_irq(¤t->sigmask_lock); if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &eax)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/kernel/mtrr.c linux-2.5/arch/x86_64/kernel/mtrr.c --- linux-2.5.5/arch/x86_64/kernel/mtrr.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/x86_64/kernel/mtrr.c Mon Feb 25 14:46:18 2002 @@ -1,249 +1,26 @@ -/* Generic MTRR (Memory Type Range Register) driver. +/* x86-64 MTRR (Memory Type Range Register) driver. + Based largely upon arch/i386/kernel/mtrr.c - Copyright (C) 1997-2000 Richard Gooch + Copyright (C) 1997-2000 Richard Gooch + Copyright (C) 2002 Dave Jones. - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Richard Gooch may be reached by email at rgooch@atnf.csiro.au - The postal address is: - Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. - - Source: "Pentium Pro Family Developer's Manual, Volume 3: - Operating System Writer's Guide" (Intel document number 242692), - section 11.11.7 - - ChangeLog - - Prehistory Martin Tischhäuser - Initial register-setting code (from proform-1.0). - 19971216 Richard Gooch - Original version for /proc/mtrr interface, SMP-safe. - v1.0 - 19971217 Richard Gooch - Bug fix for ioctls()'s. - Added sample code in Documentation/mtrr.txt - v1.1 - 19971218 Richard Gooch - Disallow overlapping regions. - 19971219 Jens Maurer - Register-setting fixups. - v1.2 - 19971222 Richard Gooch - Fixups for kernel 2.1.75. - v1.3 - 19971229 David Wragg - Register-setting fixups and conformity with Intel conventions. - 19971229 Richard Gooch - Cosmetic changes and wrote this ChangeLog ;-) - 19980106 Richard Gooch - Fixups for kernel 2.1.78. - v1.4 - 19980119 David Wragg - Included passive-release enable code (elsewhere in PCI setup). - v1.5 - 19980131 Richard Gooch - Replaced global kernel lock with private spinlock. - v1.6 - 19980201 Richard Gooch - Added wait for other CPUs to complete changes. - v1.7 - 19980202 Richard Gooch - Bug fix in definition of for UP. - v1.8 - 19980319 Richard Gooch - Fixups for kernel 2.1.90. - 19980323 Richard Gooch - Move SMP BIOS fixup before secondary CPUs call - v1.9 - 19980325 Richard Gooch - Fixed test for overlapping regions: confused by adjacent regions - 19980326 Richard Gooch - Added wbinvd in . - 19980401 Richard Gooch - Bug fix for non-SMP compilation. - 19980418 David Wragg - Fixed-MTRR synchronisation for SMP and use atomic operations - instead of spinlocks. - 19980418 Richard Gooch - Differentiate different MTRR register classes for BIOS fixup. - v1.10 - 19980419 David Wragg - Bug fix in variable MTRR synchronisation. - v1.11 - 19980419 Richard Gooch - Fixups for kernel 2.1.97. - v1.12 - 19980421 Richard Gooch - Safer synchronisation across CPUs when changing MTRRs. - v1.13 - 19980423 Richard Gooch - Bugfix for SMP systems without MTRR support. - v1.14 - 19980427 Richard Gooch - Trap calls to and on non-MTRR machines. - v1.15 - 19980427 Richard Gooch - Use atomic bitops for setting SMP change mask. - v1.16 - 19980428 Richard Gooch - Removed spurious diagnostic message. - v1.17 - 19980429 Richard Gooch - Moved register-setting macros into this file. - Moved setup code from init/main.c to i386-specific areas. - v1.18 - 19980502 Richard Gooch - Moved MTRR detection outside conditionals in . - v1.19 - 19980502 Richard Gooch - Documentation improvement: mention Pentium II and AGP. - v1.20 - 19980521 Richard Gooch - Only manipulate interrupt enable flag on local CPU. - Allow enclosed uncachable regions. - v1.21 - 19980611 Richard Gooch - Always define . - v1.22 - 19980901 Richard Gooch - Removed module support in order to tidy up code. - Added sanity check for / before . - Created addition queue for prior to SMP commence. - v1.23 - 19980902 Richard Gooch - Ported patch to kernel 2.1.120-pre3. - v1.24 - 19980910 Richard Gooch - Removed sanity checks and addition queue: Linus prefers an OOPS. - v1.25 - 19981001 Richard Gooch - Fixed harmless compiler warning in include/asm-i386/mtrr.h - Fixed version numbering and history for v1.23 -> v1.24. - v1.26 - 19990118 Richard Gooch - Added devfs support. - v1.27 - 19990123 Richard Gooch - Changed locking to spin with reschedule. - Made use of new . - v1.28 - 19990201 Zoltán Böszörményi - Extended the driver to be able to use Cyrix style ARRs. - 19990204 Richard Gooch - Restructured Cyrix support. - v1.29 - 19990204 Zoltán Böszörményi - Refined ARR support: enable MAPEN in set_mtrr_prepare() - and disable MAPEN in set_mtrr_done(). - 19990205 Richard Gooch - Minor cleanups. - v1.30 - 19990208 Zoltán Böszörményi - Protect plain 6x86s (and other processors without the - Page Global Enable feature) against accessing CR4 in - set_mtrr_prepare() and set_mtrr_done(). - 19990210 Richard Gooch - Turned and into function pointers. - v1.31 - 19990212 Zoltán Böszörményi - Major rewrite of cyrix_arr_init(): do not touch ARRs, - leave them as the BIOS have set them up. - Enable usage of all 8 ARRs. - Avoid multiplications by 3 everywhere and other - code clean ups/speed ups. - 19990213 Zoltán Böszörményi - Set up other Cyrix processors identical to the boot cpu. - Since Cyrix don't support Intel APIC, this is l'art pour l'art. - Weigh ARRs by size: - If size <= 32M is given, set up ARR# we were given. - If size > 32M is given, set up ARR7 only if it is free, - fail otherwise. - 19990214 Zoltán Böszörményi - Also check for size >= 256K if we are to set up ARR7, - mtrr_add() returns the value it gets from set_mtrr() - 19990218 Zoltán Böszörményi - Remove Cyrix "coma bug" workaround from here. - Moved to linux/arch/i386/kernel/setup.c and - linux/include/asm-i386/bugs.h - 19990228 Richard Gooch - Added MTRRIOC_KILL_ENTRY ioctl(2) - Trap for counter underflow in . - Trap for 4 MiB aligned regions for PPro, stepping <= 7. - 19990301 Richard Gooch - Created hook. - 19990305 Richard Gooch - Temporarily disable AMD support now MTRR capability flag is set. - v1.32 - 19990308 Zoltán Böszörményi - Adjust my changes (19990212-19990218) to Richard Gooch's - latest changes. (19990228-19990305) - v1.33 - 19990309 Richard Gooch - Fixed typo in message. - 19990310 Richard Gooch - Support K6-II/III based on Alan Cox's patches. - v1.34 - 19990511 Bart Hartgers - Support Centaur C6 MCR's. - 19990512 Richard Gooch - Minor cleanups. - v1.35 - 19990707 Zoltán Böszörményi - Check whether ARR3 is protected in cyrix_get_free_region() - and mtrr_del(). The code won't attempt to delete or change it - from now on if the BIOS protected ARR3. It silently skips ARR3 - in cyrix_get_free_region() or returns with an error code from - mtrr_del(). - 19990711 Zoltán Böszörményi - Reset some bits in the CCRs in cyrix_arr_init() to disable SMM - if ARR3 isn't protected. This is needed because if SMM is active - and ARR3 isn't protected then deleting and setting ARR3 again - may lock up the processor. With SMM entirely disabled, it does - not happen. - 19990812 Zoltán Böszörményi - Rearrange switch() statements so the driver accomodates to - the fact that the AMD Athlon handles its MTRRs the same way - as Intel does. - 19990814 Zoltán Böszörményi - Double check for Intel in mtrr_add()'s big switch() because - that revision check is only valid for Intel CPUs. - 19990819 Alan Cox - Tested Zoltan's changes on a pre production Athlon - 100% - success. - 19991008 Manfred Spraul - replaced spin_lock_reschedule() with a normal semaphore. - v1.36 - 20000221 Richard Gooch - Compile fix if procfs and devfs not enabled. - Formatting changes. - v1.37 - 20001109 H. Peter Anvin - Use the new centralized CPU feature detects. - - v1.38 - 20010309 Dave Jones - Add support for Cyrix III. - - v1.39 - 20010312 Dave Jones - Ugh, I broke AMD support. - Reworked fix by Troels Walsted Hansen - - v1.40 - 20010327 Dave Jones - Adapted Cyrix III support to include VIA C3. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + (For earlier history, see arch/i386/kernel/mtrr.c) + September 2001 Dave Jones + Initial rewrite for x86-64. */ #include @@ -264,7 +41,6 @@ #include #include #include -#include #define MTRR_NEED_STRINGS #include #include @@ -284,28 +60,11 @@ #include #include -#define MTRR_VERSION "1.40 (20010327)" +#define MTRR_VERSION "2.00 (20020207)" #define TRUE 1 #define FALSE 0 -/* - * The code assumes all processors support the same MTRR - * interface. This is generally a good assumption, but could - * potentially be a problem. - */ -enum mtrr_if_type { - MTRR_IF_NONE, /* No MTRRs supported */ - MTRR_IF_INTEL, /* Intel (P6) standard MTRRs */ - MTRR_IF_AMD_K6, /* AMD pre-Athlon MTRRs */ - MTRR_IF_CYRIX_ARR, /* Cyrix ARRs */ - MTRR_IF_CENTAUR_MCR, /* Centaur MCRs */ -} mtrr_if = MTRR_IF_NONE; - -static __initdata char *mtrr_if_name[] = { - "none", "Intel", "AMD K6", "Cyrix ARR", "Centaur MCR" -}; - #define MTRRcap_MSR 0x0fe #define MTRRdefType_MSR 0x2ff @@ -326,31 +85,28 @@ #define MTRRfix4K_F8000_MSR 0x26f #ifdef CONFIG_SMP -# define MTRR_CHANGE_MASK_FIXED 0x01 -# define MTRR_CHANGE_MASK_VARIABLE 0x02 -# define MTRR_CHANGE_MASK_DEFTYPE 0x04 +#define MTRR_CHANGE_MASK_FIXED 0x01 +#define MTRR_CHANGE_MASK_VARIABLE 0x02 +#define MTRR_CHANGE_MASK_DEFTYPE 0x04 #endif -/* In the Intel processor's MTRR interface, the MTRR type is always held in - an 8 bit field: */ typedef u8 mtrr_type; #define LINE_SIZE 80 -#define JIFFIE_TIMEOUT 100 #ifdef CONFIG_SMP -# define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type) +#define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type) #else -# define set_mtrr(reg,base,size,type) (*set_mtrr_up) (reg, base, size, type, \ +#define set_mtrr(reg,base,size,type) (*set_mtrr_up) (reg, base, size, type, \ TRUE) #endif #if defined(CONFIG_PROC_FS) || defined(CONFIG_DEVFS_FS) -# define USERSPACE_INTERFACE +#define USERSPACE_INTERFACE #endif #ifndef USERSPACE_INTERFACE -# define compute_ascii() while (0) +#define compute_ascii() while (0) #endif #ifdef USERSPACE_INTERFACE @@ -358,329 +114,123 @@ static unsigned int ascii_buf_bytes; #endif static unsigned int *usage_table; -static DECLARE_MUTEX(main_lock); +static DECLARE_MUTEX (main_lock); /* Private functions */ #ifdef USERSPACE_INTERFACE static void compute_ascii (void); #endif - -struct set_mtrr_context -{ - unsigned long flags; - unsigned long deftype_lo; - unsigned long deftype_hi; - unsigned long cr4val; - unsigned long ccr3; +struct set_mtrr_context { + unsigned long flags; + unsigned long deftype_lo; + unsigned long deftype_hi; + unsigned long cr4val; }; -static int arr3_protected; /* Put the processor into a state where MTRRs can be safely set */ -static void set_mtrr_prepare_save (struct set_mtrr_context *ctxt) +static void set_mtrr_prepare (struct set_mtrr_context *ctxt) { - /* Disable interrupts locally */ - __save_flags (ctxt->flags); __cli (); + unsigned int cr0; - if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) - return; + /* Disable interrupts locally */ + __save_flags(ctxt->flags); + __cli(); + + /* Save value of CR4 and clear Page Global Enable (bit 7) */ + if (test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability)) { + ctxt->cr4val = read_cr4(); + write_cr4(ctxt->cr4val & (unsigned char) ~(1 << 7)); + } + + /* Disable and flush caches. Note that wbinvd flushes the TLBs as + a side-effect */ + cr0 = read_cr0() | 0x40000000; + wbinvd(); + write_cr0(cr0); + wbinvd(); + + /* Disable MTRRs, and set the default type to uncached */ + rdmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); + wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); +} - /* Save value of CR4 and clear Page Global Enable (bit 7) */ - if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) ) { - ctxt->cr4val = read_cr4(); - write_cr4(ctxt->cr4val & ~(1<<7)); - } - - /* Disable and flush caches. Note that wbinvd flushes the TLBs as - a side-effect */ - - { - long cr0 = read_cr0() | 0x40000000; - wbinvd(); - write_cr0( cr0 ); - wbinvd(); - } - - if ( mtrr_if == MTRR_IF_INTEL ) { - /* Save MTRR state */ - rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); - } else { - /* Cyrix ARRs - everything else were excluded at the top */ - ctxt->ccr3 = getCx86 (CX86_CCR3); - } -} /* End Function set_mtrr_prepare_save */ - -static void set_mtrr_cache_disable (struct set_mtrr_context *ctxt) -{ - if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) - return; - - if ( mtrr_if == MTRR_IF_INTEL ) { - /* Disable MTRRs, and set the default type to uncached */ - wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); - } else { - /* Cyrix ARRs - everything else were excluded at the top */ - setCx86 (CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10); - } -} /* End Function set_mtrr_cache_disable */ -/* Restore the processor after a set_mtrr_prepare */ +/* Restore the processor after a set_mtrr_prepare */ static void set_mtrr_done (struct set_mtrr_context *ctxt) { - if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) { - __restore_flags (ctxt->flags); - return; - } - - /* Flush caches and TLBs */ - wbinvd(); - - /* Restore MTRRdefType */ - if ( mtrr_if == MTRR_IF_INTEL ) { - /* Intel (P6) standard MTRRs */ - wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); - } else { - /* Cyrix ARRs - everything else was excluded at the top */ - setCx86 (CX86_CCR3, ctxt->ccr3); - } - - /* Enable caches */ - write_cr0( read_cr0() & 0xbfffffff ); - - /* Restore value of CR4 */ - if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) ) - write_cr4(ctxt->cr4val); - - /* Re-enable interrupts locally (if enabled previously) */ - __restore_flags (ctxt->flags); -} /* End Function set_mtrr_done */ + /* Flush caches and TLBs */ + wbinvd(); + + /* Restore MTRRdefType */ + wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); + + /* Enable caches */ + write_cr0(read_cr0() & 0xbfffffff); + + /* Restore value of CR4 */ + if (test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability)) + write_cr4 (ctxt->cr4val); + + /* Re-enable interrupts locally (if enabled previously) */ + __restore_flags(ctxt->flags); +} + /* This function returns the number of variable MTRRs */ static unsigned int get_num_var_ranges (void) { - unsigned long config, dummy; + unsigned long config, dummy; - switch ( mtrr_if ) - { - case MTRR_IF_INTEL: rdmsr (MTRRcap_MSR, config, dummy); return (config & 0xff); - case MTRR_IF_AMD_K6: - return 2; - case MTRR_IF_CYRIX_ARR: - return 8; - case MTRR_IF_CENTAUR_MCR: - return 8; - default: - return 0; - } -} /* End Function get_num_var_ranges */ +} + /* Returns non-zero if we have the write-combining memory type */ static int have_wrcomb (void) { - unsigned long config, dummy; - struct pci_dev *dev = NULL; - - /* ServerWorks LE chipsets have problems with write-combining - Don't allow it and leave room for other chipsets to be tagged */ - - if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) { - switch(dev->vendor) { - case PCI_VENDOR_ID_SERVERWORKS: - switch (dev->device) { - case PCI_DEVICE_ID_SERVERWORKS_LE: - return 0; - break; - default: - break; - } - break; - default: - break; - } - } + unsigned long config, dummy; - - switch ( mtrr_if ) - { - case MTRR_IF_INTEL: rdmsr (MTRRcap_MSR, config, dummy); - return (config & (1<<10)); - return 1; - case MTRR_IF_AMD_K6: - case MTRR_IF_CENTAUR_MCR: - case MTRR_IF_CYRIX_ARR: - return 1; - default: - return 0; - } -} /* End Function have_wrcomb */ + return (config & (1 << 10)); +} + static u32 size_or_mask, size_and_mask; -static void intel_get_mtrr (unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type *type) +static void get_mtrr (unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type * type) { - unsigned long mask_lo, mask_hi, base_lo, base_hi; - - rdmsr (MTRRphysMask_MSR(reg), mask_lo, mask_hi); - if ( (mask_lo & 0x800) == 0 ) - { - /* Invalid (i.e. free) range */ - *base = 0; - *size = 0; - *type = 0; - return; - } - - rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi); - - /* Work out the shifted address mask. */ - mask_lo = size_or_mask | mask_hi << (32 - PAGE_SHIFT) - | mask_lo >> PAGE_SHIFT; - - /* This works correctly if size is a power of two, i.e. a - contiguous range. */ - *size = -mask_lo; - *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT; - *type = base_lo & 0xff; -} /* End Function intel_get_mtrr */ - -static void cyrix_get_arr (unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type *type) -{ - unsigned long flags; - unsigned char arr, ccr3, rcr, shift; - - arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */ - - /* Save flags and disable interrupts */ - __save_flags (flags); __cli (); - - ccr3 = getCx86 (CX86_CCR3); - setCx86 (CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ - ((unsigned char *) base)[3] = getCx86 (arr); - ((unsigned char *) base)[2] = getCx86 (arr+1); - ((unsigned char *) base)[1] = getCx86 (arr+2); - rcr = getCx86(CX86_RCR_BASE + reg); - setCx86 (CX86_CCR3, ccr3); /* disable MAPEN */ - - /* Enable interrupts if it was enabled previously */ - __restore_flags (flags); - shift = ((unsigned char *) base)[1] & 0x0f; - *base >>= PAGE_SHIFT; - - /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7 - * Note: shift==0xf means 4G, this is unsupported. - */ - if (shift) - *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1); - else - *size = 0; - - /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */ - if (reg < 7) - { - switch (rcr) - { - case 1: *type = MTRR_TYPE_UNCACHABLE; break; - case 8: *type = MTRR_TYPE_WRBACK; break; - case 9: *type = MTRR_TYPE_WRCOMB; break; - case 24: - default: *type = MTRR_TYPE_WRTHROUGH; break; - } - } else - { - switch (rcr) - { - case 0: *type = MTRR_TYPE_UNCACHABLE; break; - case 8: *type = MTRR_TYPE_WRCOMB; break; - case 9: *type = MTRR_TYPE_WRBACK; break; - case 25: - default: *type = MTRR_TYPE_WRTHROUGH; break; - } - } -} /* End Function cyrix_get_arr */ - -static void amd_get_mtrr (unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type *type) -{ - unsigned long low, high; - - rdmsr (0xC0000085, low, high); - /* Upper dword is region 1, lower is region 0 */ - if (reg == 1) low = high; - /* The base masks off on the right alignment */ - *base = (low & 0xFFFE0000) >> PAGE_SHIFT; - *type = 0; - if (low & 1) *type = MTRR_TYPE_UNCACHABLE; - if (low & 2) *type = MTRR_TYPE_WRCOMB; - if ( !(low & 3) ) - { - *size = 0; - return; - } - /* - * This needs a little explaining. The size is stored as an - * inverted mask of bits of 128K granularity 15 bits long offset - * 2 bits - * - * So to get a size we do invert the mask and add 1 to the lowest - * mask bit (4 as its 2 bits in). This gives us a size we then shift - * to turn into 128K blocks - * - * eg 111 1111 1111 1100 is 512K - * - * invert 000 0000 0000 0011 - * +1 000 0000 0000 0100 - * *128K ... - */ - low = (~low) & 0x1FFFC; - *size = (low + 4) << (15 - PAGE_SHIFT); - return; -} /* End Function amd_get_mtrr */ - -static struct -{ - unsigned long high; - unsigned long low; -} centaur_mcr[8]; - -static u8 centaur_mcr_reserved; -static u8 centaur_mcr_type; /* 0 for winchip, 1 for winchip2 */ + unsigned long mask_lo, mask_hi, base_lo, base_hi; -/* - * Report boot time MCR setups - */ - -void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) -{ - centaur_mcr[mcr].low = lo; - centaur_mcr[mcr].high = hi; + rdmsr (MTRRphysMask_MSR (reg), mask_lo, mask_hi); + if ((mask_lo & 0x800) == 0) { + /* Invalid (i.e. free) range */ + *base = 0; + *size = 0; + *type = 0; + return; + } + + rdmsr (MTRRphysBase_MSR (reg), base_lo, base_hi); + + /* Work out the shifted address mask. */ + mask_lo = size_or_mask | mask_hi << (32 - PAGE_SHIFT) + | mask_lo >> PAGE_SHIFT; + + /* This works correctly if size is a power of two, i.e. a + contiguous range. */ + *size = -mask_lo; + *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT; + *type = base_lo & 0xff; } -static void centaur_get_mcr (unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type *type) -{ - *base = centaur_mcr[reg].high >> PAGE_SHIFT; - *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT; - *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */ - if(centaur_mcr_type==1 && ((centaur_mcr[reg].low&31)&2)) - *type = MTRR_TYPE_UNCACHABLE; - if(centaur_mcr_type==1 && (centaur_mcr[reg].low&31)==25) - *type = MTRR_TYPE_WRBACK; - if(centaur_mcr_type==0 && (centaur_mcr[reg].low&31)==31) - *type = MTRR_TYPE_WRBACK; - -} /* End Function centaur_get_mcr */ -static void (*get_mtrr) (unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type *type); -static void intel_set_mtrr_up (unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type, int do_safe) +static void set_mtrr_up (unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type, int do_safe) /* [SUMMARY] Set variable MTRR register on the local CPU. The register to set. The base address of the region. @@ -691,301 +241,160 @@ [RETURNS] Nothing. */ { - struct set_mtrr_context ctxt; + struct set_mtrr_context ctxt; - if (do_safe) { - set_mtrr_prepare_save (&ctxt); - set_mtrr_cache_disable (&ctxt); - } - if (size == 0) - { - /* The invalid bit is kept in the mask, so we simply clear the - relevant mask register to disable a range. */ - wrmsr (MTRRphysMask_MSR (reg), 0, 0); - } - else - { - wrmsr (MTRRphysBase_MSR (reg), base << PAGE_SHIFT | type, - (base & size_and_mask) >> (32 - PAGE_SHIFT)); - wrmsr (MTRRphysMask_MSR (reg), -size << PAGE_SHIFT | 0x800, - (-size & size_and_mask) >> (32 - PAGE_SHIFT)); - } - if (do_safe) set_mtrr_done (&ctxt); -} /* End Function intel_set_mtrr_up */ - -static void cyrix_set_arr_up (unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type, int do_safe) -{ - struct set_mtrr_context ctxt; - unsigned char arr, arr_type, arr_size; - - arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */ - - /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */ - if (reg >= 7) - size >>= 6; - - size &= 0x7fff; /* make sure arr_size <= 14 */ - for(arr_size = 0; size; arr_size++, size >>= 1); - - if (reg<7) - { - switch (type) { - case MTRR_TYPE_UNCACHABLE: arr_type = 1; break; - case MTRR_TYPE_WRCOMB: arr_type = 9; break; - case MTRR_TYPE_WRTHROUGH: arr_type = 24; break; - default: arr_type = 8; break; - } - } - else - { - switch (type) - { - case MTRR_TYPE_UNCACHABLE: arr_type = 0; break; - case MTRR_TYPE_WRCOMB: arr_type = 8; break; - case MTRR_TYPE_WRTHROUGH: arr_type = 25; break; - default: arr_type = 9; break; - } - } - - if (do_safe) { - set_mtrr_prepare_save (&ctxt); - set_mtrr_cache_disable (&ctxt); - } - base <<= PAGE_SHIFT; - setCx86(arr, ((unsigned char *) &base)[3]); - setCx86(arr+1, ((unsigned char *) &base)[2]); - setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size); - setCx86(CX86_RCR_BASE + reg, arr_type); - if (do_safe) set_mtrr_done (&ctxt); -} /* End Function cyrix_set_arr_up */ + if (do_safe) + set_mtrr_prepare (&ctxt); -static void amd_set_mtrr_up (unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type, int do_safe) -/* [SUMMARY] Set variable MTRR register on the local CPU. - The register to set. - The base address of the region. - The size of the region. If this is 0 the region is disabled. - The type of the region. - If TRUE, do the change safely. If FALSE, safety measures should - be done externally. - [RETURNS] Nothing. -*/ -{ - u32 regs[2]; - struct set_mtrr_context ctxt; + if (size == 0) { + /* The invalid bit is kept in the mask, so we simply clear the + relevant mask register to disable a range. */ + wrmsr (MTRRphysMask_MSR (reg), 0, 0); + } else { + wrmsr (MTRRphysBase_MSR (reg), base << PAGE_SHIFT | type, + (base & size_and_mask) >> (32 - PAGE_SHIFT)); + wrmsr (MTRRphysMask_MSR (reg), -size << PAGE_SHIFT | 0x800, + (-size & size_and_mask) >> (32 - PAGE_SHIFT)); + } + if (do_safe) + set_mtrr_done (&ctxt); +} - if (do_safe) { - set_mtrr_prepare_save (&ctxt); - set_mtrr_cache_disable (&ctxt); - } - /* - * Low is MTRR0 , High MTRR 1 - */ - rdmsr (0xC0000085, regs[0], regs[1]); - /* - * Blank to disable - */ - if (size == 0) - regs[reg] = 0; - else - /* Set the register to the base, the type (off by one) and an - inverted bitmask of the size The size is the only odd - bit. We are fed say 512K We invert this and we get 111 1111 - 1111 1011 but if you subtract one and invert you get the - desired 111 1111 1111 1100 mask - - But ~(x - 1) == ~x + 1 == -x. Two's complement rocks! */ - regs[reg] = (-size>>(15-PAGE_SHIFT) & 0x0001FFFC) - | (base<base_lo, vr->base_hi); - rdmsr (MTRRphysMask_MSR (index), vr->mask_lo, vr->mask_hi); -} /* End Function get_mtrr_var_range */ + rdmsr (MTRRphysBase_MSR (index), vr->base_lo, vr->base_hi); + rdmsr (MTRRphysMask_MSR (index), vr->mask_lo, vr->mask_hi); +} /* Set the MSR pair relating to a var range. Returns TRUE if changes are made */ -static int __init set_mtrr_var_range_testing (unsigned int index, - struct mtrr_var_range *vr) +static int __init +set_mtrr_var_range_testing (unsigned int index, struct mtrr_var_range *vr) +{ + unsigned int lo, hi; + int changed = FALSE; + + rdmsr (MTRRphysBase_MSR (index), lo, hi); + if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) + || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) { + wrmsr (MTRRphysBase_MSR (index), vr->base_lo, vr->base_hi); + changed = TRUE; + } + + rdmsr (MTRRphysMask_MSR (index), lo, hi); + + if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL) + || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) { + wrmsr (MTRRphysMask_MSR (index), vr->mask_lo, vr->mask_hi); + changed = TRUE; + } + return changed; +} + + +static void __init get_fixed_ranges (mtrr_type * frs) +{ + unsigned long *p = (unsigned long *) frs; + int i; + + rdmsr (MTRRfix64K_00000_MSR, p[0], p[1]); + + for (i = 0; i < 2; i++) + rdmsr (MTRRfix16K_80000_MSR + i, p[2 + i * 2], p[3 + i * 2]); + for (i = 0; i < 8; i++) + rdmsr (MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]); +} + + +static int __init set_fixed_ranges_testing (mtrr_type * frs) { - unsigned int lo, hi; - int changed = FALSE; + unsigned long *p = (unsigned long *) frs; + int changed = FALSE; + int i; + unsigned long lo, hi; + + rdmsr (MTRRfix64K_00000_MSR, lo, hi); + if (p[0] != lo || p[1] != hi) { + wrmsr (MTRRfix64K_00000_MSR, p[0], p[1]); + changed = TRUE; + } + + for (i = 0; i < 2; i++) { + rdmsr (MTRRfix16K_80000_MSR + i, lo, hi); + if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) { + wrmsr (MTRRfix16K_80000_MSR + i, p[2 + i * 2], + p[3 + i * 2]); + changed = TRUE; + } + } + + for (i = 0; i < 8; i++) { + rdmsr (MTRRfix4K_C0000_MSR + i, lo, hi); + if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) { + wrmsr (MTRRfix4K_C0000_MSR + i, p[6 + i * 2], + p[7 + i * 2]); + changed = TRUE; + } + } + return changed; +} + - rdmsr(MTRRphysBase_MSR(index), lo, hi); - if ( (vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) - || (vr->base_hi & 0xfUL) != (hi & 0xfUL) ) - { - wrmsr (MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); - changed = TRUE; - } - - rdmsr (MTRRphysMask_MSR(index), lo, hi); - - if ( (vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL) - || (vr->mask_hi & 0xfUL) != (hi & 0xfUL) ) - { - wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); - changed = TRUE; - } - return changed; -} /* End Function set_mtrr_var_range_testing */ - -static void __init get_fixed_ranges(mtrr_type *frs) -{ - unsigned long *p = (unsigned long *)frs; - int i; - - rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]); - - for (i = 0; i < 2; i++) - rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]); - for (i = 0; i < 8; i++) - rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]); -} /* End Function get_fixed_ranges */ - -static int __init set_fixed_ranges_testing(mtrr_type *frs) -{ - unsigned long *p = (unsigned long *)frs; - int changed = FALSE; - int i; - unsigned long lo, hi; - - rdmsr(MTRRfix64K_00000_MSR, lo, hi); - if (p[0] != lo || p[1] != hi) - { - wrmsr (MTRRfix64K_00000_MSR, p[0], p[1]); - changed = TRUE; - } - - for (i = 0; i < 2; i++) - { - rdmsr (MTRRfix16K_80000_MSR + i, lo, hi); - if (p[2 + i*2] != lo || p[3 + i*2] != hi) - { - wrmsr (MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]); - changed = TRUE; - } - } - - for (i = 0; i < 8; i++) - { - rdmsr (MTRRfix4K_C0000_MSR + i, lo, hi); - if (p[6 + i*2] != lo || p[7 + i*2] != hi) - { - wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]); - changed = TRUE; - } - } - return changed; -} /* End Function set_fixed_ranges_testing */ - -struct mtrr_state -{ - unsigned int num_var_ranges; - struct mtrr_var_range *var_ranges; - mtrr_type fixed_ranges[NUM_FIXED_RANGES]; - unsigned char enabled; - mtrr_type def_type; +struct mtrr_state { + unsigned int num_var_ranges; + struct mtrr_var_range *var_ranges; + mtrr_type fixed_ranges[NUM_FIXED_RANGES]; + unsigned char enabled; + mtrr_type def_type; }; /* Grab all of the MTRR state for this CPU into *state */ -static void __init get_mtrr_state(struct mtrr_state *state) +static void __init get_mtrr_state (struct mtrr_state *state) { - unsigned int nvrs, i; - struct mtrr_var_range *vrs; - unsigned long lo, dummy; - - nvrs = state->num_var_ranges = get_num_var_ranges(); - vrs = state->var_ranges - = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL); - if (vrs == NULL) - nvrs = state->num_var_ranges = 0; - - for (i = 0; i < nvrs; i++) - get_mtrr_var_range (i, &vrs[i]); - get_fixed_ranges (state->fixed_ranges); - - rdmsr (MTRRdefType_MSR, lo, dummy); - state->def_type = (lo & 0xff); - state->enabled = (lo & 0xc00) >> 10; -} /* End Function get_mtrr_state */ + unsigned int nvrs, i; + struct mtrr_var_range *vrs; + unsigned long lo, dummy; + + nvrs = state->num_var_ranges = get_num_var_ranges (); + vrs = state->var_ranges + = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL); + if (vrs == NULL) + nvrs = state->num_var_ranges = 0; + + for (i = 0; i < nvrs; i++) + get_mtrr_var_range (i, &vrs[i]); + get_fixed_ranges (state->fixed_ranges); + + rdmsr (MTRRdefType_MSR, lo, dummy); + state->def_type = (lo & 0xff); + state->enabled = (lo & 0xc00) >> 10; +} /* Free resources associated with a struct mtrr_state */ -static void __init finalize_mtrr_state(struct mtrr_state *state) +static void __init finalize_mtrr_state (struct mtrr_state *state) { - if (state->var_ranges) kfree (state->var_ranges); -} /* End Function finalize_mtrr_state */ + if (state->var_ranges) + kfree (state->var_ranges); +} static unsigned long __init set_mtrr_state (struct mtrr_state *state, - struct set_mtrr_context *ctxt) + struct set_mtrr_context *ctxt) /* [SUMMARY] Set the MTRR state for this CPU. The MTRR state information to read. Some relevant CPU context. @@ -993,39 +402,36 @@ [RETURNS] 0 if no changes made, else a mask indication what was changed. */ { - unsigned int i; - unsigned long change_mask = 0; + unsigned int i; + unsigned long change_mask = 0; - for (i = 0; i < state->num_var_ranges; i++) - if ( set_mtrr_var_range_testing (i, &state->var_ranges[i]) ) - change_mask |= MTRR_CHANGE_MASK_VARIABLE; - - if ( set_fixed_ranges_testing(state->fixed_ranges) ) - change_mask |= MTRR_CHANGE_MASK_FIXED; - /* Set_mtrr_restore restores the old value of MTRRdefType, - so to set it we fiddle with the saved value */ - if ( (ctxt->deftype_lo & 0xff) != state->def_type - || ( (ctxt->deftype_lo & 0xc00) >> 10 ) != state->enabled) - { - ctxt->deftype_lo |= (state->def_type | state->enabled << 10); - change_mask |= MTRR_CHANGE_MASK_DEFTYPE; - } + for (i = 0; i < state->num_var_ranges; i++) + if (set_mtrr_var_range_testing (i, &state->var_ranges[i])) + change_mask |= MTRR_CHANGE_MASK_VARIABLE; + + if (set_fixed_ranges_testing (state->fixed_ranges)) + change_mask |= MTRR_CHANGE_MASK_FIXED; + /* Set_mtrr_restore restores the old value of MTRRdefType, + so to set it we fiddle with the saved value */ + if ((ctxt->deftype_lo & 0xff) != state->def_type + || ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled) { + ctxt->deftype_lo |= (state->def_type | state->enabled << 10); + change_mask |= MTRR_CHANGE_MASK_DEFTYPE; + } - return change_mask; -} /* End Function set_mtrr_state */ + return change_mask; +} static atomic_t undone_count; -static volatile int wait_barrier_cache_disable = FALSE; static volatile int wait_barrier_execute = FALSE; static volatile int wait_barrier_cache_enable = FALSE; -struct set_mtrr_data -{ - unsigned long smp_base; - unsigned long smp_size; - unsigned int smp_reg; - mtrr_type smp_type; +struct set_mtrr_data { + unsigned long smp_base; + unsigned long smp_size; + unsigned int smp_reg; + mtrr_type smp_type; }; static void ipi_handler (void *info) @@ -1033,188 +439,142 @@ [RETURNS] Nothing. */ { - struct set_mtrr_data *data = info; - struct set_mtrr_context ctxt; - set_mtrr_prepare_save (&ctxt); - /* Notify master that I've flushed and disabled my cache */ - atomic_dec (&undone_count); - while (wait_barrier_cache_disable) { rep_nop(); barrier(); } - set_mtrr_cache_disable (&ctxt); - /* Notify master that I've flushed and disabled my cache */ - atomic_dec (&undone_count); - while (wait_barrier_execute) { rep_nop(); barrier(); } - /* The master has cleared me to execute */ - (*set_mtrr_up) (data->smp_reg, data->smp_base, data->smp_size, - data->smp_type, FALSE); - /* Notify master CPU that I've executed the function */ - atomic_dec (&undone_count); - /* Wait for master to clear me to enable cache and return */ - while (wait_barrier_cache_enable) { rep_nop(); barrier(); } - set_mtrr_done (&ctxt); -} /* End Function ipi_handler */ + struct set_mtrr_data *data = info; + struct set_mtrr_context ctxt; + + set_mtrr_prepare (&ctxt); + /* Notify master that I've flushed and disabled my cache */ + atomic_dec (&undone_count); + while (wait_barrier_execute) + barrier (); + + /* The master has cleared me to execute */ + (*set_mtrr_up) (data->smp_reg, data->smp_base, data->smp_size, + data->smp_type, FALSE); + + /* Notify master CPU that I've executed the function */ + atomic_dec (&undone_count); + + /* Wait for master to clear me to enable cache and return */ + while (wait_barrier_cache_enable) + barrier (); + set_mtrr_done (&ctxt); +} + static void set_mtrr_smp (unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type) + unsigned long size, mtrr_type type) { - struct set_mtrr_data data; - struct set_mtrr_context ctxt; + struct set_mtrr_data data; + struct set_mtrr_context ctxt; - data.smp_reg = reg; - data.smp_base = base; - data.smp_size = size; - data.smp_type = type; - wait_barrier_cache_disable = TRUE; - wait_barrier_execute = TRUE; - wait_barrier_cache_enable = TRUE; - atomic_set (&undone_count, smp_num_cpus - 1); - /* Start the ball rolling on other CPUs */ - if (smp_call_function (ipi_handler, &data, 1, 0) != 0) - panic ("mtrr: timed out waiting for other CPUs\n"); - /* Flush and disable the local CPU's cache */ - set_mtrr_prepare_save (&ctxt); - /* Wait for all other CPUs to flush and disable their caches */ - while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); } - /* Set up for completion wait and then release other CPUs to change MTRRs*/ - atomic_set (&undone_count, smp_num_cpus - 1); - wait_barrier_cache_disable = FALSE; - set_mtrr_cache_disable (&ctxt); - - /* Wait for all other CPUs to flush and disable their caches */ - while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); } - /* Set up for completion wait and then release other CPUs to change MTRRs*/ - atomic_set (&undone_count, smp_num_cpus - 1); - wait_barrier_execute = FALSE; - (*set_mtrr_up) (reg, base, size, type, FALSE); - /* Now wait for other CPUs to complete the function */ - while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); } - /* Now all CPUs should have finished the function. Release the barrier to - allow them to re-enable their caches and return from their interrupt, - then enable the local cache and return */ - wait_barrier_cache_enable = FALSE; - set_mtrr_done (&ctxt); -} /* End Function set_mtrr_smp */ + data.smp_reg = reg; + data.smp_base = base; + data.smp_size = size; + data.smp_type = type; + wait_barrier_execute = TRUE; + wait_barrier_cache_enable = TRUE; + atomic_set (&undone_count, smp_num_cpus - 1); + + /* Start the ball rolling on other CPUs */ + if (smp_call_function (ipi_handler, &data, 1, 0) != 0) + panic ("mtrr: timed out waiting for other CPUs\n"); + + /* Flush and disable the local CPU's cache */ + set_mtrr_prepare (&ctxt); + + /* Wait for all other CPUs to flush and disable their caches */ + while (atomic_read (&undone_count) > 0) + barrier (); + + /* Set up for completion wait and then release other CPUs to change MTRRs */ + atomic_set (&undone_count, smp_num_cpus - 1); + wait_barrier_execute = FALSE; + (*set_mtrr_up) (reg, base, size, type, FALSE); + + /* Now wait for other CPUs to complete the function */ + while (atomic_read (&undone_count) > 0) + barrier (); + + /* Now all CPUs should have finished the function. Release the barrier to + allow them to re-enable their caches and return from their interrupt, + then enable the local cache and return */ + wait_barrier_cache_enable = FALSE; + set_mtrr_done (&ctxt); +} /* Some BIOS's are fucked and don't set all MTRRs the same! */ -static void __init mtrr_state_warn(unsigned long mask) +static void __init mtrr_state_warn (unsigned long mask) +{ + if (!mask) + return; + if (mask & MTRR_CHANGE_MASK_FIXED) + printk ("mtrr: your CPUs had inconsistent fixed MTRR settings\n"); + if (mask & MTRR_CHANGE_MASK_VARIABLE) + printk ("mtrr: your CPUs had inconsistent variable MTRR settings\n"); + if (mask & MTRR_CHANGE_MASK_DEFTYPE) + printk ("mtrr: your CPUs had inconsistent MTRRdefType settings\n"); + printk ("mtrr: probably your BIOS does not setup all CPUs\n"); +} + +#endif /* CONFIG_SMP */ + + +static char inline * attrib_to_str (int x) +{ + return (x <= 6) ? mtrr_strings[x] : "?"; +} + + +static void __init init_table (void) { - if (!mask) return; - if (mask & MTRR_CHANGE_MASK_FIXED) - printk ("mtrr: your CPUs had inconsistent fixed MTRR settings\n"); - if (mask & MTRR_CHANGE_MASK_VARIABLE) - printk ("mtrr: your CPUs had inconsistent variable MTRR settings\n"); - if (mask & MTRR_CHANGE_MASK_DEFTYPE) - printk ("mtrr: your CPUs had inconsistent MTRRdefType settings\n"); - printk ("mtrr: probably your BIOS does not setup all CPUs\n"); -} /* End Function mtrr_state_warn */ - -#endif /* CONFIG_SMP */ - -static char *attrib_to_str (int x) -{ - return (x <= 6) ? mtrr_strings[x] : "?"; -} /* End Function attrib_to_str */ - -static void init_table (void) -{ - int i, max; - - max = get_num_var_ranges (); - if ( ( usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL) ) - == NULL ) - { - printk ("mtrr: could not allocate\n"); - return; - } - for (i = 0; i < max; i++) usage_table[i] = 1; + int i, max; + + max = get_num_var_ranges (); + if ((usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL))==NULL) { + printk ("mtrr: could not allocate\n"); + return; + } + + for (i = 0; i < max; i++) + usage_table[i] = 1; + #ifdef USERSPACE_INTERFACE - if ( ( ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL) ) == NULL ) - { - printk ("mtrr: could not allocate\n"); - return; - } - ascii_buf_bytes = 0; - compute_ascii (); + if ((ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL)) == NULL) { + printk ("mtrr: could not allocate\n"); + return; + } + ascii_buf_bytes = 0; + compute_ascii (); #endif -} /* End Function init_table */ +} -static int generic_get_free_region (unsigned long base, unsigned long size) -/* [SUMMARY] Get a free MTRR. - The starting (base) address of the region. - The size (in bytes) of the region. - [RETURNS] The index of the region on success, else -1 on error. -*/ -{ - int i, max; - mtrr_type ltype; - unsigned long lbase, lsize; - - max = get_num_var_ranges (); - for (i = 0; i < max; ++i) - { - (*get_mtrr) (i, &lbase, &lsize, <ype); - if (lsize == 0) return i; - } - return -ENOSPC; -} /* End Function generic_get_free_region */ -static int centaur_get_free_region (unsigned long base, unsigned long size) +static int generic_get_free_region (unsigned long base, + unsigned long size) /* [SUMMARY] Get a free MTRR. The starting (base) address of the region. The size (in bytes) of the region. [RETURNS] The index of the region on success, else -1 on error. */ { - int i, max; - mtrr_type ltype; - unsigned long lbase, lsize; - - max = get_num_var_ranges (); - for (i = 0; i < max; ++i) - { - if(centaur_mcr_reserved & (1< The starting (base) address of the region. - The size (in bytes) of the region. - [RETURNS] The index of the region on success, else -1 on error. -*/ -{ - int i; - mtrr_type ltype; - unsigned long lbase, lsize; - - /* If we are to set up a region >32M then look at ARR7 immediately */ - if (size > 0x2000) - { - cyrix_get_arr (7, &lbase, &lsize, <ype); - if (lsize == 0) return 7; - /* Else try ARR0-ARR6 first */ - } - else - { - for (i = 0; i < 7; i++) - { - cyrix_get_arr (i, &lbase, &lsize, <ype); - if ((i == 3) && arr3_protected) continue; - if (lsize == 0) return i; - } - /* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */ - cyrix_get_arr (i, &lbase, &lsize, <ype); - if ((lsize == 0) && (size >= 0x40)) return i; - } - return -ENOSPC; -} /* End Function cyrix_get_free_region */ static int (*get_free_region) (unsigned long base, - unsigned long size) = generic_get_free_region; + unsigned long size) = generic_get_free_region; /** * mtrr_add_page - Add a memory type region @@ -1252,7 +612,8 @@ * failures and do not wish system log messages to be sent. */ -int mtrr_add_page(unsigned long base, unsigned long size, unsigned int type, char increment) +int mtrr_add_page (unsigned long base, unsigned long size, + unsigned int type, char increment) { /* [SUMMARY] Add an MTRR entry. The starting (base, in pages) address of the region. @@ -1264,152 +625,98 @@ the error code. [NOTE] This routine uses a spinlock. */ - int i, max; - mtrr_type ltype; - unsigned long lbase, lsize, last; - - switch ( mtrr_if ) - { - case MTRR_IF_NONE: - return -ENXIO; /* No MTRRs whatsoever */ - - case MTRR_IF_AMD_K6: - /* Apply the K6 block alignment and size rules - In order - o Uncached or gathering only - o 128K or bigger block - o Power of 2 block - o base suitably aligned to the power - */ - if ( type > MTRR_TYPE_WRCOMB || size < (1 << (17-PAGE_SHIFT)) || - (size & ~(size-1))-size || ( base & (size-1) ) ) - return -EINVAL; - break; - - case MTRR_IF_INTEL: - /* For Intel PPro stepping <= 7, must be 4 MiB aligned - and not touch 0x70000000->0x7003FFFF */ - if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && - boot_cpu_data.x86 == 6 && - boot_cpu_data.x86_model == 1 && - boot_cpu_data.x86_mask <= 7 ) - { - if ( base & ((1 << (22-PAGE_SHIFT))-1) ) - { - printk (KERN_WARNING "mtrr: base(0x%lx000) is not 4 MiB aligned\n", base); + int i, max; + mtrr_type ltype; + unsigned long lbase, lsize, last; + + if (base + size < 0x100) { + printk (KERN_WARNING + "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n", + base, size); return -EINVAL; - } - if (!(base + size < 0x70000000 || base > 0x7003FFFF) && - (type == MTRR_TYPE_WRCOMB || type == MTRR_TYPE_WRBACK)) - { - printk (KERN_WARNING "mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n"); - return -EINVAL; - } - } - /* Fall through */ - - case MTRR_IF_CYRIX_ARR: - case MTRR_IF_CENTAUR_MCR: - if ( mtrr_if == MTRR_IF_CENTAUR_MCR ) - { - /* - * FIXME: Winchip2 supports uncached - */ - if (type != MTRR_TYPE_WRCOMB && (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) - { - printk (KERN_WARNING "mtrr: only write-combining%s supported\n", - centaur_mcr_type?" and uncacheable are":" is"); - return -EINVAL; - } - } - else if (base + size < 0x100) - { - printk (KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n", - base, size); - return -EINVAL; } + /* Check upper bits of base and last are equal and lower bits are 0 - for base and 1 for last */ + for base and 1 for last */ last = base + size - 1; for (lbase = base; !(lbase & 1) && (last & 1); - lbase = lbase >> 1, last = last >> 1); - if (lbase != last) - { - printk (KERN_WARNING "mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n", - base, size); - return -EINVAL; + lbase = lbase >> 1, last = last >> 1) ; + + if (lbase != last) { + printk (KERN_WARNING + "mtrr: base(0x%lx000) is not aligned on a size(0x%lx000) boundary\n", + base, size); + return -EINVAL; } - break; - default: - return -EINVAL; - } + if (type >= MTRR_NUM_TYPES) { + printk ("mtrr: type: %u illegal\n", type); + return -EINVAL; + } - if (type >= MTRR_NUM_TYPES) - { - printk ("mtrr: type: %u illegal\n", type); - return -EINVAL; - } + /* If the type is WC, check that this processor supports it */ + if ((type == MTRR_TYPE_WRCOMB) && !have_wrcomb ()) { + printk (KERN_WARNING + "mtrr: your processor doesn't support write-combining\n"); + return -ENOSYS; + } - /* If the type is WC, check that this processor supports it */ - if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () ) - { - printk (KERN_WARNING "mtrr: your processor doesn't support write-combining\n"); - return -ENOSYS; - } - - if ( base & size_or_mask || size & size_or_mask ) - { - printk ("mtrr: base or size exceeds the MTRR width\n"); - return -EINVAL; - } + if (base & size_or_mask || size & size_or_mask) { + printk ("mtrr: base or size exceeds the MTRR width\n"); + return -EINVAL; + } - increment = increment ? 1 : 0; - max = get_num_var_ranges (); - /* Search for existing MTRR */ - down(&main_lock); - for (i = 0; i < max; ++i) - { - (*get_mtrr) (i, &lbase, &lsize, <ype); - if (base >= lbase + lsize) continue; - if ( (base < lbase) && (base + size <= lbase) ) continue; - /* At this point we know there is some kind of overlap/enclosure */ - if ( (base < lbase) || (base + size > lbase + lsize) ) - { - up(&main_lock); - printk (KERN_WARNING "mtrr: 0x%lx000,0x%lx000 overlaps existing" - " 0x%lx000,0x%lx000\n", - base, size, lbase, lsize); - return -EINVAL; - } - /* New region is enclosed by an existing region */ - if (ltype != type) - { - if (type == MTRR_TYPE_UNCACHABLE) continue; - up(&main_lock); - printk ( "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", - base, size, attrib_to_str (ltype), attrib_to_str (type) ); - return -EINVAL; + increment = increment ? 1 : 0; + max = get_num_var_ranges (); + /* Search for existing MTRR */ + down (&main_lock); + for (i = 0; i < max; ++i) { + (*get_mtrr) (i, &lbase, &lsize, <ype); + if (base >= lbase + lsize) + continue; + if ((base < lbase) && (base + size <= lbase)) + continue; + + /* At this point we know there is some kind of overlap/enclosure */ + if ((base < lbase) || (base + size > lbase + lsize)) { + up (&main_lock); + printk (KERN_WARNING + "mtrr: 0x%lx000,0x%lx000 overlaps existing" + " 0x%lx000,0x%lx000\n", base, size, lbase, + lsize); + return -EINVAL; + } + /* New region is enclosed by an existing region */ + if (ltype != type) { + if (type == MTRR_TYPE_UNCACHABLE) + continue; + up (&main_lock); + printk + ("mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", + base, size, attrib_to_str (ltype), + attrib_to_str (type)); + return -EINVAL; + } + if (increment) + ++usage_table[i]; + compute_ascii (); + up (&main_lock); + return i; + } + /* Search for an empty MTRR */ + i = (*get_free_region) (base, size); + if (i < 0) { + up (&main_lock); + printk ("mtrr: no more MTRRs available\n"); + return i; } - if (increment) ++usage_table[i]; + set_mtrr (i, base, size, type); + usage_table[i] = 1; compute_ascii (); - up(&main_lock); - return i; - } - /* Search for an empty MTRR */ - i = (*get_free_region) (base, size); - if (i < 0) - { - up(&main_lock); - printk ("mtrr: no more MTRRs available\n"); + up (&main_lock); return i; - } - set_mtrr (i, base, size, type); - usage_table[i] = 1; - compute_ascii (); - up(&main_lock); - return i; -} /* End Function mtrr_add_page */ +} + /** * mtrr_add - Add a memory type region @@ -1447,7 +754,8 @@ * failures and do not wish system log messages to be sent. */ -int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char increment) +int mtrr_add (unsigned long base, unsigned long size, unsigned int type, + char increment) { /* [SUMMARY] Add an MTRR entry. The starting (base) address of the region. @@ -1459,14 +767,15 @@ the error code. */ - if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) ) - { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); - return -EINVAL; - } - return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment); -} /* End Function mtrr_add */ + if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { + printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } + return mtrr_add_page (base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, + increment); +} + /** * mtrr_del_page - delete a memory type region @@ -1482,7 +791,7 @@ * On success the register is returned, on failure a negative error * code. */ - + int mtrr_del_page (int reg, unsigned long base, unsigned long size) /* [SUMMARY] Delete MTRR/decrement usage count. The register. If this is less than 0 then <> and <> must @@ -1494,66 +803,55 @@ [NOTE] This routine uses a spinlock. */ { - int i, max; - mtrr_type ltype; - unsigned long lbase, lsize; - - if ( mtrr_if == MTRR_IF_NONE ) return -ENXIO; - - max = get_num_var_ranges (); - down (&main_lock); - if (reg < 0) - { - /* Search for existing MTRR */ - for (i = 0; i < max; ++i) - { - (*get_mtrr) (i, &lbase, &lsize, <ype); - if (lbase == base && lsize == size) - { - reg = i; - break; - } + int i, max; + mtrr_type ltype; + unsigned long lbase, lsize; + + max = get_num_var_ranges (); + down (&main_lock); + if (reg < 0) { + /* Search for existing MTRR */ + for (i = 0; i < max; ++i) { + (*get_mtrr) (i, &lbase, &lsize, <ype); + if (lbase == base && lsize == size) { + reg = i; + break; + } + } + if (reg < 0) { + up (&main_lock); + printk ("mtrr: no MTRR for %lx000,%lx000 found\n", base, + size); + return -EINVAL; + } } - if (reg < 0) - { - up(&main_lock); - printk ("mtrr: no MTRR for %lx000,%lx000 found\n", base, size); - return -EINVAL; - } - } - if (reg >= max) - { - up (&main_lock); - printk ("mtrr: register: %d too big\n", reg); - return -EINVAL; - } - if ( mtrr_if == MTRR_IF_CYRIX_ARR ) - { - if ( (reg == 3) && arr3_protected ) - { - up (&main_lock); - printk ("mtrr: ARR3 cannot be changed\n"); - return -EINVAL; - } - } - (*get_mtrr) (reg, &lbase, &lsize, <ype); - if (lsize < 1) - { - up (&main_lock); - printk ("mtrr: MTRR %d not used\n", reg); - return -EINVAL; - } - if (usage_table[reg] < 1) - { + + if (reg >= max) { + up (&main_lock); + printk ("mtrr: register: %d too big\n", reg); + return -EINVAL; + } + (*get_mtrr) (reg, &lbase, &lsize, <ype); + + if (lsize < 1) { + up (&main_lock); + printk ("mtrr: MTRR %d not used\n", reg); + return -EINVAL; + } + + if (usage_table[reg] < 1) { + up (&main_lock); + printk ("mtrr: reg: %d has count=0\n", reg); + return -EINVAL; + } + + if (--usage_table[reg] < 1) + set_mtrr (reg, 0, 0, 0); + compute_ascii (); up (&main_lock); - printk ("mtrr: reg: %d has count=0\n", reg); - return -EINVAL; - } - if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0); - compute_ascii (); - up (&main_lock); - return reg; -} /* End Function mtrr_del_page */ + return reg; +} + /** * mtrr_del - delete a memory type region @@ -1569,7 +867,7 @@ * On success the register is returned, on failure a negative error * code. */ - + int mtrr_del (int reg, unsigned long base, unsigned long size) /* [SUMMARY] Delete MTRR/decrement usage count. The register. If this is less than 0 then <> and <> must @@ -1580,731 +878,479 @@ the error code. */ { - if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) ) - { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); - return -EINVAL; - } - return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); + if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { + printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } + return mtrr_del_page (reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); } + #ifdef USERSPACE_INTERFACE static int mtrr_file_add (unsigned long base, unsigned long size, - unsigned int type, char increment, struct file *file, int page) + unsigned int type, char increment, struct file *file, int page) { - int reg, max; - unsigned int *fcount = file->private_data; + int reg, max; + unsigned int *fcount = file->private_data; + + max = get_num_var_ranges (); + if (fcount == NULL) { + if ((fcount = + kmalloc (max * sizeof *fcount, GFP_KERNEL)) == NULL) { + printk ("mtrr: could not allocate\n"); + return -ENOMEM; + } + memset (fcount, 0, max * sizeof *fcount); + file->private_data = fcount; + } + + if (!page) { + if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { + printk + ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; + } + + reg = mtrr_add_page (base, size, type, 1); + + if (reg >= 0) + ++fcount[reg]; + return reg; +} - max = get_num_var_ranges (); - if (fcount == NULL) - { - if ( ( fcount = kmalloc (max * sizeof *fcount, GFP_KERNEL) ) == NULL ) - { - printk ("mtrr: could not allocate\n"); - return -ENOMEM; - } - memset (fcount, 0, max * sizeof *fcount); - file->private_data = fcount; - } - if (!page) { - if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) ) - { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); - return -EINVAL; - } - base >>= PAGE_SHIFT; - size >>= PAGE_SHIFT; - } - reg = mtrr_add_page (base, size, type, 1); - if (reg >= 0) ++fcount[reg]; - return reg; -} /* End Function mtrr_file_add */ static int mtrr_file_del (unsigned long base, unsigned long size, - struct file *file, int page) + struct file *file, int page) { - int reg; - unsigned int *fcount = file->private_data; + int reg; + unsigned int *fcount = file->private_data; + + if (!page) { + if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { + printk + ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); + return -EINVAL; + } + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; + } + reg = mtrr_del_page (-1, base, size); + if (reg < 0) + return reg; + if (fcount == NULL) + return reg; + if (fcount[reg] < 1) + return -EINVAL; + --fcount[reg]; + return reg; +} - if (!page) { - if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) ) - { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); - return -EINVAL; - } - base >>= PAGE_SHIFT; - size >>= PAGE_SHIFT; - } - reg = mtrr_del_page (-1, base, size); - if (reg < 0) return reg; - if (fcount == NULL) return reg; - if (fcount[reg] < 1) return -EINVAL; - --fcount[reg]; - return reg; -} /* End Function mtrr_file_del */ static ssize_t mtrr_read (struct file *file, char *buf, size_t len, - loff_t *ppos) + loff_t * ppos) { - if (*ppos >= ascii_buf_bytes) return 0; - if (*ppos + len > ascii_buf_bytes) len = ascii_buf_bytes - *ppos; - if ( copy_to_user (buf, ascii_buffer + *ppos, len) ) return -EFAULT; - *ppos += len; - return len; -} /* End Function mtrr_read */ + if (*ppos >= ascii_buf_bytes) + return 0; + + if (*ppos + len > ascii_buf_bytes) + len = ascii_buf_bytes - *ppos; + + if (copy_to_user (buf, ascii_buffer + *ppos, len)) + return -EFAULT; + + *ppos += len; + return len; +} -static ssize_t mtrr_write (struct file *file, const char *buf, size_t len, - loff_t *ppos) + +static ssize_t mtrr_write (struct file *file, const char *buf, + size_t len, loff_t * ppos) /* Format of control line: "base=%Lx size=%Lx type=%s" OR: "disable=%d" */ { - int i, err; - unsigned long reg; - unsigned long long base, size; - char *ptr; - char line[LINE_SIZE]; - - if ( !suser () ) return -EPERM; - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) return -ESPIPE; - memset (line, 0, LINE_SIZE); - if (len > LINE_SIZE) len = LINE_SIZE; - if ( copy_from_user (line, buf, len - 1) ) return -EFAULT; - ptr = line + strlen (line) - 1; - if (*ptr == '\n') *ptr = '\0'; - if ( !strncmp (line, "disable=", 8) ) - { - reg = simple_strtoul (line + 8, &ptr, 0); - err = mtrr_del_page (reg, 0, 0); - if (err < 0) return err; - return len; - } - if ( strncmp (line, "base=", 5) ) - { - printk ("mtrr: no \"base=\" in line: \"%s\"\n", line); - return -EINVAL; - } - base = simple_strtoull (line + 5, &ptr, 0); - for (; isspace (*ptr); ++ptr); - if ( strncmp (ptr, "size=", 5) ) - { - printk ("mtrr: no \"size=\" in line: \"%s\"\n", line); - return -EINVAL; - } - size = simple_strtoull (ptr + 5, &ptr, 0); - if ( (base & 0xfff) || (size & 0xfff) ) - { - printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%Lx base: 0x%Lx\n", size, base); - return -EINVAL; - } - for (; isspace (*ptr); ++ptr); - if ( strncmp (ptr, "type=", 5) ) - { - printk ("mtrr: no \"type=\" in line: \"%s\"\n", line); + int i, err; + unsigned long reg; + unsigned long long base, size; + char *ptr; + char line[LINE_SIZE]; + + if (!suser ()) + return -EPERM; + + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + memset (line, 0, LINE_SIZE); + + if (len > LINE_SIZE) + len = LINE_SIZE; + + if (copy_from_user (line, buf, len - 1)) + return -EFAULT; + ptr = line + strlen (line) - 1; + + if (*ptr == '\n') + *ptr = '\0'; + + if (!strncmp (line, "disable=", 8)) { + reg = simple_strtoul (line + 8, &ptr, 0); + err = mtrr_del_page (reg, 0, 0); + if (err < 0) + return err; + return len; + } + + if (strncmp (line, "base=", 5)) { + printk ("mtrr: no \"base=\" in line: \"%s\"\n", line); + return -EINVAL; + } + + base = simple_strtoull (line + 5, &ptr, 0); + + for (; isspace (*ptr); ++ptr) ; + + if (strncmp (ptr, "size=", 5)) { + printk ("mtrr: no \"size=\" in line: \"%s\"\n", line); + return -EINVAL; + } + + size = simple_strtoull (ptr + 5, &ptr, 0); + + if ((base & 0xfff) || (size & 0xfff)) { + printk ("mtrr: size and base must be multiples of 4 kiB\n"); + printk ("mtrr: size: 0x%Lx base: 0x%Lx\n", size, base); + return -EINVAL; + } + + for (; isspace (*ptr); ++ptr) ; + + if (strncmp (ptr, "type=", 5)) { + printk ("mtrr: no \"type=\" in line: \"%s\"\n", line); + return -EINVAL; + } + ptr += 5; + + for (; isspace (*ptr); ++ptr) ; + + for (i = 0; i < MTRR_NUM_TYPES; ++i) { + if (strcmp (ptr, mtrr_strings[i])) + continue; + base >>= PAGE_SHIFT; + size >>= PAGE_SHIFT; + err = + mtrr_add_page ((unsigned long) base, (unsigned long) size, + i, 1); + if (err < 0) + return err; + return len; + } + printk ("mtrr: illegal type: \"%s\"\n", ptr); return -EINVAL; - } - ptr += 5; - for (; isspace (*ptr); ++ptr); - for (i = 0; i < MTRR_NUM_TYPES; ++i) - { - if ( strcmp (ptr, mtrr_strings[i]) ) continue; - base >>= PAGE_SHIFT; - size >>= PAGE_SHIFT; - err = mtrr_add_page ((unsigned long)base, (unsigned long)size, i, 1); - if (err < 0) return err; - return len; - } - printk ("mtrr: illegal type: \"%s\"\n", ptr); - return -EINVAL; -} /* End Function mtrr_write */ +} + static int mtrr_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - int err; - mtrr_type type; - struct mtrr_sentry sentry; - struct mtrr_gentry gentry; - - switch (cmd) - { - default: - return -ENOIOCTLCMD; - case MTRRIOC_ADD_ENTRY: - if ( !suser () ) return -EPERM; - if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) - return -EFAULT; - err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 0); - if (err < 0) return err; - break; - case MTRRIOC_SET_ENTRY: - if ( !suser () ) return -EPERM; - if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) - return -EFAULT; - err = mtrr_add (sentry.base, sentry.size, sentry.type, 0); - if (err < 0) return err; - break; - case MTRRIOC_DEL_ENTRY: - if ( !suser () ) return -EPERM; - if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) - return -EFAULT; - err = mtrr_file_del (sentry.base, sentry.size, file, 0); - if (err < 0) return err; - break; - case MTRRIOC_KILL_ENTRY: - if ( !suser () ) return -EPERM; - if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) - return -EFAULT; - err = mtrr_del (-1, sentry.base, sentry.size); - if (err < 0) return err; - break; - case MTRRIOC_GET_ENTRY: - if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) ) - return -EFAULT; - if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL; - (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type); - - /* Hide entries that go above 4GB */ - if (gentry.base + gentry.size > 0x100000 || gentry.size == 0x100000) - gentry.base = gentry.size = gentry.type = 0; - else { - gentry.base <<= PAGE_SHIFT; - gentry.size <<= PAGE_SHIFT; - gentry.type = type; - } - - if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) ) - return -EFAULT; - break; - case MTRRIOC_ADD_PAGE_ENTRY: - if ( !suser () ) return -EPERM; - if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) - return -EFAULT; - err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 1); - if (err < 0) return err; - break; - case MTRRIOC_SET_PAGE_ENTRY: - if ( !suser () ) return -EPERM; - if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) - return -EFAULT; - err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0); - if (err < 0) return err; - break; - case MTRRIOC_DEL_PAGE_ENTRY: - if ( !suser () ) return -EPERM; - if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) - return -EFAULT; - err = mtrr_file_del (sentry.base, sentry.size, file, 1); - if (err < 0) return err; - break; - case MTRRIOC_KILL_PAGE_ENTRY: - if ( !suser () ) return -EPERM; - if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) - return -EFAULT; - err = mtrr_del_page (-1, sentry.base, sentry.size); - if (err < 0) return err; - break; - case MTRRIOC_GET_PAGE_ENTRY: - if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) ) - return -EFAULT; - if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL; - (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type); - gentry.type = type; - - if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) ) - return -EFAULT; - break; - } - return 0; -} /* End Function mtrr_ioctl */ + int err; + mtrr_type type; + struct mtrr_sentry sentry; + struct mtrr_gentry gentry; -static int mtrr_close (struct inode *ino, struct file *file) -{ - int i, max; - unsigned int *fcount = file->private_data; + switch (cmd) { + default: + return -ENOIOCTLCMD; - if (fcount == NULL) return 0; - max = get_num_var_ranges (); - for (i = 0; i < max; ++i) - { - while (fcount[i] > 0) - { - if (mtrr_del (i, 0, 0) < 0) printk ("mtrr: reg %d not used\n", i); - --fcount[i]; - } - } - kfree (fcount); - file->private_data = NULL; - return 0; -} /* End Function mtrr_close */ - -static struct file_operations mtrr_fops = -{ - owner: THIS_MODULE, - read: mtrr_read, - write: mtrr_write, - ioctl: mtrr_ioctl, - release: mtrr_close, -}; + case MTRRIOC_ADD_ENTRY: + if (!suser ()) + return -EPERM; + if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) + return -EFAULT; + err = + mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, + file, 0); + if (err < 0) + return err; + break; -# ifdef CONFIG_PROC_FS + case MTRRIOC_SET_ENTRY: + if (!suser ()) + return -EPERM; + if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) + return -EFAULT; + err = mtrr_add (sentry.base, sentry.size, sentry.type, 0); + if (err < 0) + return err; + break; -static struct proc_dir_entry *proc_root_mtrr; + case MTRRIOC_DEL_ENTRY: + if (!suser ()) + return -EPERM; + if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) + return -EFAULT; + err = mtrr_file_del (sentry.base, sentry.size, file, 0); + if (err < 0) + return err; + break; -# endif /* CONFIG_PROC_FS */ + case MTRRIOC_KILL_ENTRY: + if (!suser ()) + return -EPERM; + if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) + return -EFAULT; + err = mtrr_del (-1, sentry.base, sentry.size); + if (err < 0) + return err; + break; -static devfs_handle_t devfs_handle; + case MTRRIOC_GET_ENTRY: + if (copy_from_user (&gentry, (void *) arg, sizeof gentry)) + return -EFAULT; + if (gentry.regnum >= get_num_var_ranges ()) + return -EINVAL; + (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type); + + /* Hide entries that go above 4GB */ + if (gentry.base + gentry.size > 0x100000 + || gentry.size == 0x100000) + gentry.base = gentry.size = gentry.type = 0; + else { + gentry.base <<= PAGE_SHIFT; + gentry.size <<= PAGE_SHIFT; + gentry.type = type; + } -static void compute_ascii (void) -{ - char factor; - int i, max; - mtrr_type type; - unsigned long base, size; - - ascii_buf_bytes = 0; - max = get_num_var_ranges (); - for (i = 0; i < max; i++) - { - (*get_mtrr) (i, &base, &size, &type); - if (size == 0) usage_table[i] = 0; - else - { - if (size < (0x100000 >> PAGE_SHIFT)) - { - /* less than 1MB */ - factor = 'K'; - size <<= PAGE_SHIFT - 10; - } - else - { - factor = 'M'; - size >>= 20 - PAGE_SHIFT; - } - sprintf - (ascii_buffer + ascii_buf_bytes, - "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n", - i, base, base >> (20 - PAGE_SHIFT), size, factor, - attrib_to_str (type), usage_table[i]); - ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes); - } - } - devfs_set_file_size (devfs_handle, ascii_buf_bytes); -# ifdef CONFIG_PROC_FS - if (proc_root_mtrr) - proc_root_mtrr->size = ascii_buf_bytes; -# endif /* CONFIG_PROC_FS */ -} /* End Function compute_ascii */ + if (copy_to_user ((void *) arg, &gentry, sizeof gentry)) + return -EFAULT; + break; -#endif /* USERSPACE_INTERFACE */ + case MTRRIOC_ADD_PAGE_ENTRY: + if (!suser ()) + return -EPERM; + if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) + return -EFAULT; + err = + mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, + file, 1); + if (err < 0) + return err; + break; -EXPORT_SYMBOL(mtrr_add); -EXPORT_SYMBOL(mtrr_del); + case MTRRIOC_SET_PAGE_ENTRY: + if (!suser ()) + return -EPERM; + if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) + return -EFAULT; + err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0); + if (err < 0) + return err; + break; -#ifdef CONFIG_SMP + case MTRRIOC_DEL_PAGE_ENTRY: + if (!suser ()) + return -EPERM; + if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) + return -EFAULT; + err = mtrr_file_del (sentry.base, sentry.size, file, 1); + if (err < 0) + return err; + break; -typedef struct -{ - unsigned long base; - unsigned long size; - mtrr_type type; -} arr_state_t; + case MTRRIOC_KILL_PAGE_ENTRY: + if (!suser ()) + return -EPERM; + if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) + return -EFAULT; + err = mtrr_del_page (-1, sentry.base, sentry.size); + if (err < 0) + return err; + break; -arr_state_t arr_state[8] __initdata = -{ - {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, - {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL} -}; + case MTRRIOC_GET_PAGE_ENTRY: + if (copy_from_user (&gentry, (void *) arg, sizeof gentry)) + return -EFAULT; + if (gentry.regnum >= get_num_var_ranges ()) + return -EINVAL; + (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type); + gentry.type = type; + + if (copy_to_user ((void *) arg, &gentry, sizeof gentry)) + return -EFAULT; + break; + } + return 0; +} -unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 }; -static void __init cyrix_arr_init_secondary(void) +static int mtrr_close (struct inode *ino, struct file *file) { - struct set_mtrr_context ctxt; - int i; - - /* flush cache and enable MAPEN */ - set_mtrr_prepare_save (&ctxt); - set_mtrr_cache_disable (&ctxt); - - /* the CCRs are not contiguous */ - for(i=0; i<4; i++) setCx86(CX86_CCR0 + i, ccr_state[i]); - for( ; i<7; i++) setCx86(CX86_CCR4 + i, ccr_state[i]); - for(i=0; i<8; i++) - cyrix_set_arr_up(i, - arr_state[i].base, arr_state[i].size, arr_state[i].type, FALSE); + int i, max; + unsigned int *fcount = file->private_data; - set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */ -} /* End Function cyrix_arr_init_secondary */ + if (fcount == NULL) + return 0; -#endif + lock_kernel (); + max = get_num_var_ranges (); + for (i = 0; i < max; ++i) { + while (fcount[i] > 0) { + if (mtrr_del (i, 0, 0) < 0) + printk ("mtrr: reg %d not used\n", i); + --fcount[i]; + } + } + unlock_kernel (); + kfree (fcount); + file->private_data = NULL; + return 0; +} -/* - * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection - * with the SMM (System Management Mode) mode. So we need the following: - * Check whether SMI_LOCK (CCR3 bit 0) is set - * if it is set, write a warning message: ARR3 cannot be changed! - * (it cannot be changed until the next processor reset) - * if it is reset, then we can change it, set all the needed bits: - * - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset) - * - disable access to SMM memory (CCR1 bit 2 reset) - * - disable SMM mode (CCR1 bit 1 reset) - * - disable write protection of ARR3 (CCR6 bit 1 reset) - * - (maybe) disable ARR3 - * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set) - */ -static void __init cyrix_arr_init(void) -{ - struct set_mtrr_context ctxt; - unsigned char ccr[7]; - int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 }; -#ifdef CONFIG_SMP - int i; -#endif - /* flush cache and enable MAPEN */ - set_mtrr_prepare_save (&ctxt); - set_mtrr_cache_disable (&ctxt); - - /* Save all CCRs locally */ - ccr[0] = getCx86 (CX86_CCR0); - ccr[1] = getCx86 (CX86_CCR1); - ccr[2] = getCx86 (CX86_CCR2); - ccr[3] = ctxt.ccr3; - ccr[4] = getCx86 (CX86_CCR4); - ccr[5] = getCx86 (CX86_CCR5); - ccr[6] = getCx86 (CX86_CCR6); - - if (ccr[3] & 1) - { - ccrc[3] = 1; - arr3_protected = 1; - } - else - { - /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and - * access to SMM memory through ARR3 (bit 7). - */ - if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; } - if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; } - if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; } - arr3_protected = 0; - if (ccr[6] & 0x02) { - ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3 */ - setCx86 (CX86_CCR6, ccr[6]); - } - /* Disable ARR3. This is safe now that we disabled SMM. */ - /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */ - } - /* If we changed CCR1 in memory, change it in the processor, too. */ - if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]); - - /* Enable ARR usage by the processor */ - if (!(ccr[5] & 0x20)) - { - ccr[5] |= 0x20; ccrc[5] = 1; - setCx86 (CX86_CCR5, ccr[5]); - } +static struct file_operations mtrr_fops = { + owner: THIS_MODULE, + read: mtrr_read, + write: mtrr_write, + ioctl: mtrr_ioctl, + release:mtrr_close, +}; -#ifdef CONFIG_SMP - for(i=0; i<7; i++) ccr_state[i] = ccr[i]; - for(i=0; i<8; i++) - cyrix_get_arr(i, - &arr_state[i].base, &arr_state[i].size, &arr_state[i].type); +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *proc_root_mtrr; #endif - set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */ - - if ( ccrc[5] ) printk ("mtrr: ARR usage was not enabled, enabled manually\n"); - if ( ccrc[3] ) printk ("mtrr: ARR3 cannot be changed\n"); -/* - if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n"); - if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n"); - if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n"); -*/ - if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n"); -} /* End Function cyrix_arr_init */ +static devfs_handle_t devfs_handle; -/* - * Initialise the later (saner) Winchip MCR variant. In this version - * the BIOS can pass us the registers it has used (but not their values) - * and the control register is read/write - */ - -static void __init centaur_mcr1_init(void) +static void compute_ascii (void) { - unsigned i; - u32 lo, hi; + char factor; + int i, max; + mtrr_type type; + unsigned long base, size; + + ascii_buf_bytes = 0; + max = get_num_var_ranges (); + for (i = 0; i < max; i++) { + (*get_mtrr) (i, &base, &size, &type); + if (size == 0) + usage_table[i] = 0; + else { + if (size < (0x100000 >> PAGE_SHIFT)) { + /* less than 1MB */ + factor = 'K'; + size <<= PAGE_SHIFT - 10; + } else { + factor = 'M'; + size >>= 20 - PAGE_SHIFT; + } + sprintf + (ascii_buffer + ascii_buf_bytes, + "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n", + i, base, base >> (20 - PAGE_SHIFT), size, factor, + attrib_to_str (type), usage_table[i]); + ascii_buf_bytes += + strlen (ascii_buffer + ascii_buf_bytes); + } + } + devfs_set_file_size (devfs_handle, ascii_buf_bytes); +#ifdef CONFIG_PROC_FS + if (proc_root_mtrr) + proc_root_mtrr->size = ascii_buf_bytes; +#endif +} - /* Unfortunately, MCR's are read-only, so there is no way to - * find out what the bios might have done. - */ - - rdmsr(0x120, lo, hi); - if(((lo>>17)&7)==1) /* Type 1 Winchip2 MCR */ - { - lo&= ~0x1C0; /* clear key */ - lo|= 0x040; /* set key to 1 */ - wrmsr(0x120, lo, hi); /* unlock MCR */ - } - - centaur_mcr_type = 1; - - /* - * Clear any unconfigured MCR's. - */ - - for (i = 0; i < 8; ++i) - { - if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0) - { - if(!(lo & (1<<(9+i)))) - wrmsr (0x110 + i , 0, 0); - else - /* - * If the BIOS set up an MCR we cannot see it - * but we don't wish to obliterate it - */ - centaur_mcr_reserved |= (1<= 0x80000008)) { - u32 phys_addr; - phys_addr = cpuid_eax(0x80000008) & 0xff ; - size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1); + if (test_bit (X86_FEATURE_MTRR, &boot_cpu_data.x86_capability)) { + /* Query the width (in bits) of the physical + addressable memory on the Hammer family. */ + if ((cpuid_eax (0x80000000) >= 0x80000008)) { + u32 phys_addr; + phys_addr = cpuid_eax (0x80000008) & 0xff; + size_or_mask = + ~((1 << (phys_addr - PAGE_SHIFT)) - 1); size_and_mask = ~size_or_mask & 0xfff00000; - break; } - size_or_mask = 0xff000000; /* 36 bits */ - size_and_mask = 0x00f00000; - break; - case X86_VENDOR_CENTAUR: - /* VIA Cyrix family have Intel style MTRRs, but don't support PAE */ - if (boot_cpu_data.x86 == 6) { - size_or_mask = 0xfff00000; /* 32 bits */ - size_and_mask = 0; - } - break; - - default: - /* Intel, etc. */ - size_or_mask = 0xff000000; /* 36 bits */ - size_and_mask = 0x00f00000; - break; + printk ("mtrr: detected mtrr type: x86-64\n"); } - - } else if ( test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ) { - /* Pre-Athlon (K6) AMD CPU MTRRs */ - mtrr_if = MTRR_IF_AMD_K6; - get_mtrr = amd_get_mtrr; - set_mtrr_up = amd_set_mtrr_up; - size_or_mask = 0xfff00000; /* 32 bits */ - size_and_mask = 0; - } else if ( test_bit(X86_FEATURE_CYRIX_ARR, &boot_cpu_data.x86_capability) ) { - /* Cyrix ARRs */ - mtrr_if = MTRR_IF_CYRIX_ARR; - get_mtrr = cyrix_get_arr; - set_mtrr_up = cyrix_set_arr_up; - get_free_region = cyrix_get_free_region; - cyrix_arr_init(); - size_or_mask = 0xfff00000; /* 32 bits */ - size_and_mask = 0; - } else if ( test_bit(X86_FEATURE_CENTAUR_MCR, &boot_cpu_data.x86_capability) ) { - /* Centaur MCRs */ - mtrr_if = MTRR_IF_CENTAUR_MCR; - get_mtrr = centaur_get_mcr; - set_mtrr_up = centaur_set_mcr_up; - get_free_region = centaur_get_free_region; - centaur_mcr_init(); - size_or_mask = 0xfff00000; /* 32 bits */ - size_and_mask = 0; - } else { - /* No supported MTRR interface */ - mtrr_if = MTRR_IF_NONE; - } - - printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n" - "mtrr: detected mtrr type: %s\n", - MTRR_VERSION, mtrr_if_name[mtrr_if]); - - return (mtrr_if != MTRR_IF_NONE); -} /* End Function mtrr_setup */ +} #ifdef CONFIG_SMP static volatile unsigned long smp_changes_mask __initdata = 0; -static struct mtrr_state smp_mtrr_state __initdata = {0, 0}; +static struct mtrr_state smp_mtrr_state __initdata = { 0, 0 }; -void __init mtrr_init_boot_cpu(void) +void __init mtrr_init_boot_cpu (void) { - if ( !mtrr_setup () ) - return; - - if ( mtrr_if == MTRR_IF_INTEL ) { - /* Only for Intel MTRRs */ + mtrr_setup(); get_mtrr_state (&smp_mtrr_state); - } -} /* End Function mtrr_init_boot_cpu */ +} + -static void __init intel_mtrr_init_secondary_cpu(void) +static void __init mtrr_init_secondary_cpu (void) { - unsigned long mask, count; - struct set_mtrr_context ctxt; + unsigned long mask, count; + struct set_mtrr_context ctxt; - /* Note that this is not ideal, since the cache is only flushed/disabled - for this CPU while the MTRRs are changed, but changing this requires - more invasive changes to the way the kernel boots */ - set_mtrr_prepare_save (&ctxt); - set_mtrr_cache_disable (&ctxt); - mask = set_mtrr_state (&smp_mtrr_state, &ctxt); - set_mtrr_done (&ctxt); - /* Use the atomic bitops to update the global mask */ - for (count = 0; count < sizeof mask * 8; ++count) - { - if (mask & 0x01) set_bit (count, &smp_changes_mask); - mask >>= 1; - } -} /* End Function intel_mtrr_init_secondary_cpu */ - -void __init mtrr_init_secondary_cpu(void) -{ - switch ( mtrr_if ) { - case MTRR_IF_INTEL: - /* Intel (P6) standard MTRRs */ - intel_mtrr_init_secondary_cpu(); - break; - case MTRR_IF_CYRIX_ARR: - /* This is _completely theoretical_! - * I assume here that one day Cyrix will support Intel APIC. - * In reality on non-Intel CPUs we won't even get to this routine. - * Hopefully no one will plug two Cyrix processors in a dual P5 board. - * :-) - */ - cyrix_arr_init_secondary (); - break; - default: - /* I see no MTRRs I can support in SMP mode... */ - printk ("mtrr: SMP support incomplete for this vendor\n"); - } -} /* End Function mtrr_init_secondary_cpu */ -#endif /* CONFIG_SMP */ + /* Note that this is not ideal, since the cache is only flushed/disabled + for this CPU while the MTRRs are changed, but changing this requires + more invasive changes to the way the kernel boots */ + set_mtrr_prepare (&ctxt); + mask = set_mtrr_state (&smp_mtrr_state, &ctxt); + set_mtrr_done (&ctxt); + + /* Use the atomic bitops to update the global mask */ + for (count = 0; count < sizeof mask * 8; ++count) { + if (mask & 0x01) + set_bit (count, &smp_changes_mask); + mask >>= 1; + } +} -int __init mtrr_init(void) +#endif /* CONFIG_SMP */ + + +int __init mtrr_init (void) { #ifdef CONFIG_SMP - /* mtrr_setup() should already have been called from mtrr_init_boot_cpu() */ + /* mtrr_setup() should already have been called from mtrr_init_boot_cpu() */ - if ( mtrr_if == MTRR_IF_INTEL ) { finalize_mtrr_state (&smp_mtrr_state); mtrr_state_warn (smp_changes_mask); - } #else - if ( !mtrr_setup() ) - return 0; /* MTRRs not supported? */ + mtrr_setup(); #endif #ifdef CONFIG_PROC_FS - proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); - if (proc_root_mtrr) { - proc_root_mtrr->owner = THIS_MODULE; - proc_root_mtrr->proc_fops = &mtrr_fops; - } + proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); + if (proc_root_mtrr) { + proc_root_mtrr->owner = THIS_MODULE; + proc_root_mtrr->proc_fops = &mtrr_fops; + } #endif - devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, - S_IFREG | S_IRUGO | S_IWUSR, - &mtrr_fops, NULL); - init_table (); - return 0; -} /* End Function mtrr_init */ - -/* - * Local Variables: - * mode:c - * c-file-style:"k&r" - * c-basic-offset:4 - * End: - */ +#ifdef CONFIG_DEVFS_FS + devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, + S_IFREG | S_IRUGO | S_IWUSR, + &mtrr_fops, NULL); +#endif + init_table (); + return 0; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/kernel/process.c linux-2.5/arch/x86_64/kernel/process.c --- linux-2.5.5/arch/x86_64/kernel/process.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/x86_64/kernel/process.c Fri Mar 1 15:07:37 2002 @@ -140,7 +140,6 @@ while (!need_resched()) idle(); schedule(); - check_pgt_cache(); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/kernel/ptrace.c linux-2.5/arch/x86_64/kernel/ptrace.c --- linux-2.5.5/arch/x86_64/kernel/ptrace.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/arch/x86_64/kernel/ptrace.c Fri Mar 1 15:07:37 2002 @@ -420,9 +420,11 @@ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0); + preempt_disable(); current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); + preempt_enable(); /* * this isn't the same as continuing with a signal, but it will do * for normal use. strace only continues with a signal if the diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/kernel/setup.c linux-2.5/arch/x86_64/kernel/setup.c --- linux-2.5.5/arch/x86_64/kernel/setup.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/arch/x86_64/kernel/setup.c Sat Feb 16 11:31:59 2002 @@ -1001,7 +1001,7 @@ void __init print_cpu_info(struct cpuinfo_x86 *c) { if (c->x86_model_id[0]) - printk("AMD %s", c->x86_model_id); + printk("%s", c->x86_model_id); if (c->x86_mask || c->cpuid_level >= 0) printk(" stepping %02x\n", c->x86_mask); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/kernel/signal.c linux-2.5/arch/x86_64/kernel/signal.c --- linux-2.5.5/arch/x86_64/kernel/signal.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/x86_64/kernel/signal.c Fri Mar 1 15:07:37 2002 @@ -89,7 +89,7 @@ spin_lock_irq(¤t->sigmask_lock); saveset = current->blocked; current->blocked = newset; - recalc_sigpending(current); + recalc_sigpending(); spin_unlock_irq(¤t->sigmask_lock); #if DEBUG_SIG printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n", @@ -200,7 +200,7 @@ sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); current->blocked = set; - recalc_sigpending(current); + recalc_sigpending(); spin_unlock_irq(¤t->sigmask_lock); if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &eax)) @@ -431,7 +431,7 @@ spin_lock_irq(¤t->sigmask_lock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); sigaddset(¤t->blocked,sig); - recalc_sigpending(current); + recalc_sigpending(); spin_unlock_irq(¤t->sigmask_lock); } } @@ -473,9 +473,11 @@ if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; + preempt_disable(); current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); + preempt_enable(); /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) @@ -530,12 +532,14 @@ case SIGSTOP: { struct signal_struct *sig; + preempt_disable(); current->state = TASK_STOPPED; current->exit_code = signr; sig = current->p_pptr->sig; if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); + preempt_enable(); continue; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/kernel/smpboot.c linux-2.5/arch/x86_64/kernel/smpboot.c --- linux-2.5.5/arch/x86_64/kernel/smpboot.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/arch/x86_64/kernel/smpboot.c Mon Mar 4 01:29:41 2002 @@ -559,7 +559,7 @@ * We remove it from the pidhash and the runqueue * once we got the process: */ - idle = init_task.prev_task; + idle = LAST_TASK; if (!idle) panic("No idle process for CPU %d", cpu); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/kernel/time.c linux-2.5/arch/x86_64/kernel/time.c --- linux-2.5.5/arch/x86_64/kernel/time.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/arch/x86_64/kernel/time.c Fri Mar 1 15:07:37 2002 @@ -120,6 +120,62 @@ extern spinlock_t i8259A_lock; + +static inline unsigned long do_fast_gettimeoffset(void) +{ + register unsigned long eax, edx; + + /* Read the Time Stamp Counter */ + + rdtsc(eax,edx); + + /* .. relative to previous jiffy (32 bits is enough) */ + eax -= last_tsc_low; /* tsc_low delta */ + + /* + * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient + * = (tsc_low delta) * (usecs_per_clock) + * = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy) + * + * Using a mull instead of a divl saves up to 31 clock cycles + * in the critical path. + */ + + edx = (eax*fast_gettimeoffset_quotient) >> 32; + + /* our adjusted time offset in microseconds */ + return delay_at_last_interrupt + edx; +} + +/* + * This version of gettimeofday has microsecond resolution + * and better than microsecond precision on fast x86 machines with TSC. + */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + unsigned long usec, sec; + + read_lock_irqsave(&xtime_lock, flags); + usec = do_gettimeoffset(); + { + unsigned long lost = jiffies - wall_jiffies; + if (lost) + usec += lost * (1000000 / HZ); + } + sec = xtime.tv_sec; + usec += xtime.tv_usec; + read_unlock_irqrestore(&xtime_lock, flags); + + while (usec >= 1000000) { + usec -= 1000000; + sec++; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + void do_settimeofday(struct timeval *tv) { write_lock_irq(&xtime_lock); @@ -484,7 +540,7 @@ * clock/second. Our precision is about 100 ppm. */ { - cpu_khz = ((1000000*(1UL<<32)) / tsc_quotient); /* FIXME: is it right? */ + cpu_khz = ((1000*(1UL<<32)) / tsc_quotient); printk("Detected %ld Hz processor.\n", cpu_khz); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/kernel/vsyscall.c linux-2.5/arch/x86_64/kernel/vsyscall.c --- linux-2.5.5/arch/x86_64/kernel/vsyscall.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/arch/x86_64/kernel/vsyscall.c Fri Mar 1 15:07:37 2002 @@ -60,9 +60,6 @@ long __vxtime_sequence[2] __section_vxtime_sequence; -/* The rest of the kernel knows it as this. */ -extern void do_gettimeofday(struct timeval *tv) __attribute__((alias("do_vgettimeofday"))); - inline void do_vgettimeofday(struct timeval * tv) { long sequence; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/kernel/x8664_ksyms.c linux-2.5/arch/x86_64/kernel/x8664_ksyms.c --- linux-2.5.5/arch/x86_64/kernel/x8664_ksyms.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/arch/x86_64/kernel/x8664_ksyms.c Fri Mar 1 15:07:37 2002 @@ -89,7 +89,6 @@ EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strpbrk); -EXPORT_SYMBOL(simple_strtol); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strncpy_from_user); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/mm/fault.c linux-2.5/arch/x86_64/mm/fault.c --- linux-2.5.5/arch/x86_64/mm/fault.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/arch/x86_64/mm/fault.c Fri Mar 1 15:07:37 2002 @@ -112,7 +112,7 @@ mm = tsk->mm; info.si_code = SEGV_MAPERR; - if (address >= TASK_SIZE) + if (address >= TASK_SIZE && !(error_code & 5)) goto vmalloc_fault; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/mm/init.c linux-2.5/arch/x86_64/mm/init.c --- linux-2.5.5/arch/x86_64/mm/init.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/arch/x86_64/mm/init.c Fri Mar 1 15:07:37 2002 @@ -1,8 +1,9 @@ /* - * linux/arch/i386/mm/init.c + * linux/arch/x86_64/mm/init.c * * Copyright (C) 1995 Linus Torvalds * Copyright (C) 2000 Pavel Machek + * Copyright (C) 2002 Andi Kleen */ #include @@ -39,28 +40,6 @@ static unsigned long totalram_pages; -int do_check_pgt_cache(int low, int high) -{ - int freed = 0; - if(read_pda(pgtable_cache_sz) > high) { - do { - if (read_pda(pgd_quick)) { - pgd_free_slow(pgd_alloc_one_fast()); - freed++; - } - if (read_pda(pmd_quick)) { - pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); - freed++; - } - if (read_pda(pte_quick)) { - pte_free_slow(pte_alloc_one_fast(NULL, 0)); - freed++; - } - } while(read_pda(pgtable_cache_sz) > low); - } - return freed; -} - /* * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the * physical space so we can cache the place of the first one and move @@ -89,7 +68,6 @@ printk("%d reserved pages\n",reserved); printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); - printk("%ld pages in page table cache\n",read_pda(pgtable_cache_sz)); show_buffers(); } @@ -138,12 +116,12 @@ if (pmd_none(*pmd)) { pte = (pte_t *) spp_getpage(); set_pmd(pmd, __pmd(__pa(pte) + 0x7)); - if (pte != pte_offset(pmd, 0)) { + if (pte != pte_offset_kernel(pmd, 0)) { printk("PAGETABLE BUG #02!\n"); return; } } - pte = pte_offset(pmd, vaddr); + pte = pte_offset_kernel(pmd, vaddr); if (pte_val(*pte)) pte_ERROR(*pte); set_pte(pte, mk_pte_phys(phys, prot)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/mm/ioremap.c linux-2.5/arch/x86_64/mm/ioremap.c --- linux-2.5.5/arch/x86_64/mm/ioremap.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/x86_64/mm/ioremap.c Fri Mar 1 15:07:37 2002 @@ -49,7 +49,7 @@ if (address >= end) BUG(); do { - pte_t * pte = pte_alloc(&init_mm, pmd, address); + pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, flags); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/arch/x86_64/tools/offset.c linux-2.5/arch/x86_64/tools/offset.c --- linux-2.5.5/arch/x86_64/tools/offset.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/arch/x86_64/tools/offset.c Fri Mar 1 15:07:37 2002 @@ -42,10 +42,6 @@ ENTRY(irqrsp); ENTRY(irqcount); ENTRY(irqstack); - ENTRY(pgd_quick); - ENTRY(pmd_quick); - ENTRY(pte_quick); - ENTRY(pgtable_cache_sz); ENTRY(cpunumber); ENTRY(irqstackptr); ENTRY(me); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/Makefile linux-2.5/drivers/Makefile --- linux-2.5.5/drivers/Makefile Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/Makefile Thu Feb 14 02:57:58 2002 @@ -1,7 +1,7 @@ # # Makefile for the Linux kernel device drivers. # -# 15 Sep 2000, Christoph Hellwig +# 15 Sep 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/acorn/block/fd1772.c linux-2.5/drivers/acorn/block/fd1772.c --- linux-2.5.5/drivers/acorn/block/fd1772.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/acorn/block/fd1772.c Fri Feb 8 02:38:25 2002 @@ -373,6 +373,7 @@ static void config_types(void); static int floppy_open(struct inode *inode, struct file *filp); static int floppy_release(struct inode *inode, struct file *filp); +static void do_fd_request(request_queue_t *); /************************* End of Prototypes **************************/ @@ -1302,7 +1303,7 @@ } } -void do_fd_request(request_queue_t* q) +static void do_fd_request(request_queue_t* q) { unsigned long flags; @@ -1614,7 +1615,7 @@ blk_size[MAJOR_NR] = floppy_sizes; blksize_size[MAJOR_NR] = floppy_blocksizes; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request); config_types(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/acorn/block/mfmhd.c linux-2.5/drivers/acorn/block/mfmhd.c --- linux-2.5.5/drivers/acorn/block/mfmhd.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/acorn/block/mfmhd.c Tue Feb 26 21:24:48 2002 @@ -321,14 +321,14 @@ unsigned long flags; va_list ap; - save_flags_cli(flags); + local_irq_save(flags); va_start(ap, fmt); vsprintf(buffer, fmt, ap); console_print(buffer); va_end(fmt); - restore_flags(flags); + local_irq_restore(flags); }; /* console_printf */ #define DBG(x...) console_printf(x) @@ -746,7 +746,7 @@ /* Yep - a partial access */ /* and issue the remainder */ - issue_request(MINOR(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT); + issue_request(minor(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT); return; } @@ -929,7 +929,7 @@ DBG("mfm_request: before arg extraction\n"); - dev = MINOR(CURRENT->rq_dev); + dev = minor(CURRENT->rq_dev); block = CURRENT->sector; nsect = CURRENT->nr_sectors; #ifdef DEBUG @@ -1187,10 +1187,10 @@ if (!inode || !(dev = inode->i_rdev)) return -EINVAL; - major = MAJOR(dev); - minor = MINOR(dev); + major = major(dev); + minor = minor(dev); - device = DEVICE_NR(MINOR(inode->i_rdev)), err; + device = DEVICE_NR(minor(inode->i_rdev)), err; if (device >= mfm_drives) return -EINVAL; @@ -1231,7 +1231,7 @@ static int mfm_open(struct inode *inode, struct file *file) { - int dev = DEVICE_NR(MINOR(inode->i_rdev)); + int dev = DEVICE_NR(minor(inode->i_rdev)); if (dev >= mfm_drives) return -ENODEV; @@ -1249,7 +1249,7 @@ */ static int mfm_release(struct inode *inode, struct file *file) { - mfm_info[DEVICE_NR(MINOR(inode->i_rdev))].access_count--; + mfm_info[DEVICE_NR(minor(inode->i_rdev))].access_count--; return 0; } @@ -1270,7 +1270,7 @@ void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads, unsigned long discsize, unsigned int secsize) { - int drive = MINOR(dev) >> 6; + int drive = minor(dev) >> 6; if (mfm_info[drive].cylinders == 1) { mfm_info[drive].sectors = secsptrack; @@ -1338,7 +1338,7 @@ for (i = 0; i < mfm_drives; i++) { mfm_geometry (i); - register_disk(&mfm_gendisk, MKDEV(MAJOR_NR,i<<6), 1<<6, + register_disk(&mfm_gendisk, mk_kdev(MAJOR_NR,i<<6), 1<<6, &mfm_fops, mfm_info[i].cylinders * mfm_info[i].heads * mfm_info[i].sectors / 2); @@ -1430,7 +1430,7 @@ hdc63463_irqpolladdress = mfm_IRQPollLoc; hdc63463_irqpollmask = irqmask; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_mfm_request); add_gendisk(&mfm_gendisk); @@ -1448,23 +1448,23 @@ */ static int mfm_reread_partitions(kdev_t dev) { - unsigned int start, i, maxp, target = DEVICE_NR(MINOR(dev)); + unsigned int start, i, maxp, target = DEVICE_NR(minor(dev)); unsigned long flags; - save_flags_cli(flags); + local_irq_save(flags); if (mfm_info[target].busy || mfm_info[target].access_count > 1) { - restore_flags (flags); + local_irq_restore (flags); return -EBUSY; } mfm_info[target].busy = 1; - restore_flags (flags); + local_irq_restore (flags); maxp = 1 << mfm_gendisk.minor_shift; start = target << mfm_gendisk.minor_shift; for (i = maxp - 1; i >= 0; i--) { int minor = start + i; - invalidate_device (MKDEV(MAJOR_NR, minor), 1); + invalidate_device (mk_kdev(MAJOR_NR, minor), 1); mfm_gendisk.part[minor].start_sect = 0; mfm_gendisk.part[minor].nr_sects = 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/acorn/char/mouse_ps2.c linux-2.5/drivers/acorn/char/mouse_ps2.c --- linux-2.5.5/drivers/acorn/char/mouse_ps2.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/acorn/char/mouse_ps2.c Tue Feb 26 21:24:48 2002 @@ -1,8 +1,6 @@ /* * Driver for PS/2 mouse on IOMD interface */ - -#include #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/acorn/net/ether1.c linux-2.5/drivers/acorn/net/ether1.c --- linux-2.5.5/drivers/acorn/net/ether1.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/acorn/net/ether1.c Tue Feb 26 21:24:48 2002 @@ -99,13 +99,13 @@ unsigned long flags; unsigned short ret; - if (svflgs) { - save_flags_cli (flags); - } + if (svflgs) + local_irq_save (flags); + outb (addr >> 12, REG_PAGE); ret = inw (ETHER1_RAM + ((addr & 4095) >> 1)); if (svflgs) - restore_flags (flags); + local_irq_restore (flags); return ret; } @@ -114,13 +114,13 @@ { unsigned long flags; - if (svflgs) { - save_flags_cli (flags); - } + if (svflgs) + local_irq_save (flags); + outb (addr >> 12, REG_PAGE); outw (val, ETHER1_RAM + ((addr & 4095) >> 1)); if (svflgs) - restore_flags (flags); + local_irq_restore (flags); } /* @@ -722,7 +722,7 @@ nop.nop_command = CMD_NOP; nop.nop_link = nopaddr; - save_flags_cli(flags); + local_irq_save(flags); ether1_writebuffer (dev, &tx, txaddr, TX_SIZE); ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE); ether1_writebuffer (dev, skb->data, dataddr, len); @@ -733,7 +733,7 @@ /* now reset the previous nop pointer */ ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS); - restore_flags(flags); + local_irq_restore(flags); /* handle transmit */ dev->trans_start = jiffies; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/acorn/net/ether3.c linux-2.5/drivers/acorn/net/ether3.c --- linux-2.5.5/drivers/acorn/net/ether3.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/acorn/net/ether3.c Tue Feb 26 21:24:48 2002 @@ -491,7 +491,7 @@ del_timer(&priv->timer); - save_flags_cli(flags); + local_irq_save(flags); printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name); printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name, ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2)); @@ -501,7 +501,7 @@ priv->tx_head, priv->tx_tail); ether3_setbuffer(dev, buffer_read, priv->tx_tail); printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev)); - restore_flags(flags); + local_irq_restore(flags); priv->regs.config2 |= CFG2_CTRLO; priv->stats.tx_errors += 1; @@ -533,10 +533,10 @@ next_ptr = (priv->tx_head + 1) & 15; - save_flags_cli(flags); + local_irq_save(flags); if (priv->tx_tail == next_ptr) { - restore_flags(flags); + local_irq_restore(flags); return 1; /* unable to queue */ } @@ -565,7 +565,7 @@ } next_ptr = (priv->tx_head + 1) & 15; - restore_flags(flags); + local_irq_restore(flags); dev_kfree_skb(skb); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/acpi/executer/exresnte.c linux-2.5/drivers/acpi/executer/exresnte.c --- linux-2.5.5/drivers/acpi/executer/exresnte.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/acpi/executer/exresnte.c Sun Mar 3 17:54:35 2002 @@ -44,7 +44,7 @@ * FUNCTION: Acpi_ex_resolve_node_to_value * * PARAMETERS: Object_ptr - Pointer to a location that contains - * a pointer to a NS node, and will recieve a + * a pointer to a NS node, and will receive a * pointer to the resolved object. * Walk_state - Current state. Valid only if executing AML * code. NULL if simply resolving an object diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/atm/Config.help linux-2.5/drivers/atm/Config.help --- linux-2.5.5/drivers/atm/Config.help Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/atm/Config.help Mon Feb 25 18:58:39 2002 @@ -2,6 +2,12 @@ ATM over TCP driver. Useful mainly for development and for experiments. If unsure, say N. +CONFIG_ATM_LANAI + Supports ATM cards based on the Efficient Networks "Lanai" + chipset such as the Speedstream 3010 and the ENI-25p. The + Speedstream 3060 is currently not supported since we don't + have the code to drive the on-board Alcatel DSL chipset (yet). + CONFIG_ATM_ENI Driver for the Efficient Networks ENI155p series and SMC ATM Power155 155 Mbps ATM adapters. Both, the versions with 512KB and diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/atm/eni.c linux-2.5/drivers/atm/eni.c --- linux-2.5.5/drivers/atm/eni.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/atm/eni.c Mon Feb 18 03:39:04 2002 @@ -14,7 +14,6 @@ #include #include #include -#include /* for xtime */ #include #include #include @@ -2310,7 +2309,7 @@ name: DEV_LABEL, id_table: eni_pci_tbl, probe: eni_init_one, - remove: eni_remove_one, + remove: __devexit_p(eni_remove_one), }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/atm/firestream.c linux-2.5/drivers/atm/firestream.c --- linux-2.5.5/drivers/atm/firestream.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/atm/firestream.c Mon Feb 18 03:39:04 2002 @@ -1530,7 +1530,7 @@ fs_dprintk (FS_DEBUG_QUEUE, "Added %d entries. \n", n); } -static void __exit free_queue (struct fs_dev *dev, struct queue *txq) +static void __devexit free_queue (struct fs_dev *dev, struct queue *txq) { func_enter (); @@ -1546,7 +1546,7 @@ func_exit (); } -static void __exit free_freepool (struct fs_dev *dev, struct freepool *fp) +static void __devexit free_freepool (struct fs_dev *dev, struct freepool *fp) { func_enter (); @@ -2088,7 +2088,7 @@ #endif */ -const static struct pci_device_id firestream_pci_tbl[] __devinitdata = { +static struct pci_device_id firestream_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FS_IS50}, { PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS155, @@ -2102,7 +2102,7 @@ name: "firestream", id_table: firestream_pci_tbl, probe: firestream_init_one, - remove: firestream_remove_one, + remove: __devexit_p(firestream_remove_one), }; static int __init firestream_init_module (void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/atm/idt77252.c linux-2.5/drivers/atm/idt77252.c --- linux-2.5.5/drivers/atm/idt77252.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/atm/idt77252.c Thu Dec 13 16:32:35 2001 @@ -1,8 +1,8 @@ /******************************************************************* - * ident "$Id: idt77252.c,v 1.2 2001/11/11 08:13:54 ecd Exp $" + * ident "$Id: idt77252.c,v 1.3 2001/11/17 00:30:19 ecd Exp $" * * $Author: ecd $ - * $Date: 2001/11/11 08:13:54 $ + * $Date: 2001/11/17 00:30:19 $ * * Copyright (c) 2000 ATecoM GmbH * @@ -30,7 +30,7 @@ * *******************************************************************/ static char const rcsid[] = -"$Id: idt77252.c,v 1.2 2001/11/11 08:13:54 ecd Exp $"; +"$Id: idt77252.c,v 1.3 2001/11/17 00:30:19 ecd Exp $"; #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/atm/iphase.c linux-2.5/drivers/atm/iphase.c --- linux-2.5.5/drivers/atm/iphase.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/atm/iphase.c Mon Feb 18 03:39:04 2002 @@ -54,7 +54,6 @@ #include #include #include -#include /* for xtime */ #include #include #include @@ -1777,8 +1776,9 @@ memset((caddr_t)ia_vcc, 0, sizeof(*ia_vcc)); if (vcc->qos.txtp.max_sdu > (iadev->tx_buf_sz - sizeof(struct cpcs_trailer))){ - printk("IA: SDU size over the configured SDU size %d\n", - iadev->tx_buf_sz); + printk("IA: SDU size over (%d) the configured SDU size %d\n", + vcc->qos.txtp.max_sdu,iadev->tx_buf_sz); + INPH_IA_VCC(vcc) = NULL; kfree(ia_vcc); return -EINVAL; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/base/core.c linux-2.5/drivers/base/core.c --- linux-2.5.5/drivers/base/core.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/base/core.c Mon Feb 11 02:04:57 2002 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/DAC960.c linux-2.5/drivers/block/DAC960.c --- linux-2.5.5/drivers/block/DAC960.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/block/DAC960.c Thu Feb 21 01:26:10 2002 @@ -1945,7 +1945,7 @@ Initialize the I/O Request Queue. */ RequestQueue = BLK_DEFAULT_QUEUE(MajorNumber); - blk_init_queue(RequestQueue, DAC960_RequestFunction); + blk_init_queue(RequestQueue, DAC960_RequestFunction, &Controller->lock); RequestQueue->queuedata = Controller; blk_queue_max_hw_segments(RequestQueue, Controller->DriverScatterGatherLimit); @@ -2267,6 +2267,7 @@ Controller->Bus = Bus; Controller->Device = Device; Controller->Function = Function; + Controller->lock = SPIN_LOCK_UNLOCKED; /* Map the Controller Register Window. */ @@ -5295,7 +5296,7 @@ DAC960_ComputeGenericDiskInfo(Controller); DAC960_RegisterDisk(Controller, LogicalDriveNumber); } - if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0) + if (Controller->GenericDiskInfo.sizes[minor(Inode->i_rdev)] == 0) return -ENXIO; /* Increment Controller and Logical Drive Usage Counts. @@ -6902,3 +6903,5 @@ module_init(DAC960_Initialize); module_exit(DAC960_Finalize); + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/DAC960.h linux-2.5/drivers/block/DAC960.h --- linux-2.5.5/drivers/block/DAC960.h Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/block/DAC960.h Fri Feb 8 02:15:53 2002 @@ -2074,7 +2074,7 @@ #define DAC960_KernelDevice(ControllerNumber, \ LogicalDriveNumber, \ PartitionNumber) \ - MKDEV(DAC960_MajorNumber(ControllerNumber), \ + mk_kdev(DAC960_MajorNumber(ControllerNumber), \ DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber)) @@ -2477,6 +2477,7 @@ int BlockSizes[DAC960_MinorCount]; unsigned char ProgressBuffer[DAC960_ProgressBufferSize]; unsigned char UserStatusBuffer[DAC960_UserMessageSize]; + spinlock_t lock; } DAC960_Controller_T; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/Makefile linux-2.5/drivers/block/Makefile --- linux-2.5.5/drivers/block/Makefile Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/block/Makefile Mon Feb 4 22:15:16 2002 @@ -1,7 +1,7 @@ # # Makefile for the kernel block device drivers. # -# 12 June 2000, Christoph Hellwig +# 12 June 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # # Note : at this point, these files are compiled on all systems. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/acsi.c linux-2.5/drivers/block/acsi.c --- linux-2.5.5/drivers/block/acsi.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/block/acsi.c Thu Feb 21 00:23:13 2002 @@ -784,7 +784,7 @@ status = acsi_getstatus(); if (status != 0) { - int dev = DEVICE_NR(MINOR(CURRENT->rq_dev)); + int dev = DEVICE_NR(minor(CURRENT->rq_dev)); printk( KERN_ERR "ad%c: ", dev+'a' ); if (!acsi_reqsense( acsi_buffer, acsi_info[dev].target, acsi_info[dev].lun)) @@ -815,7 +815,7 @@ status = acsi_getstatus(); if (status != 0) { - int dev = DEVICE_NR(MINOR(CURRENT->rq_dev)); + int dev = DEVICE_NR(minor(CURRENT->rq_dev)); printk( KERN_ERR "ad%c: ", dev+'a' ); if (!acsi_reqsense( acsi_buffer, acsi_info[dev].target, acsi_info[dev].lun)) @@ -993,7 +993,7 @@ panic(DEVICE_NAME ": block not locked"); } - dev = MINOR(CURRENT->rq_dev); + dev = minor(CURRENT->rq_dev); block = CURRENT->sector; if (DEVICE_NR(dev) >= NDevices || block+CURRENT->nr_sectors >= acsi_part[dev].nr_sects) { @@ -1111,7 +1111,7 @@ if (!inode) return -EINVAL; - dev = DEVICE_NR(MINOR(inode->i_rdev)); + dev = DEVICE_NR(minor(inode->i_rdev)); if (dev >= NDevices) return -EINVAL; switch (cmd) { @@ -1174,7 +1174,7 @@ int device; struct acsi_info_struct *aip; - device = DEVICE_NR(MINOR(inode->i_rdev)); + device = DEVICE_NR(minor(inode->i_rdev)); if (device >= NDevices) return -ENXIO; aip = &acsi_info[device]; @@ -1212,7 +1212,7 @@ static int acsi_release( struct inode * inode, struct file * file ) { - int device = DEVICE_NR(MINOR(inode->i_rdev)); + int device = DEVICE_NR(minor(inode->i_rdev)); if (--access_count[device] == 0 && acsi_info[device].removable) acsi_prevent_removal(device, 0); return( 0 ); @@ -1240,7 +1240,7 @@ static int acsi_media_change (dev_t dev) { - int device = DEVICE_NR(MINOR(dev)); + int device = DEVICE_NR(minor(dev)); struct acsi_info_struct *aip; aip = &acsi_info[device]; @@ -1742,7 +1742,7 @@ acsi_blocksizes[i] = 1024; blksize_size[MAJOR_NR] = acsi_blocksizes; for( i = 0; i < NDevices; ++i ) - register_disk(&acsi_gendisk, MKDEV(MAJOR_NR,i<<4), + register_disk(&acsi_gendisk, mk_kdev(MAJOR_NR,i<<4), (acsi_info[i].type==HARDDISK)?1<<4:1, &acsi_fops, acsi_info[i].size); @@ -1784,7 +1784,7 @@ phys_acsi_buffer = virt_to_phys( acsi_buffer ); STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &acsi_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_acsi_request, &acsi_lock); add_gendisk(&acsi_gendisk); #ifdef CONFIG_ATARI_SLM @@ -1853,7 +1853,7 @@ int res; struct acsi_info_struct *aip; - device = DEVICE_NR(MINOR(dev)); + device = DEVICE_NR(minor(dev)); aip = &acsi_info[device]; gdev = &GENDISK_STRUCT; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/amiflop.c linux-2.5/drivers/block/amiflop.c --- linux-2.5.5/drivers/block/amiflop.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/block/amiflop.c Fri Mar 1 15:07:37 2002 @@ -1514,7 +1514,7 @@ rel_fdc(); return -EBUSY; } - fsync_dev(inode->i_rdev); + fsync_bdev(inode->i_bdev); if (fd_motor_on(drive) == 0) { rel_fdc(); return -ENODEV; @@ -1857,7 +1857,7 @@ post_write_timer.data = 0; post_write_timer.function = post_write; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &amiflop_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, &amiflop_lock); blksize_size[MAJOR_NR] = floppy_blocksizes; blk_size[MAJOR_NR] = floppy_sizes; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/ataflop.c linux-2.5/drivers/block/ataflop.c --- linux-2.5.5/drivers/block/ataflop.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/block/ataflop.c Thu Feb 21 01:26:10 2002 @@ -659,7 +659,7 @@ unsigned char *p; int sect, nsect; unsigned long flags; - int type, drive = MINOR(device) & 3; + int type, drive = minor(device) & 3; DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n", drive, desc->track, desc->head, desc->sect_offset )); @@ -672,7 +672,7 @@ atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */ restore_flags(flags); - type = MINOR(device) >> 2; + type = minor(device) >> 2; if (type) { if (--type >= NUM_DISK_MINORS || minor2disktype[type].drive_types > DriveType) { @@ -1367,9 +1367,9 @@ static int check_floppy_change (kdev_t dev) { - unsigned int drive = MINOR(dev) & 0x03; + unsigned int drive = minor(dev) & 0x03; - if (MAJOR(dev) != MAJOR_NR) { + if (major(dev) != MAJOR_NR) { printk(KERN_ERR "floppy_changed: not a floppy\n"); return 0; } @@ -1394,7 +1394,7 @@ static int floppy_revalidate (kdev_t dev) { - int drive = MINOR(dev) & 3; + int drive = minor(dev) & 3; if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change) || @@ -1466,13 +1466,13 @@ if (QUEUE_EMPTY) goto the_end; - if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + if (major(CURRENT->rq_dev) != MAJOR_NR) panic(DEVICE_NAME ": request list destroyed"); if (CURRENT->bh && !buffer_locked(CURRENT->bh)) panic(DEVICE_NAME ": block not locked"); - device = MINOR(CURRENT_DEVICE); + device = minor(CURRENT_DEVICE); drive = device & 3; type = device >> 2; @@ -1553,7 +1553,7 @@ { /* invalidate the buffer track to force a reread */ BufferDrive = -1; - set_bit(MINOR(rdev) & 3, &fake_change); + set_bit(minor(rdev) & 3, &fake_change); check_disk_change(rdev); return 0; } @@ -1576,7 +1576,7 @@ case BLKFLSBUF: return blk_ioctl(device, cmd, param); } - drive = MINOR (device); + drive = minor (device); type = drive >> 2; drive &= 3; switch (cmd) { @@ -1896,15 +1896,15 @@ return -EIO; } - drive = MINOR(inode->i_rdev) & 3; - type = MINOR(inode->i_rdev) >> 2; + drive = minor(inode->i_rdev) & 3; + type = minor(inode->i_rdev) >> 2; DPRINT(("fd_open: type=%d\n",type)); if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS) return -ENXIO; old_dev = fd_device[drive]; - if (fd_ref[drive] && old_dev != MINOR(inode->i_rdev)) + if (fd_ref[drive] && old_dev != minor(inode->i_rdev)) return -EBUSY; if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL)) @@ -1915,10 +1915,10 @@ else fd_ref[drive]++; - fd_device[drive] = MINOR(inode->i_rdev); + fd_device[drive] = minor(inode->i_rdev); - if (old_dev && old_dev != MINOR(inode->i_rdev)) - invalidate_buffers(MKDEV(FLOPPY_MAJOR, old_dev)); + if (old_dev && old_dev != minor(inode->i_rdev)) + invalidate_buffers(mk_kdev(FLOPPY_MAJOR, old_dev)); if (filp->f_flags & O_NDELAY) return 0; @@ -1939,7 +1939,7 @@ static int floppy_release( struct inode * inode, struct file * filp ) { - int drive = MINOR(inode->i_rdev) & 3; + int drive = minor(inode->i_rdev) & 3; if (fd_ref[drive] < 0) fd_ref[drive] = 0; @@ -2013,7 +2013,7 @@ blk_size[MAJOR_NR] = floppy_sizes; blksize_size[MAJOR_NR] = floppy_blocksizes; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &ataflop_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, &ataflop_lock); printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n", DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E', diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/blkpg.c linux-2.5/drivers/block/blkpg.c --- linux-2.5.5/drivers/block/blkpg.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/block/blkpg.c Thu Feb 21 01:26:10 2002 @@ -256,7 +256,7 @@ if (cmd == BLKGETSIZE) return put_user((unsigned long)ullval, (unsigned long *)arg); else - return put_user((u64)ullval << 9 , (u64 *)arg); + return put_user(ullval << 9, (u64 *)arg); #if 0 case BLKRRPART: /* Re-read partition tables */ if (!capable(CAP_SYS_ADMIN)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/cciss.c linux-2.5/drivers/block/cciss.c --- linux-2.5.5/drivers/block/cciss.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/block/cciss.c Tue Feb 26 21:24:48 2002 @@ -2617,7 +2617,7 @@ static struct pci_driver cciss_pci_driver = { name: "cciss", probe: cciss_init_one, - remove: cciss_remove_one, + remove: __devexit_p(cciss_remove_one), id_table: cciss_pci_device_id, /* id_table */ }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/cpqarray.c linux-2.5/drivers/block/cpqarray.c --- linux-2.5.5/drivers/block/cpqarray.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/block/cpqarray.c Thu Feb 21 01:26:10 2002 @@ -52,6 +52,7 @@ MODULE_LICENSE("GPL"); #define MAJOR_NR COMPAQ_SMART2_MAJOR +#define LOCAL_END_REQUEST #include #include #include @@ -1491,9 +1492,10 @@ int ctlr, i; unsigned long flags; - ctlr = major(dev) - MAJOR_NR; if (minor(dev) != 0) return -ENXIO; + + ctlr = major(dev) - MAJOR_NR; spin_lock_irqsave(IDA_LOCK(ctlr), flags); if (hba[ctlr]->usage_count > 1) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/floppy.c linux-2.5/drivers/block/floppy.c --- linux-2.5.5/drivers/block/floppy.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/block/floppy.c Thu Feb 21 01:26:10 2002 @@ -129,6 +129,12 @@ * floppy controller (lingering task on list after module is gone... boom.) */ +/* + * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range + * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix + * requires many non-obvious changes in arch dependent code. + */ + #define FLOPPY_SANITY_CHECK #undef FLOPPY_SILENT_DCL_CLEAR @@ -230,6 +236,7 @@ static int irqdma_allocated; +#define LOCAL_END_REQUEST #define MAJOR_NR FLOPPY_MAJOR #include @@ -2274,17 +2281,32 @@ * ============================= */ +static inline void end_request(struct request *req, int uptodate) +{ + kdev_t dev = req->rq_dev; + + if (end_that_request_first(req, uptodate, req->hard_cur_sectors)) + return; + add_blkdev_randomness(major(dev)); + floppy_off(DEVICE_NR(dev)); + blkdev_dequeue_request(req); + end_that_request_last(req); +} + + /* new request_done. Can handle physical sectors which are smaller than a * logical buffer */ static void request_done(int uptodate) { + struct request_queue *q = QUEUE; + struct request *req = elv_next_request(q); unsigned long flags; int block; probing = 0; reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate); - if (QUEUE_EMPTY){ + if (blk_queue_empty(q)) { DPRINT("request list destroyed in floppy request done\n"); return; } @@ -2292,48 +2314,48 @@ if (uptodate){ /* maintain values for invalidation on geometry * change */ - block = current_count_sectors + CURRENT->sector; + block = current_count_sectors + req->sector; INFBOUND(DRS->maxblock, block); if (block > _floppy->sect) DRS->maxtrack = 1; /* unlock chained buffers */ - spin_lock_irqsave(QUEUE->queue_lock, flags); - while (current_count_sectors && !QUEUE_EMPTY && - current_count_sectors >= CURRENT->current_nr_sectors){ - current_count_sectors -= CURRENT->current_nr_sectors; - CURRENT->nr_sectors -= CURRENT->current_nr_sectors; - CURRENT->sector += CURRENT->current_nr_sectors; - end_request(1); + spin_lock_irqsave(q->queue_lock, flags); + while (current_count_sectors && !blk_queue_empty(q) && + current_count_sectors >= req->current_nr_sectors){ + current_count_sectors -= req->current_nr_sectors; + req->nr_sectors -= req->current_nr_sectors; + req->sector += req->current_nr_sectors; + end_request(req, 1); } - spin_unlock_irqrestore(QUEUE->queue_lock, flags); + spin_unlock_irqrestore(q->queue_lock, flags); - if (current_count_sectors && !QUEUE_EMPTY){ + if (current_count_sectors && !blk_queue_empty(q)) { /* "unlock" last subsector */ - CURRENT->buffer += current_count_sectors <<9; - CURRENT->current_nr_sectors -= current_count_sectors; - CURRENT->nr_sectors -= current_count_sectors; - CURRENT->sector += current_count_sectors; + req->buffer += current_count_sectors <<9; + req->current_nr_sectors -= current_count_sectors; + req->nr_sectors -= current_count_sectors; + req->sector += current_count_sectors; return; } - if (current_count_sectors && QUEUE_EMPTY) + if (current_count_sectors && blk_queue_empty(q)) DPRINT("request list destroyed in floppy request done\n"); } else { - if (rq_data_dir(CURRENT) == WRITE) { + if (rq_data_dir(req) == WRITE) { /* record write error information */ DRWE->write_errors++; if (DRWE->write_errors == 1) { - DRWE->first_error_sector = CURRENT->sector; + DRWE->first_error_sector = req->sector; DRWE->first_error_generation = DRS->generation; } - DRWE->last_error_sector = CURRENT->sector; + DRWE->last_error_sector = req->sector; DRWE->last_error_generation = DRS->generation; } - spin_lock_irqsave(QUEUE->queue_lock, flags); - end_request(0); - spin_unlock_irqrestore(QUEUE->queue_lock, flags); + spin_lock_irqsave(q->queue_lock, flags); + end_request(req, 0); + spin_unlock_irqrestore(q->queue_lock, flags); } } @@ -4168,7 +4190,7 @@ blk_size[MAJOR_NR] = floppy_sizes; blksize_size[MAJOR_NR] = floppy_blocksizes; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &floppy_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, &floppy_lock); reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT); config_types(); @@ -4225,7 +4247,7 @@ FDCS->rawcmd = 2; if (user_reset_fdc(-1,FD_RESET_ALWAYS,0)){ /* free ioports reserved by floppy_grab_irq_and_dma() */ - release_region(FDCS->address, 6); + release_region(FDCS->address+2, 4); release_region(FDCS->address+7, 1); FDCS->address = -1; FDCS->version = FDC_NONE; @@ -4235,7 +4257,7 @@ FDCS->version = get_fdc_version(); if (FDCS->version == FDC_NONE){ /* free ioports reserved by floppy_grab_irq_and_dma() */ - release_region(FDCS->address, 6); + release_region(FDCS->address+2, 4); release_region(FDCS->address+7, 1); FDCS->address = -1; continue; @@ -4314,11 +4336,11 @@ for (fdc=0; fdc< N_FDC; fdc++){ if (FDCS->address != -1){ - if (!request_region(FDCS->address, 6, "floppy")) { - DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address); + if (!request_region(FDCS->address+2, 4, "floppy")) { + DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + 2); goto cleanup1; } - if (!request_region(FDCS->address + 7, 1, "floppy DIR")) { + if (!request_region(FDCS->address+7, 1, "floppy DIR")) { DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + 7); goto cleanup2; } @@ -4346,12 +4368,12 @@ irqdma_allocated = 1; return 0; cleanup2: - release_region(FDCS->address, 6); + release_region(FDCS->address + 2, 4); cleanup1: fd_free_irq(); fd_free_dma(); while(--fdc >= 0) { - release_region(FDCS->address, 6); + release_region(FDCS->address + 2, 4); release_region(FDCS->address + 7, 1); } MOD_DEC_USE_COUNT; @@ -4418,7 +4440,7 @@ old_fdc = fdc; for (fdc = 0; fdc < N_FDC; fdc++) if (FDCS->address != -1) { - release_region(FDCS->address, 6); + release_region(FDCS->address+2, 4); release_region(FDCS->address+7, 1); } fdc = old_fdc; @@ -4478,3 +4500,5 @@ __setup ("floppy=", floppy_setup); module_init(floppy_init) #endif + +EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/genhd.c linux-2.5/drivers/block/genhd.c --- linux-2.5.5/drivers/block/genhd.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/block/genhd.c Thu Jan 24 19:36:18 2002 @@ -30,6 +30,7 @@ * Global kernel list of partitioning information. */ static struct gendisk *gendisk_head; +static struct gendisk *gendisk_array[MAX_BLKDEV]; /** * add_gendisk - add partitioning information to kernel list @@ -59,6 +60,7 @@ goto out; } } + gendisk_array[gp->major] = gp; gp->next = gendisk_head; gendisk_head = gp; out: @@ -81,6 +83,7 @@ struct gendisk **gpp; write_lock(&gendisk_lock); + gendisk_array[gp->major] = NULL; for (gpp = &gendisk_head; *gpp; gpp = &((*gpp)->next)) if (*gpp == gp) break; @@ -106,11 +109,15 @@ int maj = major(dev); read_lock(&gendisk_lock); + if ((gp = gendisk_array[maj])) + goto out; + + /* This is needed for early 2.4 source compatiblity. --hch */ for (gp = gendisk_head; gp; gp = gp->next) if (gp->major == maj) break; +out: read_unlock(&gendisk_lock); - return gp; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/ll_rw_blk.c linux-2.5/drivers/block/ll_rw_blk.c --- linux-2.5.5/drivers/block/ll_rw_blk.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/block/ll_rw_blk.c Mon Mar 4 02:28:59 2002 @@ -1695,11 +1695,12 @@ printk("block: %d slots per queue, batch=%d\n", queue_nr_requests, batch_requests); blk_max_low_pfn = max_low_pfn; +#ifdef CONFIG_HIGHMEM blk_max_pfn = max_pfn; - -#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_IDE) - ide_init(); /* this MUST precede hd_init */ +#else + blk_max_pfn = max_low_pfn; #endif + #if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_HD) hd_init(); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/loop.c linux-2.5/drivers/block/loop.c --- linux-2.5.5/drivers/block/loop.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/block/loop.c Sun Mar 3 17:54:35 2002 @@ -36,6 +36,9 @@ * Al Viro too. * Jens Axboe , Nov 2000 * + * Support up to 256 loop devices + * Heinz Mauelshagen , Feb 2002 + * * Still To Fix: * - Advisory locking is ignored here. * - Should use an own CAP_* category instead of CAP_SYS_ADMIN @@ -380,7 +383,7 @@ static void loop_end_io_transfer(struct bio *bio) { struct bio *rbh = bio->bi_private; - struct loop_device *lo = &loop_dev[minor(rbh->bi_dev)]; + struct loop_device *lo = &loop_dev[minor(bio->bi_dev)]; int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); if (!uptodate || bio_rw(bio) == WRITE) { @@ -927,7 +930,7 @@ * And now the modules code and kernel interface. */ MODULE_PARM(max_loop, "i"); -MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-255)"); +MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-256)"); MODULE_LICENSE("GPL"); int loop_register_transfer(struct loop_func_table *funcs) @@ -963,9 +966,9 @@ { int i; - if ((max_loop < 1) || (max_loop > 255)) { + if ((max_loop < 1) || (max_loop > 256)) { printk(KERN_WARNING "loop: invalid max_loop (must be between" - " 1 and 255), using default (8)\n"); + " 1 and 256), using default (8)\n"); max_loop = 8; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/nbd.c linux-2.5/drivers/block/nbd.c --- linux-2.5.5/drivers/block/nbd.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/block/nbd.c Thu Feb 14 02:57:58 2002 @@ -327,7 +327,7 @@ req = CURRENT; #ifdef PARANOIA if (!req) - FAIL("que not empty but no request?"); + FAIL("queue not empty but no request?"); #endif dev = minor(req->rq_dev); #ifdef PARANOIA diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/paride/pcd.c linux-2.5/drivers/block/paride/pcd.c --- linux-2.5.5/drivers/block/paride/pcd.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/block/paride/pcd.c Thu Feb 21 00:23:39 2002 @@ -181,9 +181,7 @@ #define MAJOR_NR major #define DEVICE_NAME "PCD" -#define DEVICE_REQUEST do_pcd_request #define DEVICE_NR(device) (minor(device)) -#define DEVICE_ON(device) #define DEVICE_OFF(device) #include @@ -357,7 +355,7 @@ } } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &pcd_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_pcd_request, &pcd_lock); for (i=0;i>PD_BITS) -#define DEVICE_ON(device) #define DEVICE_OFF(device) #include @@ -395,9 +393,9 @@ return -1; } q = BLK_DEFAULT_QUEUE(MAJOR_NR); - blk_init_queue(q, DEVICE_REQUEST, &pd_lock); + blk_init_queue(q, do_pd_request, &pd_lock); blk_queue_max_sectors(q, cluster); - + pd_gendisk.major = major; pd_gendisk.major_name = name; add_gendisk(&pd_gendisk); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/paride/pf.c linux-2.5/drivers/block/paride/pf.c --- linux-2.5.5/drivers/block/paride/pf.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/block/paride/pf.c Thu Feb 21 01:26:10 2002 @@ -201,9 +201,7 @@ #define MAJOR_NR major #define DEVICE_NAME "PF" -#define DEVICE_REQUEST do_pf_request #define DEVICE_NR(device) minor(device) -#define DEVICE_ON(device) #define DEVICE_OFF(device) #include @@ -360,10 +358,10 @@ return -1; } q = BLK_DEFAULT_QUEUE(MAJOR_NR); - blk_init_queue(q, DEVICE_REQUEST, &pf_spin_lock); + blk_init_queue(q, do_pf_request, &pf_spin_lock); blk_queue_max_phys_segments(q, cluster); blk_queue_max_hw_segments(q, cluster); - + for (i=0;ibuffers; + void * address; + + if (need_kmap) + kmap(page); + address = page_address(page); + if (bh) { + struct buffer_head *tmp = bh; + do { + if (!buffer_uptodate(tmp)) { + memset(address, 0, tmp->b_size); + mark_buffer_uptodate(tmp, 1); + } + address += tmp->b_size; + tmp = tmp->b_this_page; + } while (tmp != bh); + } else + memset(address, 0, PAGE_CACHE_SIZE); + if (need_kmap) + kunmap(page); flush_dcache_page(page); SetPageUptodate(page); } +} + +static int ramdisk_readpage(struct file *file, struct page * page) +{ + ramdisk_updatepage(page, 1); UnlockPage(page); return 0; } static int ramdisk_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) { - if (!Page_Uptodate(page)) { - void *addr = page_address(page); - memset(addr, 0, PAGE_CACHE_SIZE); - flush_dcache_page(page); - SetPageUptodate(page); - } + ramdisk_updatepage(page, 0); SetPageDirty(page); return 0; } @@ -150,40 +168,37 @@ err = 0; mapping = rd_bdev[minor]->bd_inode->i_mapping; + /* writing a buffer cache not uptodate must not clear it */ + /*if (sbh->b_page->mapping == mapping) { + if (rw == WRITE) { + mark_buffer_uptodate(sbh, 1); + SetPageDirty(sbh->b_page); + } + goto out; + }*/ + index = sector >> (PAGE_CACHE_SHIFT - 9); offset = (sector << 9) & ~PAGE_CACHE_MASK; size = vec->bv_len; do { int count; - struct page ** hash; struct page * page; char * src, * dst; - int unlock = 0; count = PAGE_CACHE_SIZE - offset; if (count > size) count = size; size -= count; - hash = page_hash(mapping, index); - page = __find_get_page(mapping, index, hash); + page = grab_cache_page(mapping, index); if (!page) { - page = grab_cache_page(mapping, index); err = -ENOMEM; - if (!page) - goto out; - err = 0; - - if (!Page_Uptodate(page)) { - memset(kmap(page), 0, PAGE_CACHE_SIZE); - kunmap(page); - SetPageUptodate(page); - } - - unlock = 1; + goto out; } + ramdisk_updatepage(page, 1); + index++; if (rw == READ) { @@ -207,8 +222,7 @@ } else { SetPageDirty(page); } - if (unlock) - UnlockPage(page); + UnlockPage(page); __free_page(page); } while (size); @@ -268,7 +282,7 @@ goto fail; set_bit(BIO_UPTODATE, &sbh->bi_flags); - sbh->bi_end_io(sbh, len >> 9); + sbh->bi_end_io(sbh); return 0; fail: bio_io_error(sbh); @@ -299,6 +313,7 @@ error = 0; } up(&inode->i_bdev->bd_sem); + invalidate_buffers(inode->i_rdev); break; case BLKGETSIZE: /* Return device size */ if (!arg) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/smart1,2.h linux-2.5/drivers/block/smart1,2.h --- linux-2.5.5/drivers/block/smart1,2.h Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/block/smart1,2.h Thu Feb 21 16:21:07 2002 @@ -252,7 +252,10 @@ outb(CHANNEL_CLEAR, h->ioaddr + SMART1_LOCAL_DOORBELL); +#include // Nuke me when you nuke the ifdef. +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif if (cmd) ((cmdlist_t*)bus_to_virt(cmd))->req.hdr.rcode = status; } else { cmd = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/swim3.c linux-2.5/drivers/block/swim3.c --- linux-2.5.5/drivers/block/swim3.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/block/swim3.c Fri Feb 8 02:38:25 2002 @@ -29,14 +29,15 @@ #include #include #include -#include +#include +#include #define MAJOR_NR FLOPPY_MAJOR #include #include static int floppy_blocksizes[2] = {512,512}; -static int floppy_sizes[2] = {2880,2880}; +static int floppy_sizes[2] = {1440,1440}; #define MAX_FLOPPIES 2 @@ -445,9 +446,9 @@ ++cp; init_dma(cp, OUTPUT_MORE, CURRENT->buffer, 512); ++cp; - init_dma(cp, OUTPUT_MORE, write_postamble, sizeof(write_postamble)); + init_dma(cp, OUTPUT_LAST, write_postamble, sizeof(write_postamble)); } else { - init_dma(cp, INPUT_MORE, CURRENT->buffer, n * 512); + init_dma(cp, INPUT_LAST, CURRENT->buffer, n * 512); } ++cp; out_le16(&cp->command, DBDMA_STOP); @@ -679,7 +680,10 @@ break; dr = fs->dma; cp = fs->dma_cmd; - st_le32(&dr->control, RUN << 16); + /* We must wait a bit for dbdma to complete */ + for (n=0; (in_le32(&dr->status) & ACTIVE) && n < 1000; n++) + udelay(10); + DBDMA_DO_STOP(dr); out_8(&sw->intr_enable, 0); out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION); out_8(&sw->select, RELAX); @@ -1032,7 +1036,8 @@ MAJOR_NR); return -EBUSY; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST,&swim3_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, + &swim3_lock); blksize_size[MAJOR_NR] = floppy_blocksizes; blk_size[MAJOR_NR] = floppy_sizes; } @@ -1061,9 +1066,14 @@ return -EINVAL; } + if (!request_OF_resource(swim, 0, NULL)) { + printk(KERN_INFO "swim3: can't request IO resource !\n"); + return -EINVAL; + } + mediabay = (strcasecmp(swim->parent->type, "media-bay") == 0) ? swim->parent : NULL; if (mediabay == NULL) - feature_set(swim, FEATURE_SWIM3_enable); + pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1); memset(fs, 0, sizeof(*fs)); fs->state = idle; @@ -1085,14 +1095,14 @@ if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) { printk(KERN_ERR "Couldn't get irq %d for SWIM3\n", fs->swim3_intr); - feature_clear(swim, FEATURE_SWIM3_enable); + pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0); return -EBUSY; } /* if (request_irq(fs->dma_intr, fd_dma_interrupt, 0, "SWIM3-dma", fs)) { printk(KERN_ERR "Couldn't get irq %d for SWIM3 DMA", fs->dma_intr); - feature_clear(swim, FEATURE_SWIM3_enable); + pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0); return -EBUSY; } */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/swim_iop.c linux-2.5/drivers/block/swim_iop.c --- linux-2.5.5/drivers/block/swim_iop.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/block/swim_iop.c Fri Feb 8 02:38:25 2002 @@ -149,7 +149,8 @@ MAJOR_NR); return -EBUSY; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &swim_iop_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, + &swim_iop_lock); blksize_size[MAJOR_NR] = floppy_blocksizes; blk_size[MAJOR_NR] = floppy_sizes; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/block/xd.c linux-2.5/drivers/block/xd.c --- linux-2.5.5/drivers/block/xd.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/block/xd.c Thu Feb 21 01:26:10 2002 @@ -170,7 +170,7 @@ return -1; } devfs_handle = devfs_mk_dir (NULL, xd_gendisk.major_name, NULL); - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &xd_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_xd_request, &xd_lock); add_gendisk(&xd_gendisk); xd_geninit(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/cdrom/aztcd.c linux-2.5/drivers/cdrom/aztcd.c --- linux-2.5.5/drivers/cdrom/aztcd.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/cdrom/aztcd.c Thu Feb 21 01:26:10 2002 @@ -1925,7 +1925,7 @@ MAJOR_NR); return -EIO; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &aztSpin); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_aztcd_request, &aztSpin); blksize_size[MAJOR_NR] = aztcd_blocksizes; register_disk(NULL, mk_kdev(MAJOR_NR, 0), 1, &azt_fops, 0); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/cdrom/cdu31a.c linux-2.5/drivers/cdrom/cdu31a.c --- linux-2.5.5/drivers/cdrom/cdu31a.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/cdrom/cdu31a.c Thu Feb 21 01:26:10 2002 @@ -3440,7 +3440,7 @@ strcmp("CD-ROM CDU31A", drive_config.product_id) == 0; blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), - DEVICE_REQUEST, + do_cdu31a_request, &cdu31a_lock); cdu31a_block_size = 1024; /* 1kB default block size */ /* use 'mount -o block=2048' */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/cdrom/cm206.c linux-2.5/drivers/cdrom/cm206.c --- linux-2.5.5/drivers/cdrom/cm206.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/cdrom/cm206.c Thu Feb 21 01:26:10 2002 @@ -1500,7 +1500,7 @@ return -EIO; } devfs_plain_cdrom(&cm206_info, &cm206_bdops); - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_cm206_request, &cm206_lock); blksize_size[MAJOR_NR] = cm206_blocksizes; init_bh(CM206_BH, cm206_bh); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/cdrom/gscd.c linux-2.5/drivers/cdrom/gscd.c --- linux-2.5.5/drivers/cdrom/gscd.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/cdrom/gscd.c Thu Feb 21 01:26:10 2002 @@ -1020,7 +1020,7 @@ devfs_register(NULL, "gscd", DEVFS_FL_DEFAULT, MAJOR_NR, 0, S_IFBLK | S_IRUGO | S_IWUGO, &gscd_fops, NULL); - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &gscd_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_gscd_request, &gscd_lock); blksize_size[MAJOR_NR] = gscd_blocksizes; disk_state = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/cdrom/mcd.c linux-2.5/drivers/cdrom/mcd.c --- linux-2.5.5/drivers/cdrom/mcd.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/cdrom/mcd.c Thu Feb 21 01:26:10 2002 @@ -1073,7 +1073,7 @@ } blksize_size[MAJOR_NR] = mcd_blocksizes; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_mcd_request, &mcd_spinlock); /* check for card */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/cdrom/mcdx.c linux-2.5/drivers/cdrom/mcdx.c --- linux-2.5.5/drivers/cdrom/mcdx.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/cdrom/mcdx.c Thu Feb 21 01:26:10 2002 @@ -1182,7 +1182,7 @@ return 1; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_mcdx_request, &mcdx_lock); blksize_size[MAJOR_NR] = mcdx_blocksizes; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/cdrom/optcd.c linux-2.5/drivers/cdrom/optcd.c --- linux-2.5.5/drivers/cdrom/optcd.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/cdrom/optcd.c Thu Feb 21 01:26:10 2002 @@ -2060,7 +2060,7 @@ devfs_register (NULL, "optcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0, S_IFBLK | S_IRUGO | S_IWUGO, &opt_fops, NULL); blksize_size[MAJOR_NR] = &blksize; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_optcd_request, &optcd_lock); request_region(optcd_port, 4, "optcd"); register_disk(NULL, mk_kdev(MAJOR_NR,0), 1, &opt_fops, 0); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/cdrom/sbpcd.c linux-2.5/drivers/cdrom/sbpcd.c --- linux-2.5.5/drivers/cdrom/sbpcd.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/cdrom/sbpcd.c Thu Feb 21 01:26:10 2002 @@ -348,6 +348,12 @@ */ #define DONT_MERGE_REQUESTS +/* + * Add bio/kdev_t changes for 2.5.x required to make it work again. + * Still room for improvement in the request handling here if anyone + * actually cares. Bring your own chainsaw. Paul G. 02/2002 + */ + #ifndef SBPCD_ISSUE #define SBPCD_ISSUE 1 #endif /* SBPCD_ISSUE */ @@ -490,6 +496,8 @@ #define NUM_PROBE (sizeof(sbpcd) / sizeof(int)) +static spinlock_t sbpcd_lock = SPIN_LOCK_UNLOCKED; + /*==========================================================================*/ /* * the external references: @@ -4881,7 +4889,6 @@ */ #undef DEBUG_GTL static inline void sbpcd_end_request(struct request *req, int uptodate) { - list_add(&req->queue, &req->q->queue_head); end_request(uptodate); } /*==========================================================================*/ @@ -4917,8 +4924,7 @@ xnr, CURRENT, CURRENT->sector, CURRENT->nr_sectors, current->pid, jiffies); #endif INIT_REQUEST; - req=CURRENT; /* take out our request so no other */ - blkdev_dequeue_request(req); /* task can fuck it up GTL */ + req=CURRENT; if (req->rq_status == RQ_INACTIVE) sbpcd_end_request(req, 0); @@ -4927,9 +4933,9 @@ spin_unlock_irq(q->queue_lock); down(&ioctl_read_sem); - if (req->cmd != READ) + if (rq_data_dir(CURRENT) != READ) { - msg(DBG_INF, "bad cmd %d\n", req->cmd); + msg(DBG_INF, "bad cmd %d\n", req->cmd[0]); goto err_done; } i = minor(req->rq_dev); @@ -5680,13 +5686,13 @@ #ifdef DONT_MERGE_REQUESTS static int dont_merge_requests_fn(request_queue_t *q, struct request *req, - struct request *next, int max_segments) + struct request *next) { return 0; } static int dont_bh_merge_fn(request_queue_t *q, struct request *req, - struct buffer_head *bh, int max_segments) + struct bio *bio) { return 0; } @@ -5858,7 +5864,7 @@ goto init_done; #endif /* MODULE */ } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DO_SBPCD_REQUEST, &sbpcd_lock); #ifdef DONT_MERGE_REQUESTS (BLK_DEFAULT_QUEUE(MAJOR_NR))->back_merge_fn = dont_bh_merge_fn; (BLK_DEFAULT_QUEUE(MAJOR_NR))->front_merge_fn = dont_bh_merge_fn; @@ -5916,7 +5922,7 @@ } D_S[j].sbpcd_infop = sbpcd_infop; memcpy (sbpcd_infop, &sbpcd_info, sizeof(struct cdrom_device_info)); - sbpcd_infop->dev = MKDEV(MAJOR_NR, j); + sbpcd_infop->dev = mk_kdev(MAJOR_NR, j); strncpy(sbpcd_infop->name,major_name, sizeof(sbpcd_infop->name)); sprintf (nbuff, "c%dt%d/cd", SBPCD_ISSUE - 1, D_S[j].drv_id); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/cdrom/sjcd.c linux-2.5/drivers/cdrom/sjcd.c --- linux-2.5.5/drivers/cdrom/sjcd.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/cdrom/sjcd.c Thu Feb 21 00:25:48 2002 @@ -1694,7 +1694,7 @@ return (-EIO); } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST,&sjcd_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_sjcd_request, &sjcd_lock); register_disk(NULL, mk_kdev(MAJOR_NR, 0), 1, &sjcd_fops, 0); if (check_region(sjcd_base, 4)) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/cdrom/sonycd535.c linux-2.5/drivers/cdrom/sonycd535.c --- linux-2.5.5/drivers/cdrom/sonycd535.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/cdrom/sonycd535.c Thu Feb 21 01:26:10 2002 @@ -1596,7 +1596,9 @@ MAJOR_NR, CDU535_MESSAGE_NAME); return -EIO; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &sonycd535_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), + do_cdu535_request, + &sonycd535_lock); blksize_size[MAJOR_NR] = &sonycd535_block_size; sony_toc = (struct s535_sony_toc *) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/Config.help linux-2.5/drivers/char/Config.help --- linux-2.5.5/drivers/char/Config.help Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/char/Config.help Tue Feb 26 20:09:24 2002 @@ -425,6 +425,24 @@ read . The module will be called istallion.o. +CONFIG_SERIAL_TX3912 + The TX3912 is a Toshiba RISC processor based o the MIPS 3900 core; + see . + Say Y here to enable kernel support for the on-board serial port. + +CONFIG_SERIAL_TX3912_CONSOLE + The TX3912 is a Toshiba RISC processor based o the MIPS 3900 core; + see . + Say Y here to direct console I/O to the on-board serial port. + +CONFIG_AU1000_SERIAL_CONSOLE + If you have an Alchemy AU1000 processor (MIPS based) and you want + to use a console on a serial port, say Y. Otherwise, say N. + +CONFIG_AU1000_UART + If you have an Alchemy AU1000 processor (MIPS based) and you want + to use serial ports, say Y. Otherwise, say N. + CONFIG_SYNCLINK Provides support for the SyncLink ISA and PCI multiprotocol serial adapters. These adapters support asynchronous and HDLC bit @@ -941,6 +959,11 @@ The module is called mixcomwd.o. If you want to compile it as a module, say M here and read . Most people will say N. + +CONFIG_EUROTECH_WDT + Enable support for the watchdog timer on the Eurotech CPU-1220 and + CPU-1410 cards. These are PC/104 SBCs. Spec sheets and product + information are at . CONFIG_IB700_WDT This is the driver for the hardware watchdog on the IB700 Single diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/Config.in linux-2.5/drivers/char/Config.in --- linux-2.5.5/drivers/char/Config.in Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/char/Config.in Sun Mar 3 17:54:35 2002 @@ -62,6 +62,39 @@ tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION fi + bool ' TX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912 + dep_bool ' Console on TX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912 + bool ' Enable Au1000 UART Support' CONFIG_AU1000_UART + if [ "$CONFIG_AU1000_UART" = "y" ]; then + bool ' Enable Au1000 serial console' CONFIG_AU1000_SERIAL_CONSOLE + fi + bool 'TXx927 SIO support' CONFIG_TXX927_SERIAL + if [ "$CONFIG_TXX927_SERIAL" = "y" ]; then + bool 'TXx927 SIO Console support' CONFIG_TXX927_SERIAL_CONSOLE + fi + if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then + bool ' Support for sb1250 onchip DUART' CONFIG_SIBYTE_SB1250_DUART + if [ "$CONFIG_SIBYTE_SB1250_DUART" = "y" ]; then + bool ' Console on SB1250 DUART' CONFIG_SIBYTE_SB1250_DUART_CONSOLE + if [ "$CONFIG_SIBYTE_SB1250_DUART_CONSOLE" = "y" ]; then + define_bool CONFIG_SERIAL_CONSOLE y + fi + int ' Output buffers size (in bytes)' CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE 1024 + bool ' Leave port 1 alone (for kgdb or audio)' CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1 + fi + fi +fi +if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then + tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232 +fi +if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then + bool 'DC21285 serial port support' CONFIG_SERIAL_21285 + if [ "$CONFIG_SERIAL_21285" = "y" ]; then + if [ "$CONFIG_OBSOLETE" = "y" ]; then + bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD + fi + bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE + fi if [ "$CONFIG_MIPS" = "y" ]; then bool ' TMPTX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912 dep_bool ' Console on TMPTX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912 @@ -71,7 +104,7 @@ fi fi fi -if [ "$CONFIG_IT8712" = "y" ]; then +if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then define_bool CONFIG_IT8172_CIR y @@ -81,17 +114,12 @@ bool 'Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0 bool 'Enable Smart Card Reader 1 Support ' CONFIG_IT8172_SCR1 fi -if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then - tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232 -fi -if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then - bool 'DC21285 serial port support' CONFIG_SERIAL_21285 - if [ "$CONFIG_SERIAL_21285" = "y" ]; then - if [ "$CONFIG_OBSOLETE" = "y" ]; then - bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD - fi - bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE +if [ "$CONFIG_MIPS_IVR" = "y" ]; then + bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD + if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then + define_bool CONFIG_IT8172_CIR y fi + bool 'Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0 fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then @@ -107,26 +135,6 @@ source drivers/i2c/Config.in -mainmenu_option next_comment -comment 'Mice' -tristate 'Bus Mouse Support' CONFIG_BUSMOUSE -if [ "$CONFIG_BUSMOUSE" != "n" ]; then - dep_tristate ' ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE - dep_tristate ' Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE - dep_tristate ' Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE - if [ "$CONFIG_ADB" = "y" -a "$CONFIG_ADB_KEYBOARD" = "y" ]; then - dep_tristate ' Apple Desktop Bus mouse support (old driver)' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE - fi -fi - -tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE -if [ "$CONFIG_MOUSE" != "n" ]; then - bool ' PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE - tristate ' C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE - tristate ' PC110 digitizer pad support' CONFIG_PC110_PAD -fi -endmenu - tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE if [ "$CONFIG_QIC02_TAPE" != "n" ]; then bool ' Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF @@ -169,6 +177,7 @@ tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT tristate ' W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT + dep_tristate ' Indy/I2 Hardware Watchdog' CONFIG_INDYDOG $CONFIG_SGI_IP22 fi endmenu @@ -222,9 +231,11 @@ if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then source drivers/char/pcmcia/Config.in fi - -if [ "$CONFIG_X86" = "y" ]; then - tristate 'ACP Modem (Mwave) support' CONFIG_MWAVE +if [ "$CONFIG_MIPS_AU1000" = "y" ]; then + tristate ' Alchemy Au1000 GPIO device support' CONFIG_AU1000_GPIO + tristate ' Au1000/ADS7846 touchscreen support' CONFIG_TS_AU1000_ADS7846 +fi +if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then + tristate ' ITE GPIO' CONFIG_ITE_GPIO fi - endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/Makefile linux-2.5/drivers/char/Makefile --- linux-2.5.5/drivers/char/Makefile Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/char/Makefile Sun Mar 3 17:54:35 2002 @@ -21,9 +21,10 @@ # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := busmouse.o console.o keyboard.o sysrq.o \ +export-objs := busmouse.o vt.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o \ - sonypi.o tty_io.o tty_ioctl.o generic_serial.o + sonypi.o tty_io.o tty_ioctl.o generic_serial.o \ + au1000_gpio.o rtc.o mod-subdirs := ftape drm pcmcia @@ -31,13 +32,11 @@ KEYMAP =defkeymap.o KEYBD =pc_keyb.o -CONSOLE =console.o SERIAL =serial.o ifeq ($(ARCH),s390) KEYMAP = KEYBD = - CONSOLE = SERIAL = endif @@ -50,7 +49,6 @@ ifeq ($(ARCH),s390x) KEYMAP = KEYBD = - CONSOLE = SERIAL = endif @@ -75,28 +73,23 @@ ifeq ($(ARCH),sh) KEYMAP = KEYBD = - CONSOLE = ifeq ($(CONFIG_SH_HP600),y) KEYMAP = defkeymap.o KEYBD = scan_keyb.o hp600_keyb.o - CONSOLE = console.o endif ifeq ($(CONFIG_SH_DMIDA),y) # DMIDA does not connect the HD64465 PS/2 keyboard port # but we allow for USB keyboards to be plugged in. KEYMAP = defkeymap.o KEYBD = # hd64465_keyb.o pc_keyb.o - CONSOLE = console.o endif ifeq ($(CONFIG_SH_EC3104),y) KEYMAP = defkeymap.o KEYBD = ec3104_keyb.o - CONSOLE = console.o endif ifeq ($(CONFIG_SH_DREAMCAST),y) KEYMAP = defkeymap.o KEYBD = - CONSOLE = console.o endif endif @@ -124,12 +117,17 @@ KEYMAP = qtronixmap.o endif -obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o +ifeq ($(CONFIG_DUMMY_KEYB),y) + KEYBD = dummy_keyb.o +endif + +obj-$(CONFIG_VT) += vt.o vt_ioctl.o decvte.o vc_screen.o consolemap.o consolemap_deftbl.o selection.o obj-$(CONFIG_SERIAL) += $(SERIAL) obj-$(CONFIG_SERIAL_ACPI) += acpi_serial.o obj-$(CONFIG_SERIAL_21285) += serial_21285.o obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o +obj-$(CONFIG_TS_AU1000_ADS7846) += au1000_ts.o ifndef CONFIG_SUN_KEYBOARD obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD) @@ -147,6 +145,7 @@ obj-$(CONFIG_CYCLADES) += cyclades.o obj-$(CONFIG_STALLION) += stallion.o obj-$(CONFIG_ISTALLION) += istallion.o +obj-$(CONFIG_SIBYTE_SB1250_DUART) += sb1250_duart.o obj-$(CONFIG_COMPUTONE) += ip2.o ip2main.o obj-$(CONFIG_RISCOM8) += riscom8.o obj-$(CONFIG_ISI) += isicom.o @@ -164,11 +163,10 @@ obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o +obj-$(CONFIG_TXX927_SERIAL) += serial_txx927.o subdir-$(CONFIG_RIO) += rio -obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o -obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o obj-$(CONFIG_PRINTER) += lp.o obj-$(CONFIG_BUSMOUSE) += busmouse.o @@ -176,12 +174,7 @@ obj-$(CONFIG_R3964) += n_r3964.o obj-$(CONFIG_APPLICOM) += applicom.o obj-$(CONFIG_SONYPI) += sonypi.o -obj-$(CONFIG_MS_BUSMOUSE) += msbusmouse.o -obj-$(CONFIG_82C710_MOUSE) += qpmouse.o -obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o obj-$(CONFIG_ATARIMOUSE) += atarimouse.o -obj-$(CONFIG_ADBMOUSE) += adbmouse.o -obj-$(CONFIG_PC110_PAD) += pc110pad.o obj-$(CONFIG_RTC) += rtc.o obj-$(CONFIG_EFI_RTC) += efirtc.o ifeq ($(CONFIG_PPC),) @@ -191,6 +184,9 @@ obj-$(CONFIG_I8K) += i8k.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_INTEL_RNG) += i810_rng.o +obj-$(CONFIG_ITE_GPIO) += ite_gpio.o +obj-$(CONFIG_AU1000_GPIO) += au1000_gpio.o +obj-$(CONFIG_COBALT_LCD) += lcd.o obj-$(CONFIG_QIC02_TAPE) += tpqic02.o @@ -229,6 +225,7 @@ obj-$(CONFIG_SH_WDT) += shwdt.o obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o +obj-$(CONFIG_INDYDOG) += indydog.o subdir-$(CONFIG_MWAVE) += mwave ifeq ($(CONFIG_MWAVE),y) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/acquirewdt.c linux-2.5/drivers/char/acquirewdt.c --- linux-2.5.5/drivers/char/acquirewdt.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/char/acquirewdt.c Sun Jan 13 22:15:01 2002 @@ -17,6 +17,9 @@ * * (c) Copyright 1995 Alan Cox * + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Can't add timeout - driver doesn't allow changing value */ #include @@ -50,8 +53,14 @@ #define WDT_STOP 0x43 #define WDT_START 0x443 -#define WD_TIMO (100*60) /* 1 minute */ +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); /* * Kernel methods. @@ -126,10 +135,13 @@ spin_unlock(&acq_lock); return -EBUSY; } + if (nowayout) { + MOD_INC_USE_COUNT; + } /* * Activate */ - + acq_is_open=1; inb_p(WDT_START); spin_unlock(&acq_lock); @@ -144,9 +156,9 @@ if(minor(inode->i_rdev)==WATCHDOG_MINOR) { spin_lock(&acq_lock); -#ifndef CONFIG_WATCHDOG_NOWAYOUT - inb_p(WDT_STOP); -#endif + if (!nowayout) { + inb_p(WDT_STOP); + } acq_is_open=0; spin_unlock(&acq_lock); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/adbmouse.c linux-2.5/drivers/char/adbmouse.c --- linux-2.5.5/drivers/char/adbmouse.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/char/adbmouse.c Thu Jan 1 00:00:00 1970 @@ -1,209 +0,0 @@ -/* - * Macintosh ADB Mouse driver for Linux - * - * 27 Oct 1997 Michael Schmitz - * logitech fixes by anthony tong - * further hacking by Paul Mackerras - * - * Apple mouse protocol according to: - * - * Device code shamelessly stolen from: - */ -/* - * Atari Mouse Driver for Linux - * by Robert de Vries (robert@and.nl) 19Jul93 - * - * 16 Nov 1994 Andreas Schwab - * Compatibility with busmouse - * Support for three button mouse (shamelessly stolen from MiNT) - * third button wired to one of the joystick directions on joystick 1 - * - * 1996/02/11 Andreas Schwab - * Module support - * Allow multiple open's - * - * Converted to use new generic busmouse code. 11 July 1998 - * Russell King - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __powerpc__ -#include -#endif -#if defined(__mc68000__) || defined(MODULE) -#include -#endif - -#include "busmouse.h" - -static int msedev; -static unsigned char adb_mouse_buttons[16]; - -extern void (*adb_mouse_interrupt_hook)(unsigned char *, int); -extern int adb_emulate_buttons; -extern int adb_button2_keycode; -extern int adb_button3_keycode; - -/* - * XXX: need to figure out what ADB mouse packets mean ... - * This is the stuff stolen from the Atari driver ... - */ -static void adb_mouse_interrupt(unsigned char *buf, int nb) -{ - int buttons, id; - char dx, dy; - - /* - Handler 1 -- 100cpi original Apple mouse protocol. - Handler 2 -- 200cpi original Apple mouse protocol. - - For Apple's standard one-button mouse protocol the data array will - contain the following values: - - BITS COMMENTS - data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. - data[1] = bxxx xxxx First button and x-axis motion. - data[2] = byyy yyyy Second button and y-axis motion. - - Handler 4 -- Apple Extended mouse protocol. - - For Apple's 3-button mouse protocol the data array will contain the - following values: - - BITS COMMENTS - data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. - data[1] = bxxx xxxx Left button and x-axis motion. - data[2] = byyy yyyy Second button and y-axis motion. - data[3] = byyy bxxx Third button and fourth button. - Y is additiona. high bits of y-axis motion. - X is additional high bits of x-axis motion. - - 'buttons' here means 'button down' states! - Button 1 (left) : bit 2, busmouse button 3 - Button 2 (right) : bit 0, busmouse button 1 - Button 3 (middle): bit 1, busmouse button 2 - */ - - /* x/y and buttons swapped */ - - id = (buf[0] >> 4) & 0xf; - - buttons = adb_mouse_buttons[id]; - - /* button 1 (left, bit 2) */ - buttons = (buttons & 3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */ - - /* button 2 (middle) */ - buttons = (buttons & 5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */ - - /* button 3 (right) present? - * on a logitech mouseman, the right and mid buttons sometimes behave - * strangely until they both have been pressed after booting. */ - /* data valid only if extended mouse format ! */ - if (nb >= 4) - buttons = (buttons & 6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */ - - adb_mouse_buttons[id] = buttons; - - /* a button is down if it is down on any mouse */ - for (id = 0; id < 16; ++id) - buttons &= adb_mouse_buttons[id]; - - dx = ((buf[2] & 0x7f) < 64 ? (buf[2] & 0x7f) : (buf[2] & 0x7f) - 128); - dy = ((buf[1] & 0x7f) < 64 ? (buf[1] & 0x7f) : (buf[1] & 0x7f) - 128); - busmouse_add_movementbuttons(msedev, dx, -dy, buttons); - - if (console_loglevel >= 8) - printk(" %X %X %X dx %d dy %d \n", - buf[1], buf[2], buf[3], dx, dy); -} - -static int release_mouse(struct inode *inode, struct file *file) -{ - adb_mouse_interrupt_hook = NULL; - /* - * FIXME?: adb_mouse_interrupt_hook may still be executing - * on another CPU. - */ - return 0; -} - -static int open_mouse(struct inode *inode, struct file *file) -{ - adb_mouse_interrupt_hook = adb_mouse_interrupt; - return 0; -} - -static struct busmouse adb_mouse = -{ - ADB_MOUSE_MINOR, "adbmouse", THIS_MODULE, open_mouse, release_mouse, 7 -}; - -static int __init adb_mouse_init(void) -{ -#ifdef __powerpc__ - if ((_machine != _MACH_chrp) && (_machine != _MACH_Pmac)) - return -ENODEV; -#endif -#ifdef __mc68000__ - if (!MACH_IS_MAC) - return -ENODEV; -#endif - /* all buttons up */ - memset(adb_mouse_buttons, 7, sizeof(adb_mouse_buttons)); - - msedev = register_busmouse(&adb_mouse); - if (msedev < 0) - printk(KERN_WARNING "Unable to register ADB mouse driver.\n"); - else - printk(KERN_INFO "Macintosh ADB mouse driver installed.\n"); - - return msedev < 0 ? msedev : 0; -} - -#ifndef MODULE - -/* - * XXX this function is misnamed. - * It is called if the kernel is booted with the adb_buttons=xxx - * option, which is about using ADB keyboard buttons to emulate - * mouse buttons. -- paulus - */ -static int __init adb_mouse_setup(char *str) -{ - int ints[4]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - if (ints[0] >= 1) { - adb_emulate_buttons = ints[1]; - if (ints[0] >= 2) - adb_button2_keycode = ints[2]; - if (ints[0] >= 3) - adb_button3_keycode = ints[3]; - } - return 1; -} - -__setup("adb_buttons=", adb_mouse_setup); - -#endif /* !MODULE */ - -static void __exit adb_mouse_cleanup(void) -{ - unregister_busmouse(msedev); -} - -module_init(adb_mouse_init); -module_exit(adb_mouse_cleanup); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/advantechwdt.c linux-2.5/drivers/char/advantechwdt.c --- linux-2.5.5/drivers/char/advantechwdt.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/char/advantechwdt.c Sun Jan 13 22:15:01 2002 @@ -20,6 +20,9 @@ * * (c) Copyright 1995 Alan Cox * + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default */ #include @@ -56,8 +59,7 @@ * the manual says WDT_STOP is 0x43, not 0x443). * (0x43 is also a write-only control register for the 8254 timer!) * - * TODO: module parameters to set the I/O port addresses and NOWAYOUT - * option at load time. + * TODO: module parameters to set the I/O port addresses */ #define WDT_STOP 0x443 @@ -65,6 +67,19 @@ #define WD_TIMO 60 /* 1 minute */ +static int timeout = WD_TIMO; /* in seconds */ +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + /* * Kernel methods. */ @@ -73,7 +88,7 @@ advwdt_ping(void) { /* Write a watchdog value */ - outb_p(WD_TIMO, WDT_START); + outb_p(timeout, WDT_START); } static ssize_t @@ -135,6 +150,9 @@ spin_unlock(&advwdt_lock); return -EBUSY; } + if (nowayout) { + MOD_INC_USE_COUNT; + } /* * Activate */ @@ -153,9 +171,9 @@ { if (minor(inode->i_rdev) == WATCHDOG_MINOR) { spin_lock(&advwdt_lock); -#ifndef CONFIG_WATCHDOG_NOWAYOUT - inb_p(WDT_STOP); -#endif + if (!nowayout) { + inb_p(WDT_STOP); + } advwdt_is_open = 0; spin_unlock(&advwdt_lock); } @@ -207,11 +225,21 @@ 0 }; +static void __init +advwdt_validate_timeout(void) +{ + if (timeout < 1 || timeout > 63) { + timeout = WD_TIMO; + printk(KERN_INFO "advantechwdt: timeout value must be 1 <= x <= 63, using %d\n", timeout); + } +} + static int __init advwdt_init(void) { printk("WDT driver for Advantech single board computer initialising.\n"); + advwdt_validate_timeout(); spin_lock_init(&advwdt_lock); misc_register(&advwdt_miscdev); #if WDT_START != WDT_STOP diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/agp/agpgart_be.c linux-2.5/drivers/char/agp/agpgart_be.c --- linux-2.5.5/drivers/char/agp/agpgart_be.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/char/agp/agpgart_be.c Sun Mar 3 18:29:27 2002 @@ -397,7 +397,7 @@ static void agp_generic_agp_enable(u32 mode) { struct pci_dev *device = NULL; - u32 command, scratch, cap_id; + u32 command, scratch; u8 cap_ptr; pci_read_config_dword(agp_bridge.dev, @@ -410,34 +410,8 @@ */ - pci_for_each_dev(device) - { - /* - * Enable AGP devices. Most will be VGA display but - * some may be coprocessors on non VGA devices too - */ - - if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) && - (device->class != (PCI_CLASS_PROCESSOR_CO << 8))) - continue; - - pci_read_config_dword(device, 0x04, &scratch); - - if (!(scratch & 0x00100000)) - continue; - - pci_read_config_byte(device, 0x34, &cap_ptr); - - if (cap_ptr != 0x00) { - do { - pci_read_config_dword(device, - cap_ptr, &cap_id); - - if ((cap_id & 0xff) != 0x02) - cap_ptr = (cap_id >> 8) & 0xff; - } - while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); - } + pci_for_each_dev(device) { + cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); if (cap_ptr != 0x00) { /* * Ok, here we have a AGP device. Disable impossible @@ -506,25 +480,8 @@ * command registers. */ - while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, - device)) != NULL) { - pci_read_config_dword(device, 0x04, &scratch); - - if (!(scratch & 0x00100000)) - continue; - - pci_read_config_byte(device, 0x34, &cap_ptr); - - if (cap_ptr != 0x00) { - do { - pci_read_config_dword(device, - cap_ptr, &cap_id); - - if ((cap_id & 0xff) != 0x02) - cap_ptr = (cap_id >> 8) & 0xff; - } - while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); - } + pci_for_each_dev(device) { + cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); if (cap_ptr != 0x00) pci_write_config_dword(device, cap_ptr + 8, command); } @@ -622,7 +579,7 @@ table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) - set_bit(PG_reserved, &page->flags); + SetPageReserved(page); agp_bridge.gatt_table_real = (unsigned long *) table; CACHE_FLUSH(); @@ -632,7 +589,7 @@ if (agp_bridge.gatt_table == NULL) { for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) - clear_bit(PG_reserved, &page->flags); + ClearPageReserved(page); free_pages((unsigned long) table, page_order); @@ -699,7 +656,7 @@ table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) - clear_bit(PG_reserved, &page->flags); + ClearPageReserved(page); free_pages((unsigned long) agp_bridge.gatt_table_real, page_order); return 0; @@ -809,11 +766,11 @@ struct page * page; page = alloc_page(GFP_KERNEL); - if (page == NULL) { + if (page == NULL) return 0; - } - atomic_inc(&page->count); - set_bit(PG_locked, &page->flags); + + get_page(page); + LockPage(page); atomic_inc(&agp_bridge.current_memory_agp); return (unsigned long)page_address(page); } @@ -823,14 +780,12 @@ void *pt = (void *) addr; struct page *page; - if (pt == NULL) { + if (pt == NULL) return; - } - + page = virt_to_page(pt); - atomic_dec(&page->count); - clear_bit(PG_locked, &page->flags); - wake_up_page(page); + put_page(page); + UnlockPage(page); free_page((unsigned long) pt); atomic_dec(&agp_bridge.current_memory_agp); } @@ -2278,13 +2233,12 @@ if (page_map->real == NULL) { return -ENOMEM; } - set_bit(PG_reserved, &virt_to_page(page_map->real)->flags); + SetPageReserved(virt_to_page(page_map->real)); CACHE_FLUSH(); page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), PAGE_SIZE); if (page_map->remapped == NULL) { - clear_bit(PG_reserved, - &virt_to_page(page_map->real)->flags); + ClearPageReserved(virt_to_page(page_map->real)); free_page((unsigned long) page_map->real); page_map->real = NULL; return -ENOMEM; @@ -2301,8 +2255,7 @@ static void amd_free_page_map(amd_page_map *page_map) { iounmap(page_map->remapped); - clear_bit(PG_reserved, - &virt_to_page(page_map->real)->flags); + ClearPageReserved(virt_to_page(page_map->real)); free_page((unsigned long) page_map->real); } @@ -2790,8 +2743,8 @@ if (page == NULL) return 0; - atomic_inc(&page->count); - set_bit(PG_locked, &page->flags); + get_page(page); + LockPage(page); atomic_inc(&agp_bridge.current_memory_agp); global_cache_flush(); @@ -2826,9 +2779,8 @@ } page = virt_to_page(pt); - atomic_dec(&page->count); - clear_bit(PG_locked, &page->flags); - wake_up_page(page); + put_page(page); + UnlockPage(page); free_page((unsigned long) pt); atomic_dec(&agp_bridge.current_memory_agp); } @@ -2910,13 +2862,12 @@ if (page_map->real == NULL) { return -ENOMEM; } - set_bit(PG_reserved, &virt_to_page(page_map->real)->flags); + SetPageReserved(virt_to_page(page_map->real)); CACHE_FLUSH(); page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), PAGE_SIZE); if (page_map->remapped == NULL) { - clear_bit(PG_reserved, - &virt_to_page(page_map->real)->flags); + ClearPageReserved(virt_to_page(page_map->real)); free_page((unsigned long) page_map->real); page_map->real = NULL; return -ENOMEM; @@ -2933,8 +2884,7 @@ static void serverworks_free_page_map(serverworks_page_map *page_map) { iounmap(page_map->remapped); - clear_bit(PG_reserved, - &virt_to_page(page_map->real)->flags); + ClearPageReserved(virt_to_page(page_map->real)); free_page((unsigned long) page_map->real); } @@ -3324,24 +3274,8 @@ */ - pci_for_each_dev(device) - { - /* - * Enable AGP devices. Most will be VGA display but - * some may be coprocessors on non VGA devices too - */ - - if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) && - (device->class != (PCI_CLASS_PROCESSOR_CO << 8))) - continue; - - pci_read_config_dword(device, 0x04, &scratch); - - if (!(scratch & 0x00100000)) - continue; - - pci_read_config_byte(device, 0x34, &cap_ptr); - + pci_for_each_dev(device) { + cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); if (cap_ptr != 0x00) { do { pci_read_config_dword(device, @@ -3419,25 +3353,8 @@ * command registers. */ - while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, - device)) != NULL) { - pci_read_config_dword(device, 0x04, &scratch); - - if (!(scratch & 0x00100000)) - continue; - - pci_read_config_byte(device, 0x34, &cap_ptr); - - if (cap_ptr != 0x00) { - do { - pci_read_config_dword(device, - cap_ptr, &cap_id); - - if ((cap_id & 0xff) != 0x02) - cap_ptr = (cap_id >> 8) & 0xff; - } - while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); - } + pci_for_each_dev(device) { + cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); if (cap_ptr != 0x00) pci_write_config_dword(device, cap_ptr + 8, command); } @@ -3887,7 +3804,6 @@ { struct pci_dev *dev = NULL; u8 cap_ptr = 0x00; - u32 cap_id, scratch; if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) == NULL) return -ENODEV; @@ -4028,20 +3944,7 @@ #endif /* CONFIG_AGP_SWORKS */ /* find capndx */ - pci_read_config_dword(dev, 0x04, &scratch); - if (!(scratch & 0x00100000)) - return -ENODEV; - - pci_read_config_byte(dev, 0x34, &cap_ptr); - if (cap_ptr != 0x00) { - do { - pci_read_config_dword(dev, cap_ptr, &cap_id); - - if ((cap_id & 0xff) != 0x02) - cap_ptr = (cap_id >> 8) & 0xff; - } - while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); - } + cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); if (cap_ptr == 0x00) return -ENODEV; agp_bridge.capndx = cap_ptr; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/amd768_rng.c linux-2.5/drivers/char/amd768_rng.c --- linux-2.5.5/drivers/char/amd768_rng.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/amd768_rng.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,295 @@ +/* + Hardware driver for the AMD 768 Random Number Generator (RNG) + (c) Copyright 2001 Red Hat Inc + + derived from + + Hardware driver for Intel i810 Random Number Generator (RNG) + Copyright 2000,2001 Jeff Garzik + Copyright 2000,2001 Philipp Rumpf + + Please read Documentation/i810_rng.txt for details on use. + + ---------------------------------------------------------- + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. + + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * core module and version information + */ +#define RNG_VERSION "0.1.0" +#define RNG_MODULE_NAME "amd768_rng" +#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION +#define PFX RNG_MODULE_NAME ": " + + +/* + * debugging macros + */ +#undef RNG_DEBUG /* define to enable copious debugging info */ + +#ifdef RNG_DEBUG +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#undef RNG_NDEBUG /* define to disable lightweight runtime checks */ +#ifdef RNG_NDEBUG +#define assert(expr) +#else +#define assert(expr) \ + if(!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#endif + +#define RNG_MISCDEV_MINOR 183 /* official */ + +/* + * various RNG status variables. they are globals + * as we only support a single RNG device + */ + +static u32 pmbase; /* PMxx I/O base */ +static struct semaphore rng_open_sem; /* Semaphore for serializing rng_open/release */ + + +/* + * inlined helper functions for accessing RNG registers + */ + +static inline int rng_data_present (void) +{ + return inl(pmbase+0xF4) & 1; +} + + +static inline int rng_data_read (void) +{ + return inl(pmbase+0xF0); +} + +static int rng_dev_open (struct inode *inode, struct file *filp) +{ + if ((filp->f_mode & FMODE_READ) == 0) + return -EINVAL; + if (filp->f_mode & FMODE_WRITE) + return -EINVAL; + + /* wait for device to become free */ + if (filp->f_flags & O_NONBLOCK) { + if (down_trylock (&rng_open_sem)) + return -EAGAIN; + } else { + if (down_interruptible (&rng_open_sem)) + return -ERESTARTSYS; + } + return 0; +} + + +static int rng_dev_release (struct inode *inode, struct file *filp) +{ + up(&rng_open_sem); + return 0; +} + + +static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size, + loff_t * offp) +{ + static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; + int have_data; + u32 data = 0; + ssize_t ret = 0; + + while (size) { + spin_lock(&rng_lock); + + have_data = 0; + if (rng_data_present()) { + data = rng_data_read(); + have_data = 4; + } + + spin_unlock (&rng_lock); + + while (have_data > 0) { + if (put_user((u8)data, buf++)) { + ret = ret ? : -EFAULT; + break; + } + size--; + ret++; + have_data--; + data>>=8; + } + + if (filp->f_flags & O_NONBLOCK) + return ret ? : -EAGAIN; + + if(current->need_resched) + { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + else + udelay(200); /* FIXME: We could poll for 250uS ?? */ + + if (signal_pending (current)) + return ret ? : -ERESTARTSYS; + } + return ret; +} + + +static struct file_operations rng_chrdev_ops = { + owner: THIS_MODULE, + open: rng_dev_open, + release: rng_dev_release, + read: rng_dev_read, +}; + + +static struct miscdevice rng_miscdev = { + RNG_MISCDEV_MINOR, + RNG_MODULE_NAME, + &rng_chrdev_ops, +}; + + +/* + * rng_init_one - look for and attempt to init a single RNG + */ +static int __init rng_init_one (struct pci_dev *dev) +{ + int rc; + u8 rnen; + + DPRINTK ("ENTER\n"); + + rc = misc_register (&rng_miscdev); + if (rc) { + printk (KERN_ERR PFX "cannot register misc device\n"); + DPRINTK ("EXIT, returning %d\n", rc); + goto err_out; + } + + pci_read_config_dword(dev, 0x58, &pmbase); + + pmbase&=0x0000FF00; + + if(pmbase == 0) + { + printk (KERN_ERR PFX "power management base not set\n"); + DPRINTK ("EXIT, returning %d\n", rc); + goto err_out_free_miscdev; + } + + pci_read_config_byte(dev, 0x40, &rnen); + rnen|=(1<<7); /* RNG on */ + pci_write_config_byte(dev, 0x40, rnen); + + pci_read_config_byte(dev, 0x41, &rnen); + rnen|=(1<<7); /* PMIO enable */ + pci_write_config_byte(dev, 0x41, rnen); + + printk(KERN_INFO PFX "AMD768 system management I/O registers at 0x%X.\n", pmbase); + DPRINTK ("EXIT, returning 0\n"); + return 0; + +err_out_free_miscdev: + misc_deregister (&rng_miscdev); +err_out: + return rc; +} + + +/* + * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might one day + * want to register another driver on the same PCI id. + */ +static struct pci_device_id rng_pci_tbl[] __initdata = { + { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, +}; +MODULE_DEVICE_TABLE (pci, rng_pci_tbl); + + +MODULE_AUTHOR("Alan Cox, Jeff Garzik, Philipp Rumpf, Matt Sottek"); +MODULE_DESCRIPTION("AMD 768 Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL"); + + +/* + * rng_init - initialize RNG module + */ +static int __init rng_init (void) +{ + int rc; + struct pci_dev *pdev; + + DPRINTK ("ENTER\n"); + + init_MUTEX (&rng_open_sem); + + pci_for_each_dev(pdev) { + if (pci_match_device (rng_pci_tbl, pdev) != NULL) + goto match; + } + + DPRINTK ("EXIT, returning -ENODEV\n"); + return -ENODEV; + +match: + rc = rng_init_one (pdev); + if (rc) + return rc; + + printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +/* + * rng_init - shutdown RNG module + */ +static void __exit rng_cleanup (void) +{ + DPRINTK ("ENTER\n"); + misc_deregister (&rng_miscdev); + DPRINTK ("EXIT\n"); +} + + +module_init (rng_init); +module_exit (rng_cleanup); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/amigamouse.c linux-2.5/drivers/char/amigamouse.c --- linux-2.5.5/drivers/char/amigamouse.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/char/amigamouse.c Thu Jan 1 00:00:00 1970 @@ -1,213 +0,0 @@ -/* - * Amiga Mouse Driver for Linux 68k by Michael Rausch - * based upon: - * - * Logitech Bus Mouse Driver for Linux - * by James Banks - * - * Mods by Matthew Dillon - * calls verify_area() - * tracks better when X is busy or paging - * - * Heavily modified by David Giller - * changed from queue- to counter- driven - * hacked out a (probably incorrect) mouse_poll - * - * Modified again by Nathan Laredo to interface with - * 0.96c-pl1 IRQ handling changes (13JUL92) - * didn't bother touching poll code. - * - * Modified the poll() code blindly to conform to the VFS - * requirements. 92.07.14 - Linus. Somebody should test it out. - * - * Modified by Johan Myreen to make room for other mice (9AUG92) - * removed assignment chr_fops[10] = &mouse_fops; see mouse.c - * renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public. - * renamed this file mouse.c => busmouse.c - * - * Modified for use in the 1.3 kernels by Jes Sorensen. - * - * Moved the isr-allocation to the mouse_{open,close} calls, as there - * is no reason to service the mouse in the vertical blank isr if - * the mouse is not in use. Jes Sorensen - * - * Converted to use new generic busmouse code. 5 Apr 1998 - * Russell King - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "busmouse.h" - -#if AMIGA_OLD_INT -#define AMI_MSE_INT_ON() mouseint_allowed = 1 -#define AMI_MSE_INT_OFF() mouseint_allowed = 0 -static int mouseint_allowed; -#endif - -static int msedev; - -static void mouse_interrupt(int irq, void *dummy, struct pt_regs *fp) -{ - static int lastx=0, lasty=0; - int dx, dy; - int nx, ny; - unsigned char buttons; - - unsigned short joy0dat, potgor; - -#if AMIGA_OLD_INT - if(!mouseint_allowed) - return; - AMI_MSE_INT_OFF(); -#endif - - /* - * This routine assumes, just like Kickstart, that the mouse - * has not moved more than 127 ticks since last VBL. - */ - - joy0dat = custom.joy0dat; - - nx = joy0dat & 0xff; - ny = joy0dat >> 8; - - dx = nx - lastx; - if (dx < - 127) - dx = (256 + nx) - lastx; - - if (dx > 127) - dx = (nx - 256) - lastx; - - dy = ny - lasty; - if (dy < - 127) - dy = (256 + ny) - lasty; - - if (dy > 127) - dy = (ny - 256) - lasty; - - lastx = nx; - lasty = ny; - -#if 0 - dx = -lastdx; - dx += (lastdx = joy0dat & 0xff); - if (dx < -127) - dx = -255-dx; /* underrun */ - else - if (dx > 127) - dx = 255-dx; /* overflow */ - - dy = -lastdy; - dy += (lastdy = joy0dat >> 8); - if (dy < -127) - dy = -255-dy; - else - if (dy > 127) - dy = 255-dy; -#endif - - - potgor = custom.potgor; - buttons = (ciaa.pra & 0x40 ? 4 : 0) | /* left button; note that the bits are low-active, as are the expected results -> double negation */ -#if 1 - (potgor & 0x0100 ? 2 : 0) | /* middle button; emulation goes here */ -#endif - (potgor & 0x0400 ? 1 : 0); /* right button */ - - - busmouse_add_movementbuttons(msedev, dx, -dy, buttons); -#if AMIGA_OLD_INT - AMI_MSE_INT_ON(); -#endif -} - -/* - * close access to the mouse - */ - -static int release_mouse(struct inode * inode, struct file * file) -{ - free_irq(IRQ_AMIGA_VERTB, mouse_interrupt); -#if AMIGA_OLD_INT - AMI_MSE_INT_OFF(); -#endif - return 0; -} - -/* - * open access to the mouse, currently only one open is - * allowed. - */ - -static int open_mouse(struct inode * inode, struct file * file) -{ - /* - * use VBL to poll mouse deltas - */ - - if(request_irq(IRQ_AMIGA_VERTB, mouse_interrupt, 0, - "Amiga mouse", mouse_interrupt)) { - printk(KERN_INFO "Installing Amiga mouse failed.\n"); - return -EIO; - } - -#if AMIGA_OLD_INT - AMI_MSE_INT_ON(); -#endif - return 0; -} - -static struct busmouse amigamouse = { - AMIGAMOUSE_MINOR, "amigamouse", THIS_MODULE, open_mouse, release_mouse, 7 -}; - -static int __init amiga_mouse_init(void) -{ - if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE)) - return -ENODEV; - if (!request_mem_region(CUSTOM_PHYSADDR+10, 2, "amigamouse [Denise]")) - return -EBUSY; - - custom.joytest = 0; /* reset counters */ -#if AMIGA_OLD_INT - AMI_MSE_INT_OFF(); -#endif - msedev = register_busmouse(&amigamouse); - if (msedev < 0) - printk(KERN_WARNING "Unable to install Amiga mouse driver.\n"); - else - printk(KERN_INFO "Amiga mouse installed.\n"); - return msedev < 0 ? msedev : 0; -} - -static void __exit amiga_mouse_exit(void) -{ - unregister_busmouse(msedev); - release_mem_region(CUSTOM_PHYSADDR+10, 2); -} - -module_init(amiga_mouse_init); -module_exit(amiga_mouse_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/amiserial.c linux-2.5/drivers/char/amiserial.c --- linux-2.5.5/drivers/char/amiserial.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/char/amiserial.c Sun Jan 6 01:38:26 2002 @@ -2143,7 +2143,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/applicom.c linux-2.5/drivers/char/applicom.c --- linux-2.5.5/drivers/char/applicom.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/char/applicom.c Thu Feb 14 00:36:31 2002 @@ -36,7 +36,7 @@ #if LINUX_VERSION_CODE < 0x20300 /* These probably want adding to */ -#define init_waitqueue_head(x) do { *(x) = NULL; } while (0); +#define init_waitqueue_head(x) do { *(x) = NULL; } while (0) #define PCI_BASE_ADDRESS(dev) (dev->base_address[0]) #define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x #define __setup(x,y) /* */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/atixlmouse.c linux-2.5/drivers/char/atixlmouse.c --- linux-2.5.5/drivers/char/atixlmouse.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/char/atixlmouse.c Thu Jan 1 00:00:00 1970 @@ -1,151 +0,0 @@ -/* - * ATI XL Bus Mouse Driver for Linux - * by Bob Harris (rth@sparta.com) - * - * Uses VFS interface for linux 0.98 (01OCT92) - * - * Modified by Chris Colohan (colohan@eecg.toronto.edu) - * Modularised 8-Sep-95 Philip Blundell - * - * Converted to use new generic busmouse code. 5 Apr 1998 - * Russell King - * - * version 0.3a - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "busmouse.h" - -#define ATIXL_MOUSE_IRQ 5 /* H/W interrupt # set up on ATIXL board */ -#define ATIXL_BUSMOUSE 3 /* Minor device # (mknod c 10 3 /dev/bm) */ - -/* ATI XL Inport Busmouse Definitions */ - -#define ATIXL_MSE_DATA_PORT 0x23d -#define ATIXL_MSE_SIGNATURE_PORT 0x23e -#define ATIXL_MSE_CONTROL_PORT 0x23c - -#define ATIXL_MSE_READ_BUTTONS 0x00 -#define ATIXL_MSE_READ_X 0x01 -#define ATIXL_MSE_READ_Y 0x02 - -/* Some nice ATI XL macros */ - -/* Select IR7, HOLD UPDATES (INT ENABLED), save X,Y */ -#define ATIXL_MSE_DISABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \ - outb( (0x20 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); } - -/* Select IR7, Enable updates (INT ENABLED) */ -#define ATIXL_MSE_ENABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \ - outb( (0xdf & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); } - -/* Select IR7 - Mode Register, NO INTERRUPTS */ -#define ATIXL_MSE_INT_OFF() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \ - outb( (0xe7 & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); } - -/* Select IR7 - Mode Register, DATA INTERRUPTS ENABLED */ -#define ATIXL_MSE_INT_ON() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \ - outb( (0x08 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); } - -/* Same general mouse structure */ - -static int msedev; - -static void mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - char dx, dy, buttons; - - ATIXL_MSE_DISABLE_UPDATE(); /* Note that interrupts are still enabled */ - outb(ATIXL_MSE_READ_X, ATIXL_MSE_CONTROL_PORT); /* Select IR1 - X movement */ - dx = inb( ATIXL_MSE_DATA_PORT); - outb(ATIXL_MSE_READ_Y, ATIXL_MSE_CONTROL_PORT); /* Select IR2 - Y movement */ - dy = inb( ATIXL_MSE_DATA_PORT); - outb(ATIXL_MSE_READ_BUTTONS, ATIXL_MSE_CONTROL_PORT); /* Select IR0 - Button Status */ - buttons = inb( ATIXL_MSE_DATA_PORT); - busmouse_add_movementbuttons(msedev, dx, -dy, buttons); - ATIXL_MSE_ENABLE_UPDATE(); -} - -static int release_mouse(struct inode * inode, struct file * file) -{ - ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */ - free_irq(ATIXL_MOUSE_IRQ, NULL); - return 0; -} - -static int open_mouse(struct inode * inode, struct file * file) -{ - if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL)) - return -EBUSY; - ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */ - return 0; -} - -static struct busmouse atixlmouse = { - ATIXL_BUSMOUSE, "atixl", THIS_MODULE, open_mouse, release_mouse, 0 -}; - -static int __init atixl_busmouse_init(void) -{ - unsigned char a,b,c; - - /* - * We must request the resource and claim it atomically - * nowdays. We can throw it away on error. Otherwise we - * may race another module load of the same I/O - */ - - if (!request_region(ATIXL_MSE_DATA_PORT, 3, "atixlmouse")) - return -EIO; - - a = inb( ATIXL_MSE_SIGNATURE_PORT ); /* Get signature */ - b = inb( ATIXL_MSE_SIGNATURE_PORT ); - c = inb( ATIXL_MSE_SIGNATURE_PORT ); - if (( a != b ) && ( a == c )) - printk(KERN_INFO "\nATI Inport "); - else - { - release_region(ATIXL_MSE_DATA_PORT,3); - return -EIO; - } - outb(0x80, ATIXL_MSE_CONTROL_PORT); /* Reset the Inport device */ - outb(0x07, ATIXL_MSE_CONTROL_PORT); /* Select Internal Register 7 */ - outb(0x0a, ATIXL_MSE_DATA_PORT); /* Data Interrupts 8+, 1=30hz, 2=50hz, 3=100hz, 4=200hz rate */ - - msedev = register_busmouse(&atixlmouse); - if (msedev < 0) - { - printk("Bus mouse initialisation error.\n"); - release_region(ATIXL_MSE_DATA_PORT,3); /* Was missing */ - } - else - printk("Bus mouse detected and installed.\n"); - return msedev < 0 ? msedev : 0; -} - -static void __exit atixl_cleanup (void) -{ - release_region(ATIXL_MSE_DATA_PORT, 3); - unregister_busmouse(msedev); -} - -module_init(atixl_busmouse_init); -module_exit(atixl_cleanup); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/au1000_gpio.c linux-2.5/drivers/char/au1000_gpio.c --- linux-2.5.5/drivers/char/au1000_gpio.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/au1000_gpio.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,270 @@ +/* + * FILE NAME au1000_gpio.c + * + * BRIEF MODULE DESCRIPTION + * Driver for Alchemy Au1000 GPIO. + * + * Author: MontaVista Software, Inc. + * Steve Longerbeam + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "0.01" + +static const struct { + u32 active_hi; + u32 avail_mask; +} pinfunc_to_avail[15] = { + {1, 0x7<<16}, // 0 = SSI0 / GPIO[18:16] + {-1, 0}, // 1 = AC97 / SSI1 + {1, 1<<19}, // 2 = IRDA / GPIO19 + {1, 1<<20}, // 3 = UART0 / GPIO20 + {1, 0x1f<<24}, // 4 = NIC2 / GPIO[28:24] + {1, 0x7<<29}, // 5 = I2S / GPIO[31:29] + {0, 1<<8}, // 6 = I2SDI / GPIO8 + {0, 0x3f<<9}, // 7 = UART3 / GPIO[14:9] + {0, 1<<15}, // 8 = IRFIRSEL / GPIO15 + {0, 1<<2}, // 9 = EXTCLK0 or OSC / GPIO2 + {0, 1<<3}, // 10 = EXTCLK1 / GPIO3 + {0, 1<<6}, // 11 = SMROMCKE / GPIO6 + {1, 1<<21}, // 12 = UART1 / GPIO21 + {1, 1<<22}, // 13 = UART2 / GPIO22 + {1, 1<<23} // 14 = UART3 / GPIO23 +}; + + +u32 get_au1000_avail_gpio_mask(void) +{ + int i; + u32 pinfunc = inl(SYS_PINFUNC); + u32 avail_mask = 0; // start with no gpio available + + // first, check for GPIO's reprogrammed as peripheral pins + for (i=0; i<15; i++) { + if (pinfunc_to_avail[i].active_hi < 0) + continue; + if (!(pinfunc_to_avail[i].active_hi ^ + ((pinfunc & (1< +#include + +#include +#include +#include +#include +#include +#include /* request_region */ +#include /* mark_bh */ +#include /* get_user,copy_to_user */ +#include +#include + +#define TS_NAME "au1000-ts" +#define TS_MAJOR 11 + +#define PFX TS_NAME +#define AU1000_TS_DEBUG 1 + +#ifdef AU1000_TS_DEBUG +#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg) +#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg) +#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg) + + +// SSI Status register bit defines +#define SSISTAT_BF (1<<4) +#define SSISTAT_OF (1<<3) +#define SSISTAT_UF (1<<2) +#define SSISTAT_DONE (1<<1) +#define SSISTAT_BUSY (1<<0) + +// SSI Interrupt Pending and Enable register bit defines +#define SSIINT_OI (1<<3) +#define SSIINT_UI (1<<2) +#define SSIINT_DI (1<<1) + +// SSI Address/Data register bit defines +#define SSIADAT_D (1<<24) +#define SSIADAT_ADDR_BIT 16 +#define SSIADAT_ADDR_MASK (0xff<pressure_eqn == PRESSURE_EQN_2) { + Rt = (ts->x_plate_ohms * ts->x_raw * + (4096 - ts->z1_raw)) / ts->z1_raw; + Rt -= (ts->y_plate_ohms * ts->y_raw); + Rt = (Rt + 2048) >> 12; // round up to nearest ohm + } else { + Rt = (ts->x_plate_ohms * ts->x_raw * + (ts->z2_raw - ts->z1_raw)) / ts->z1_raw; + Rt = (Rt + 2048) >> 12; // round up to nearest ohm + } + + // hysteresis + if (!ts->pendown && Rt > ts->pendown_thresh_ohms) + ts->pendown = 1; + else if (ts->pendown && Rt < ts->penup_thresh_ohms) + ts->pendown = 0; + + if (ts->pendown) { + // Pen is down + // Calculate calibrated X,Y + Xcal = ((ts->cal.xscale * ts->x_raw) >> 8) + ts->cal.xtrans; + Ycal = ((ts->cal.yscale * ts->y_raw) >> 8) + ts->cal.ytrans; + + event.x = (unsigned short)Xcal; + event.y = (unsigned short)Ycal; + event.pressure = (unsigned short)Rt; + + // add this event to the event queue + spin_lock_irqsave(&ts->lock, flags); + ts->event_buf[ts->nextIn++] = event; + if (ts->nextIn == EVENT_BUFSIZE) + ts->nextIn = 0; + if (ts->event_count < EVENT_BUFSIZE) { + ts->event_count++; + } else { + // throw out the oldest event + if (++ts->nextOut == EVENT_BUFSIZE) + ts->nextOut = 0; + } + spin_unlock_irqrestore(&ts->lock, flags); + + // async notify + if (ts->fasync) + kill_fasync(&ts->fasync, SIGIO, POLL_IN); + // wake up any read call + if (waitqueue_active(&ts->wait)) + wake_up_interruptible(&ts->wait); + } +} + + +/* + * Raw X,Y,pressure acquisition timer function. This triggers + * the start of a new acquisition. Its duration between calls + * is the touch screen polling rate. + */ +static void +au1000_acq_timer(unsigned long data) +{ + au1000_ts_t* ts = (au1000_ts_t*)data; + unsigned long flags; + + spin_lock_irqsave(&ts->lock, flags); + + // start acquisition with X coordinate + ts->acq_state = ACQ_X; + // start me up + outl(SSIADAT_D | (MEASURE_12BIT_X << SSIADAT_ADDR_BIT), SSI0_ADATA); + + // schedule next acquire + ts->acq_timer.expires = jiffies + HZ / 100; + add_timer(&ts->acq_timer); + + spin_unlock_irqrestore(&ts->lock, flags); +} + +static void +ssi0_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + au1000_ts_t *ts = (au1000_ts_t*)dev_id; + u32 stat, int_stat, data; + + spin_lock(&ts->lock); + + stat = inl(SSI0_STATUS); + // clear sticky status bits + outl(stat & (SSISTAT_OF|SSISTAT_UF|SSISTAT_DONE), SSI0_STATUS); + + int_stat = inl(SSI0_INT); + // clear sticky intr status bits + outl(int_stat & (SSIINT_OI|SSIINT_UI|SSIINT_DI), SSI0_INT); + + if ((int_stat & (SSIINT_OI|SSIINT_UI|SSIINT_DI)) != SSIINT_DI) { + if (int_stat & SSIINT_OI) + err("overflow"); + if (int_stat & SSIINT_UI) + err("underflow"); + spin_unlock(&ts->lock); + return; + } + + data = inl(SSI0_ADATA) & SSIADAT_DATA_MASK; + + switch (ts->acq_state) { + case IDLE: + break; + case ACQ_X: + ts->x_raw = data; + ts->acq_state = ACQ_Y; + // trigger Y acq + outl(SSIADAT_D | (MEASURE_12BIT_Y << SSIADAT_ADDR_BIT), + SSI0_ADATA); + break; + case ACQ_Y: + ts->y_raw = data; + ts->acq_state = ACQ_Z1; + // trigger Z1 acq + outl(SSIADAT_D | (MEASURE_12BIT_Z1 << SSIADAT_ADDR_BIT), + SSI0_ADATA); + break; + case ACQ_Z1: + ts->z1_raw = data; + if (ts->pressure_eqn == PRESSURE_EQN_2) { + // don't acq Z2, using 2nd eqn for touch pressure + ts->acq_state = IDLE; + // got the raw stuff, now mark BH + queue_task(&ts->chug_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } else { + ts->acq_state = ACQ_Z2; + // trigger Z2 acq + outl(SSIADAT_D | (MEASURE_12BIT_Z2<z2_raw = data; + ts->acq_state = IDLE; + // got the raw stuff, now mark BH + queue_task(&ts->chug_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + break; + } + + spin_unlock(&ts->lock); +} + + +/* +++++++++++++ File operations ++++++++++++++*/ + +static int +au1000_fasync(int fd, struct file *filp, int mode) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + return fasync_helper(fd, filp, mode, &ts->fasync); +} + +static int +au1000_ioctl(struct inode * inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + + switch(cmd) { + case TS_GET_RATE: /* TODO: what is this? */ + break; + case TS_SET_RATE: /* TODO: what is this? */ + break; + case TS_GET_CAL: + copy_to_user((char *)arg, (char *)&ts->cal, sizeof(TS_CAL)); + break; + case TS_SET_CAL: + copy_from_user((char *)&ts->cal, (char *)arg, sizeof(TS_CAL)); + break; + default: + err("unknown cmd %04x", cmd); + return -EINVAL; + } + + return 0; +} + +static unsigned int +au1000_poll(struct file * filp, poll_table * wait) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + poll_wait(filp, &ts->wait, wait); + if (ts->event_count) + return POLLIN | POLLRDNORM; + return 0; +} + +static ssize_t +au1000_read(struct file * filp, char * buf, size_t count, loff_t * l) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + unsigned long flags; + TS_EVENT event; + int i; + + if (ts->event_count == 0) { + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + interruptible_sleep_on(&ts->wait); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + for (i = count; + i >= sizeof(TS_EVENT); + i -= sizeof(TS_EVENT), buf += sizeof(TS_EVENT)) { + if (ts->event_count == 0) + break; + spin_lock_irqsave(&ts->lock, flags); + event = ts->event_buf[ts->nextOut++]; + if (ts->nextOut == EVENT_BUFSIZE) + ts->nextOut = 0; + if (ts->event_count) + ts->event_count--; + spin_unlock_irqrestore(&ts->lock, flags); + copy_to_user(buf, &event, sizeof(TS_EVENT)); + } + + return count - i; +} + + +static int +au1000_open(struct inode * inode, struct file * filp) +{ + au1000_ts_t* ts; + unsigned long flags; + + filp->private_data = ts = &au1000_ts; + + spin_lock_irqsave(&ts->lock, flags); + + // setup SSI0 config + outl(DEFAULT_SSI_CONFIG, SSI0_CONFIG); + + // clear out SSI0 status bits + outl(SSISTAT_OF|SSISTAT_UF|SSISTAT_DONE, SSI0_STATUS); + // clear out SSI0 interrupt pending bits + outl(SSIINT_OI|SSIINT_UI|SSIINT_DI, SSI0_INT); + + // enable SSI0 interrupts + outl(SSIINT_OI|SSIINT_UI|SSIINT_DI, SSI0_INT_ENABLE); + + /* + * init bh handler that chugs the raw data (calibrates and + * calculates touch pressure). + */ + ts->chug_tq.routine = chug_raw_data; + ts->chug_tq.data = ts; + ts->pendown = 0; // pen up + + // flush event queue + ts->nextIn = ts->nextOut = ts->event_count = 0; + + // Start acquisition timer function + init_timer(&ts->acq_timer); + ts->acq_timer.function = au1000_acq_timer; + ts->acq_timer.data = (unsigned long)ts; + ts->acq_timer.expires = jiffies + HZ / 100; + add_timer(&ts->acq_timer); + + spin_unlock_irqrestore(&ts->lock, flags); + MOD_INC_USE_COUNT; + return 0; +} + +static int +au1000_release(struct inode * inode, struct file * filp) +{ + au1000_ts_t* ts = (au1000_ts_t*)filp->private_data; + unsigned long flags; + + au1000_fasync(-1, filp, 0); + del_timer_sync(&ts->acq_timer); + + spin_lock_irqsave(&ts->lock, flags); + // disable SSI0 interrupts + outl(0, SSI0_INT_ENABLE); + spin_unlock_irqrestore(&ts->lock, flags); + + MOD_DEC_USE_COUNT; + return 0; +} + + +static struct file_operations ts_fops = { + read: au1000_read, + poll: au1000_poll, + ioctl: au1000_ioctl, + fasync: au1000_fasync, + open: au1000_open, + release: au1000_release, +}; + +/* +++++++++++++ End File operations ++++++++++++++*/ + + +int __init +au1000ts_init_module(void) +{ + au1000_ts_t* ts = &au1000_ts; + int ret; + + /* register our character device */ + if ((ret = register_chrdev(TS_MAJOR, TS_NAME, &ts_fops)) < 0) { + err("can't get major number"); + return ret; + } + info("registered"); + + memset(ts, 0, sizeof(au1000_ts_t)); + init_waitqueue_head(&ts->wait); + spin_lock_init(&ts->lock); + + if (!request_region(virt_to_phys((void*)SSI0_STATUS), 0x100, TS_NAME)) { + err("SSI0 ports in use"); + return -ENXIO; + } + + if ((ret = request_irq(AU1000_SSI0_INT, ssi0_interrupt, + SA_SHIRQ | SA_INTERRUPT, TS_NAME, ts))) { + err("could not get IRQ"); + return ret; + } + + // initial calibration values + ts->cal.xscale = -93; + ts->cal.xtrans = 346; + ts->cal.yscale = -64; + ts->cal.ytrans = 251; + + // init pen up/down hysteresis points + ts->pendown_thresh_ohms = DEFAULT_PENDOWN_THRESH_OHMS; + ts->penup_thresh_ohms = DEFAULT_PENUP_THRESH_OHMS; + ts->pressure_eqn = PRESSURE_EQN_2; + // init X and Y plate resistances + ts->x_plate_ohms = DEFAULT_X_PLATE_OHMS; + ts->y_plate_ohms = DEFAULT_Y_PLATE_OHMS; + + // set GPIO to SSI0 function + outl(inl(PIN_FUNCTION) & ~1, PIN_FUNCTION); + + // enable SSI0 clock and bring SSI0 out of reset + outl(0, SSI0_CONTROL); + udelay(1000); + outl(SSIEN_E, SSI0_CONTROL); + udelay(100); + + // FIXME: is this a working baudrate? + ts->clkdiv = 0; + ts->baudrate = calc_baudrate(ts->clkdiv); + outl(ts->clkdiv, SSI0_CLKDIV); + + info("baudrate = %d Hz", ts->baudrate); + + return 0; +} + +void +au1000ts_cleanup_module(void) +{ + // disable clocks and hold in reset + outl(SSIEN_CD, SSI0_CONTROL); + free_irq(AU1000_SSI0_INT, &au1000_ts); + release_region(virt_to_phys((void*)SSI0_STATUS), 0x100); + unregister_chrdev(TS_MAJOR, TS_NAME); +} + +/* Module information */ +MODULE_AUTHOR("Steve Longerbeam, stevel@mvista.com, www.mvista.com"); +MODULE_DESCRIPTION("Au1000/ADS7846 Touch Screen Driver"); + +module_init(au1000ts_init_module); +module_exit(au1000ts_cleanup_module); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/console.c linux-2.5/drivers/char/console.c --- linux-2.5.5/drivers/char/console.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/char/console.c Thu Jan 1 00:00:00 1970 @@ -1,3021 +0,0 @@ -/* - * linux/drivers/char/console.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* - * Hopefully this will be a rather complete VT102 implementation. - * - * Beeping thanks to John T Kohl. - * - * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics - * Chars, and VT100 enhancements by Peter MacDonald. - * - * Copy and paste function by Andrew Haylett, - * some enhancements by Alessandro Rubini. - * - * Code to check for different video-cards mostly by Galen Hunt, - * - * - * Rudimentary ISO 10646/Unicode/UTF-8 character set support by - * Markus Kuhn, . - * - * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 - * Resizing of consoles, aeb, 940926 - * - * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 - * - * - * User-defined bell sound, new setterm control sequences and printk - * redirection by Martin Mares 19-Nov-95 - * - * APM screenblank bug fixed Takashi Manabe - * - * Merge with the abstract console driver by Geert Uytterhoeven - * , Jan 1997. - * - * Original m68k console driver modifications by - * - * - Arno Griffioen - * - David Carter - * - * Note that the abstract console driver allows all consoles to be of - * potentially different sizes, so the following variables depend on the - * current console (currcons): - * - * - video_num_columns - * - video_num_lines - * - video_size_row - * - can_do_color - * - * The abstract console driver provides a generic interface for a text - * console. It supports VGA text mode, frame buffer based graphical consoles - * and special graphics processors that are only accessible through some - * registers (e.g. a TMS340x0 GSP). - * - * The interface to the hardware is specified using a special structure - * (struct consw) which contains function pointers to console operations - * (see for more information). - * - * Support for changeable cursor shape - * by Pavel Machek , August 1997 - * - * Ported to i386 and con_scrolldelta fixed - * by Emmanuel Marty , April 1998 - * - * Resurrected character buffers in videoram plus lots of other trickery - * by Martin Mares , July 1998 - * - * Removed old-style timers, introduced console_timer, made timer - * deletion SMP-safe. 17Jun00, Andrew Morton - * - * Removed console_lock, enabled interrupts across all console operations - * 13 March 2001, Andrew Morton - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "console_macros.h" - - -const struct consw *conswitchp; - -/* A bitmap for codes <32. A bit of 1 indicates that the code - * corresponding to that bit number invokes some special action - * (such as cursor movement) and should not be displayed as a - * glyph unless the disp_ctrl mode is explicitly enabled. - */ -#define CTRL_ACTION 0x0d00ff81 -#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ - -/* - * Here is the default bell parameters: 750HZ, 1/8th of a second - */ -#define DEFAULT_BELL_PITCH 750 -#define DEFAULT_BELL_DURATION (HZ/8) - -extern void vcs_make_devfs (unsigned int index, int unregister); - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -static struct tty_struct *console_table[MAX_NR_CONSOLES]; -static struct termios *console_termios[MAX_NR_CONSOLES]; -static struct termios *console_termios_locked[MAX_NR_CONSOLES]; -struct vc vc_cons [MAX_NR_CONSOLES]; - -#ifndef VT_SINGLE_DRIVER -static const struct consw *con_driver_map[MAX_NR_CONSOLES]; -#endif - -static int con_open(struct tty_struct *, struct file *); -static void vc_init(unsigned int console, unsigned int rows, - unsigned int cols, int do_clear); -static void blank_screen(unsigned long dummy); -static void gotoxy(int currcons, int new_x, int new_y); -static void save_cur(int currcons); -static void reset_terminal(int currcons, int do_clear); -static void con_flush_chars(struct tty_struct *tty); -static void set_vesa_blanking(unsigned long arg); -static void set_cursor(int currcons); -static void hide_cursor(int currcons); -static void unblank_screen_t(unsigned long dummy); -static void console_callback(void *ignored); - -static int printable; /* Is console ready for printing? */ - -int do_poke_blanked_console; -int console_blanked; - -static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ -static int blankinterval = 10*60*HZ; -static int vesa_off_interval; - -static struct tq_struct console_callback_tq = { - routine: console_callback, -}; - -/* - * fg_console is the current virtual console, - * last_console is the last used one, - * want_console is the console we want to switch to, - * kmsg_redirect is the console for kernel messages, - */ -int fg_console; -int last_console; -int want_console = -1; -int kmsg_redirect; - -/* - * For each existing display, we have a pointer to console currently visible - * on that display, allowing consoles other than fg_console to be refreshed - * appropriately. Unless the low-level driver supplies its own display_fg - * variable, we use this one for the "master display". - */ -static struct vc_data *master_display_fg; - -/* - * Unfortunately, we need to delay tty echo when we're currently writing to the - * console since the code is (and always was) not re-entrant, so we schedule - * all flip requests to process context with schedule-task() and run it from - * console_callback(). - */ - -/* - * For the same reason, we defer scrollback to the console callback. - */ -static int scrollback_delta; - -/* - * Hook so that the power management routines can (un)blank - * the console on our behalf. - */ -int (*console_blank_hook)(int); - -static struct timer_list console_timer; - -/* - * Low-Level Functions - */ - -#define IS_FG (currcons == fg_console) -#define IS_VISIBLE CON_IS_VISIBLE(vc_cons[currcons].d) - -#ifdef VT_BUF_VRAM_ONLY -#define DO_UPDATE 0 -#else -#define DO_UPDATE IS_VISIBLE -#endif - -static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data); -static struct pm_dev *pm_con; - -static inline unsigned short *screenpos(int currcons, int offset, int viewed) -{ - unsigned short *p; - - if (!viewed) - p = (unsigned short *)(origin + offset); - else if (!sw->con_screen_pos) - p = (unsigned short *)(visible_origin + offset); - else - p = sw->con_screen_pos(vc_cons[currcons].d, offset); - return p; -} - -static inline void scrolldelta(int lines) -{ - scrollback_delta += lines; - schedule_console_callback(); -} - -void schedule_console_callback(void) -{ - schedule_task(&console_callback_tq); -} - -static void scrup(int currcons, unsigned int t, unsigned int b, int nr) -{ - unsigned short *d, *s; - - if (t+nr >= b) - nr = b - t - 1; - if (b > video_num_lines || t >= b || nr < 1) - return; - if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr)) - return; - d = (unsigned short *) (origin+video_size_row*t); - s = (unsigned short *) (origin+video_size_row*(t+nr)); - scr_memcpyw(d, s, (b-t-nr) * video_size_row); - scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr); -} - -static void -scrdown(int currcons, unsigned int t, unsigned int b, int nr) -{ - unsigned short *s; - unsigned int step; - - if (t+nr >= b) - nr = b - t - 1; - if (b > video_num_lines || t >= b || nr < 1) - return; - if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr)) - return; - s = (unsigned short *) (origin+video_size_row*t); - step = video_num_columns * nr; - scr_memmovew(s + step, s, (b-t-nr)*video_size_row); - scr_memsetw(s, video_erase_char, 2*step); -} - -static void do_update_region(int currcons, unsigned long start, int count) -{ -#ifndef VT_BUF_VRAM_ONLY - unsigned int xx, yy, offset; - u16 *p; - - p = (u16 *) start; - if (!sw->con_getxy) { - offset = (start - origin) / 2; - xx = offset % video_num_columns; - yy = offset / video_num_columns; - } else { - int nxx, nyy; - start = sw->con_getxy(vc_cons[currcons].d, start, &nxx, &nyy); - xx = nxx; yy = nyy; - } - for(;;) { - u16 attrib = scr_readw(p) & 0xff00; - int startx = xx; - u16 *q = p; - while (xx < video_num_columns && count) { - if (attrib != (scr_readw(p) & 0xff00)) { - if (p > q) - sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx); - startx = xx; - q = p; - attrib = scr_readw(p) & 0xff00; - } - p++; - xx++; - count--; - } - if (p > q) - sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx); - if (!count) - break; - xx = 0; - yy++; - if (sw->con_getxy) { - p = (u16 *)start; - start = sw->con_getxy(vc_cons[currcons].d, start, NULL, NULL); - } - } -#endif -} - -void update_region(int currcons, unsigned long start, int count) -{ - if (DO_UPDATE) { - hide_cursor(currcons); - do_update_region(currcons, start, count); - set_cursor(currcons); - } -} - -/* Structure of attributes is hardware-dependent */ - -static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse) -{ - if (sw->con_build_attr) - return sw->con_build_attr(vc_cons[currcons].d, _color, _intensity, _blink, _underline, _reverse); - -#ifndef VT_BUF_VRAM_ONLY -/* - * ++roman: I completely changed the attribute format for monochrome - * mode (!can_do_color). The formerly used MDA (monochrome display - * adapter) format didn't allow the combination of certain effects. - * Now the attribute is just a bit vector: - * Bit 0..1: intensity (0..2) - * Bit 2 : underline - * Bit 3 : reverse - * Bit 7 : blink - */ - { - u8 a = color; - if (!can_do_color) - return _intensity | - (_underline ? 4 : 0) | - (_reverse ? 8 : 0) | - (_blink ? 0x80 : 0); - if (_underline) - a = (a & 0xf0) | ulcolor; - else if (_intensity == 0) - a = (a & 0xf0) | halfcolor; - if (_reverse) - a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77); - if (_blink) - a ^= 0x80; - if (_intensity == 2) - a ^= 0x08; - if (hi_font_mask == 0x100) - a <<= 1; - return a; - } -#else - return 0; -#endif -} - -static void update_attr(int currcons) -{ - attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm); - video_erase_char = (build_attr(currcons, color, 1, blink, 0, decscnm) << 8) | ' '; -} - -/* Note: inverting the screen twice should revert to the original state */ - -void invert_screen(int currcons, int offset, int count, int viewed) -{ - unsigned short *p; - - count /= 2; - p = screenpos(currcons, offset, viewed); - if (sw->con_invert_region) - sw->con_invert_region(vc_cons[currcons].d, p, count); -#ifndef VT_BUF_VRAM_ONLY - else { - u16 *q = p; - int cnt = count; - u16 a; - - if (!can_do_color) { - while (cnt--) { - a = scr_readw(q); - a ^= 0x0800; - scr_writew(a, q); - q++; - } - } else if (hi_font_mask == 0x100) { - while (cnt--) { - a = scr_readw(q); - a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); - scr_writew(a, q); - q++; - } - } else { - while (cnt--) { - a = scr_readw(q); - a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); - scr_writew(a, q); - q++; - } - } - } -#endif - if (DO_UPDATE) - do_update_region(currcons, (unsigned long) p, count); -} - -/* used by selection: complement pointer position */ -void complement_pos(int currcons, int offset) -{ - static unsigned short *p; - static unsigned short old; - static unsigned short oldx, oldy; - - if (p) { - scr_writew(old, p); - if (DO_UPDATE) - sw->con_putc(vc_cons[currcons].d, old, oldy, oldx); - } - if (offset == -1) - p = NULL; - else { - unsigned short new; - p = screenpos(currcons, offset, 1); - old = scr_readw(p); - new = old ^ complement_mask; - scr_writew(new, p); - if (DO_UPDATE) { - oldx = (offset >> 1) % video_num_columns; - oldy = (offset >> 1) / video_num_columns; - sw->con_putc(vc_cons[currcons].d, new, oldy, oldx); - } - } -} - -static void insert_char(int currcons, unsigned int nr) -{ - unsigned short *p, *q = (unsigned short *) pos; - - p = q + video_num_columns - nr - x; - while (--p >= q) - scr_writew(scr_readw(p), p + nr); - scr_memsetw(q, video_erase_char, nr*2); - need_wrap = 0; - if (DO_UPDATE) { - unsigned short oldattr = attr; - sw->con_bmove(vc_cons[currcons].d,y,x,y,x+nr,1, - video_num_columns-x-nr); - attr = video_erase_char >> 8; - while (nr--) - sw->con_putc(vc_cons[currcons].d, - video_erase_char,y,x+nr); - attr = oldattr; - } -} - -static void delete_char(int currcons, unsigned int nr) -{ - unsigned int i = x; - unsigned short *p = (unsigned short *) pos; - - while (++i <= video_num_columns - nr) { - scr_writew(scr_readw(p+nr), p); - p++; - } - scr_memsetw(p, video_erase_char, nr*2); - need_wrap = 0; - if (DO_UPDATE) { - unsigned short oldattr = attr; - sw->con_bmove(vc_cons[currcons].d, y, x+nr, y, x, 1, - video_num_columns-x-nr); - attr = video_erase_char >> 8; - while (nr--) - sw->con_putc(vc_cons[currcons].d, - video_erase_char, y, - video_num_columns-1-nr); - attr = oldattr; - } -} - -static int softcursor_original; - -static void add_softcursor(int currcons) -{ - int i = scr_readw((u16 *) pos); - u32 type = cursor_type; - - if (! (type & 0x10)) return; - if (softcursor_original != -1) return; - softcursor_original = i; - i |= ((type >> 8) & 0xff00 ); - i ^= ((type) & 0xff00 ); - if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000; - if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; - scr_writew(i, (u16 *) pos); - if (DO_UPDATE) - sw->con_putc(vc_cons[currcons].d, i, y, x); -} - -static void hide_cursor(int currcons) -{ - if (currcons == sel_cons) - clear_selection(); - if (softcursor_original != -1) { - scr_writew(softcursor_original,(u16 *) pos); - if (DO_UPDATE) - sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x); - softcursor_original = -1; - } - sw->con_cursor(vc_cons[currcons].d,CM_ERASE); -} - -static void set_cursor(int currcons) -{ - if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS) - return; - if (deccm) { - if (currcons == sel_cons) - clear_selection(); - add_softcursor(currcons); - if ((cursor_type & 0x0f) != 1) - sw->con_cursor(vc_cons[currcons].d,CM_DRAW); - } else - hide_cursor(currcons); -} - -static void set_origin(int currcons) -{ - if (!IS_VISIBLE || - !sw->con_set_origin || - !sw->con_set_origin(vc_cons[currcons].d)) - origin = (unsigned long) screenbuf; - visible_origin = origin; - scr_end = origin + screenbuf_size; - pos = origin + video_size_row*y + 2*x; -} - -static inline void save_screen(int currcons) -{ - if (sw->con_save_screen) - sw->con_save_screen(vc_cons[currcons].d); -} - -/* - * Redrawing of screen - */ - -void redraw_screen(int new_console, int is_switch) -{ - int redraw = 1; - int currcons, old_console; - - if (!vc_cons_allocated(new_console)) { - /* strange ... */ - /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */ - return; - } - - if (is_switch) { - currcons = fg_console; - hide_cursor(currcons); - if (fg_console != new_console) { - struct vc_data **display = vc_cons[new_console].d->vc_display_fg; - old_console = (*display) ? (*display)->vc_num : fg_console; - *display = vc_cons[new_console].d; - fg_console = new_console; - currcons = old_console; - if (!IS_VISIBLE) { - save_screen(currcons); - set_origin(currcons); - } - currcons = new_console; - if (old_console == new_console) - redraw = 0; - } - } else { - currcons = new_console; - hide_cursor(currcons); - } - - if (redraw) { - int update; - set_origin(currcons); - update = sw->con_switch(vc_cons[currcons].d); - set_palette(currcons); - if (update && vcmode != KD_GRAPHICS) - do_update_region(currcons, origin, screenbuf_size/2); - } - set_cursor(currcons); - if (is_switch) { - set_leds(); - compute_shiftstate(); - } -} - -/* - * Allocation, freeing and resizing of VTs. - */ - -int vc_cons_allocated(unsigned int i) -{ - return (i < MAX_NR_CONSOLES && vc_cons[i].d); -} - -static void visual_init(int currcons, int init) -{ - /* ++Geert: sw->con_init determines console size */ - sw = conswitchp; -#ifndef VT_SINGLE_DRIVER - if (con_driver_map[currcons]) - sw = con_driver_map[currcons]; -#endif - cons_num = currcons; - display_fg = &master_display_fg; - vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir; - vc_cons[currcons].d->vc_uni_pagedir = 0; - hi_font_mask = 0; - complement_mask = 0; - can_do_color = 0; - sw->con_init(vc_cons[currcons].d, init); - if (!complement_mask) - complement_mask = can_do_color ? 0x7700 : 0x0800; - s_complement_mask = complement_mask; - video_size_row = video_num_columns<<1; - screenbuf_size = video_num_lines*video_size_row; -} - -int vc_allocate(unsigned int currcons) /* return 0 on success */ -{ - if (currcons >= MAX_NR_CONSOLES) - return -ENXIO; - if (!vc_cons[currcons].d) { - long p, q; - - /* prevent users from taking too much memory */ - if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) - return -EPERM; - - /* due to the granularity of kmalloc, we waste some memory here */ - /* the alloc is done in two steps, to optimize the common situation - of a 25x80 console (structsize=216, screenbuf_size=4000) */ - /* although the numbers above are not valid since long ago, the - point is still up-to-date and the comment still has its value - even if only as a historical artifact. --mj, July 1998 */ - p = (long) kmalloc(structsize, GFP_KERNEL); - if (!p) - return -ENOMEM; - memset((void *)p, 0, structsize); - vc_cons[currcons].d = (struct vc_data *)p; - vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data)); - visual_init(currcons, 1); - if (!*vc_cons[currcons].d->vc_uni_pagedir_loc) - con_set_default_unimap(currcons); - q = (long)kmalloc(screenbuf_size, GFP_KERNEL); - if (!q) { - kfree((char *) p); - vc_cons[currcons].d = NULL; - vt_cons[currcons] = NULL; - return -ENOMEM; - } - screenbuf = (unsigned short *) q; - kmalloced = 1; - vc_init(currcons, video_num_lines, video_num_columns, 1); - - if (!pm_con) { - pm_con = pm_register(PM_SYS_DEV, - PM_SYS_VGA, - pm_con_request); - } - } - return 0; -} - -/* - * Change # of rows and columns (0 means unchanged/the size of fg_console) - * [this is to be used together with some user program - * like resize that changes the hardware videomode] - */ -int vc_resize(unsigned int lines, unsigned int cols, - unsigned int first, unsigned int last) -{ - unsigned int cc, ll, ss, sr, todo = 0; - unsigned int currcons = fg_console, i; - unsigned short *newscreens[MAX_NR_CONSOLES]; - - cc = (cols ? cols : video_num_columns); - ll = (lines ? lines : video_num_lines); - sr = cc << 1; - ss = sr * ll; - - for (currcons = first; currcons <= last; currcons++) { - if (!vc_cons_allocated(currcons) || - (cc == video_num_columns && ll == video_num_lines)) - newscreens[currcons] = NULL; - else { - unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER); - if (!p) { - for (i = first; i < currcons; i++) - if (newscreens[i]) - kfree(newscreens[i]); - return -ENOMEM; - } - newscreens[currcons] = p; - todo++; - } - } - if (!todo) - return 0; - - for (currcons = first; currcons <= last; currcons++) { - unsigned int occ, oll, oss, osr; - unsigned long ol, nl, nlend, rlth, rrem; - if (!newscreens[currcons] || !vc_cons_allocated(currcons)) - continue; - - oll = video_num_lines; - occ = video_num_columns; - osr = video_size_row; - oss = screenbuf_size; - - video_num_lines = ll; - video_num_columns = cc; - video_size_row = sr; - screenbuf_size = ss; - - rlth = MIN(osr, sr); - rrem = sr - rlth; - ol = origin; - nl = (long) newscreens[currcons]; - nlend = nl + ss; - if (ll < oll) - ol += (oll - ll) * osr; - - update_attr(currcons); - - while (ol < scr_end) { - scr_memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); - if (rrem) - scr_memsetw((void *)(nl + rlth), video_erase_char, rrem); - ol += osr; - nl += sr; - } - if (nlend > nl) - scr_memsetw((void *) nl, video_erase_char, nlend - nl); - if (kmalloced) - kfree(screenbuf); - screenbuf = newscreens[currcons]; - kmalloced = 1; - screenbuf_size = ss; - set_origin(currcons); - - /* do part of a reset_terminal() */ - top = 0; - bottom = video_num_lines; - gotoxy(currcons, x, y); - save_cur(currcons); - - if (console_table[currcons]) { - struct winsize ws, *cws = &console_table[currcons]->winsize; - memset(&ws, 0, sizeof(ws)); - ws.ws_row = video_num_lines; - ws.ws_col = video_num_columns; - if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) && - console_table[currcons]->pgrp > 0) - kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1); - *cws = ws; - } - - if (IS_VISIBLE) - update_screen(currcons); - } - - return 0; -} - - -void vc_disallocate(unsigned int currcons) -{ - acquire_console_sem(); - if (vc_cons_allocated(currcons)) { - sw->con_deinit(vc_cons[currcons].d); - if (kmalloced) - kfree(screenbuf); - if (currcons >= MIN_NR_CONSOLES) - kfree(vc_cons[currcons].d); - vc_cons[currcons].d = NULL; - } - release_console_sem(); -} - -/* - * VT102 emulator - */ - -#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x) -#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x) -#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x) - -#define decarm VC_REPEAT -#define decckm VC_CKMODE -#define kbdapplic VC_APPLIC -#define lnm VC_CRLF - -/* - * this is what the terminal answers to a ESC-Z or csi0c query. - */ -#define VT100ID "\033[?1;2c" -#define VT102ID "\033[?6c" - -unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, - 8,12,10,14, 9,13,11,15 }; - -/* the default colour table, for VGA+ colour systems */ -int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, - 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; -int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, - 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; -int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, - 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; - -/* - * gotoxy() must verify all boundaries, because the arguments - * might also be negative. If the given position is out of - * bounds, the cursor is placed at the nearest margin. - */ -static void gotoxy(int currcons, int new_x, int new_y) -{ - int min_y, max_y; - - if (new_x < 0) - x = 0; - else - if (new_x >= video_num_columns) - x = video_num_columns - 1; - else - x = new_x; - if (decom) { - min_y = top; - max_y = bottom; - } else { - min_y = 0; - max_y = video_num_lines; - } - if (new_y < min_y) - y = min_y; - else if (new_y >= max_y) - y = max_y - 1; - else - y = new_y; - pos = origin + y*video_size_row + (x<<1); - need_wrap = 0; -} - -/* for absolute user moves, when decom is set */ -static void gotoxay(int currcons, int new_x, int new_y) -{ - gotoxy(currcons, new_x, decom ? (top+new_y) : new_y); -} - -void scrollback(int lines) -{ - int currcons = fg_console; - - if (!lines) - lines = video_num_lines/2; - scrolldelta(-lines); -} - -void scrollfront(int lines) -{ - int currcons = fg_console; - - if (!lines) - lines = video_num_lines/2; - scrolldelta(lines); -} - -static void lf(int currcons) -{ - /* don't scroll if above bottom of scrolling region, or - * if below scrolling region - */ - if (y+1 == bottom) - scrup(currcons,top,bottom,1); - else if (y < video_num_lines-1) { - y++; - pos += video_size_row; - } - need_wrap = 0; -} - -static void ri(int currcons) -{ - /* don't scroll if below top of scrolling region, or - * if above scrolling region - */ - if (y == top) - scrdown(currcons,top,bottom,1); - else if (y > 0) { - y--; - pos -= video_size_row; - } - need_wrap = 0; -} - -static inline void cr(int currcons) -{ - pos -= x<<1; - need_wrap = x = 0; -} - -static inline void bs(int currcons) -{ - if (x) { - pos -= 2; - x--; - need_wrap = 0; - } -} - -static inline void del(int currcons) -{ - /* ignored */ -} - -static void csi_J(int currcons, int vpar) -{ - unsigned int count; - unsigned short * start; - - switch (vpar) { - case 0: /* erase from cursor to end of display */ - count = (scr_end-pos)>>1; - start = (unsigned short *) pos; - if (DO_UPDATE) { - /* do in two stages */ - sw->con_clear(vc_cons[currcons].d, y, x, 1, - video_num_columns-x); - sw->con_clear(vc_cons[currcons].d, y+1, 0, - video_num_lines-y-1, - video_num_columns); - } - break; - case 1: /* erase from start to cursor */ - count = ((pos-origin)>>1)+1; - start = (unsigned short *) origin; - if (DO_UPDATE) { - /* do in two stages */ - sw->con_clear(vc_cons[currcons].d, 0, 0, y, - video_num_columns); - sw->con_clear(vc_cons[currcons].d, y, 0, 1, - x + 1); - } - break; - case 2: /* erase whole display */ - count = video_num_columns * video_num_lines; - start = (unsigned short *) origin; - if (DO_UPDATE) - sw->con_clear(vc_cons[currcons].d, 0, 0, - video_num_lines, - video_num_columns); - break; - default: - return; - } - scr_memsetw(start, video_erase_char, 2*count); - need_wrap = 0; -} - -static void csi_K(int currcons, int vpar) -{ - unsigned int count; - unsigned short * start; - - switch (vpar) { - case 0: /* erase from cursor to end of line */ - count = video_num_columns-x; - start = (unsigned short *) pos; - if (DO_UPDATE) - sw->con_clear(vc_cons[currcons].d, y, x, 1, - video_num_columns-x); - break; - case 1: /* erase from start of line to cursor */ - start = (unsigned short *) (pos - (x<<1)); - count = x+1; - if (DO_UPDATE) - sw->con_clear(vc_cons[currcons].d, y, 0, 1, - x + 1); - break; - case 2: /* erase whole line */ - start = (unsigned short *) (pos - (x<<1)); - count = video_num_columns; - if (DO_UPDATE) - sw->con_clear(vc_cons[currcons].d, y, 0, 1, - video_num_columns); - break; - default: - return; - } - scr_memsetw(start, video_erase_char, 2 * count); - need_wrap = 0; -} - -static void csi_X(int currcons, int vpar) /* erase the following vpar positions */ -{ /* not vt100? */ - int count; - - if (!vpar) - vpar++; - count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar; - - scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count); - if (DO_UPDATE) - sw->con_clear(vc_cons[currcons].d, y, x, 1, count); - need_wrap = 0; -} - -static void default_attr(int currcons) -{ - intensity = 1; - underline = 0; - reverse = 0; - blink = 0; - color = def_color; -} - -/* console_sem is held */ -static void csi_m(int currcons) -{ - int i; - - for (i=0;i<=npar;i++) - switch (par[i]) { - case 0: /* all attributes off */ - default_attr(currcons); - break; - case 1: - intensity = 2; - break; - case 2: - intensity = 0; - break; - case 4: - underline = 1; - break; - case 5: - blink = 1; - break; - case 7: - reverse = 1; - break; - case 10: /* ANSI X3.64-1979 (SCO-ish?) - * Select primary font, don't display - * control chars if defined, don't set - * bit 8 on output. - */ - translate = set_translate(charset == 0 - ? G0_charset - : G1_charset,currcons); - disp_ctrl = 0; - toggle_meta = 0; - break; - case 11: /* ANSI X3.64-1979 (SCO-ish?) - * Select first alternate font, lets - * chars < 32 be displayed as ROM chars. - */ - translate = set_translate(IBMPC_MAP,currcons); - disp_ctrl = 1; - toggle_meta = 0; - break; - case 12: /* ANSI X3.64-1979 (SCO-ish?) - * Select second alternate font, toggle - * high bit before displaying as ROM char. - */ - translate = set_translate(IBMPC_MAP,currcons); - disp_ctrl = 1; - toggle_meta = 1; - break; - case 21: - case 22: - intensity = 1; - break; - case 24: - underline = 0; - break; - case 25: - blink = 0; - break; - case 27: - reverse = 0; - break; - case 38: /* ANSI X3.64-1979 (SCO-ish?) - * Enables underscore, white foreground - * with white underscore (Linux - use - * default foreground). - */ - color = (def_color & 0x0f) | background; - underline = 1; - break; - case 39: /* ANSI X3.64-1979 (SCO-ish?) - * Disable underline option. - * Reset colour to default? It did this - * before... - */ - color = (def_color & 0x0f) | background; - underline = 0; - break; - case 49: - color = (def_color & 0xf0) | foreground; - break; - default: - if (par[i] >= 30 && par[i] <= 37) - color = color_table[par[i]-30] - | background; - else if (par[i] >= 40 && par[i] <= 47) - color = (color_table[par[i]-40]<<4) - | foreground; - break; - } - update_attr(currcons); -} - -static void respond_string(const char * p, struct tty_struct * tty) -{ - while (*p) { - tty_insert_flip_char(tty, *p, 0); - p++; - } - con_schedule_flip(tty); -} - -static void cursor_report(int currcons, struct tty_struct * tty) -{ - char buf[40]; - - sprintf(buf, "\033[%d;%dR", y + (decom ? top+1 : 1), x+1); - respond_string(buf, tty); -} - -static inline void status_report(struct tty_struct * tty) -{ - respond_string("\033[0n", tty); /* Terminal ok */ -} - -static inline void respond_ID(struct tty_struct * tty) -{ - respond_string(VT102ID, tty); -} - -void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry) -{ - char buf[8]; - - sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), - (char)('!' + mry)); - respond_string(buf, tty); -} - -/* invoked via ioctl(TIOCLINUX) and through set_selection */ -int mouse_reporting(void) -{ - int currcons = fg_console; - - return report_mouse; -} - -/* console_sem is held */ -static void set_mode(int currcons, int on_off) -{ - int i; - - for (i=0; i<=npar; i++) - if (ques) switch(par[i]) { /* DEC private modes set/reset */ - case 1: /* Cursor keys send ^[Ox/^[[x */ - if (on_off) - set_kbd(decckm); - else - clr_kbd(decckm); - break; - case 3: /* 80/132 mode switch unimplemented */ - deccolm = on_off; -#if 0 - (void) vc_resize(video_num_lines, deccolm ? 132 : 80); - /* this alone does not suffice; some user mode - utility has to change the hardware regs */ -#endif - break; - case 5: /* Inverted screen on/off */ - if (decscnm != on_off) { - decscnm = on_off; - invert_screen(currcons, 0, screenbuf_size, 0); - update_attr(currcons); - } - break; - case 6: /* Origin relative/absolute */ - decom = on_off; - gotoxay(currcons,0,0); - break; - case 7: /* Autowrap on/off */ - decawm = on_off; - break; - case 8: /* Autorepeat on/off */ - if (on_off) - set_kbd(decarm); - else - clr_kbd(decarm); - break; - case 9: - report_mouse = on_off ? 1 : 0; - break; - case 25: /* Cursor on/off */ - deccm = on_off; - break; - case 1000: - report_mouse = on_off ? 2 : 0; - break; - } else switch(par[i]) { /* ANSI modes set/reset */ - case 3: /* Monitor (display ctrls) */ - disp_ctrl = on_off; - break; - case 4: /* Insert Mode on/off */ - decim = on_off; - break; - case 20: /* Lf, Enter == CrLf/Lf */ - if (on_off) - set_kbd(lnm); - else - clr_kbd(lnm); - break; - } -} - -/* console_sem is held */ -static void setterm_command(int currcons) -{ - switch(par[0]) { - case 1: /* set color for underline mode */ - if (can_do_color && par[1] < 16) { - ulcolor = color_table[par[1]]; - if (underline) - update_attr(currcons); - } - break; - case 2: /* set color for half intensity mode */ - if (can_do_color && par[1] < 16) { - halfcolor = color_table[par[1]]; - if (intensity == 0) - update_attr(currcons); - } - break; - case 8: /* store colors as defaults */ - def_color = attr; - if (hi_font_mask == 0x100) - def_color >>= 1; - default_attr(currcons); - update_attr(currcons); - break; - case 9: /* set blanking interval */ - blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; - poke_blanked_console(); - break; - case 10: /* set bell frequency in Hz */ - if (npar >= 1) - bell_pitch = par[1]; - else - bell_pitch = DEFAULT_BELL_PITCH; - break; - case 11: /* set bell duration in msec */ - if (npar >= 1) - bell_duration = (par[1] < 2000) ? - par[1]*HZ/1000 : 0; - else - bell_duration = DEFAULT_BELL_DURATION; - break; - case 12: /* bring specified console to the front */ - if (par[1] >= 1 && vc_cons_allocated(par[1]-1)) - set_console(par[1] - 1); - break; - case 13: /* unblank the screen */ - poke_blanked_console(); - break; - case 14: /* set vesa powerdown interval */ - vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; - break; - } -} - -/* console_sem is held */ -static void csi_at(int currcons, unsigned int nr) -{ - if (nr > video_num_columns - x) - nr = video_num_columns - x; - else if (!nr) - nr = 1; - insert_char(currcons, nr); -} - -/* console_sem is held */ -static void csi_L(int currcons, unsigned int nr) -{ - if (nr > video_num_lines - y) - nr = video_num_lines - y; - else if (!nr) - nr = 1; - scrdown(currcons,y,bottom,nr); - need_wrap = 0; -} - -/* console_sem is held */ -static void csi_P(int currcons, unsigned int nr) -{ - if (nr > video_num_columns - x) - nr = video_num_columns - x; - else if (!nr) - nr = 1; - delete_char(currcons, nr); -} - -/* console_sem is held */ -static void csi_M(int currcons, unsigned int nr) -{ - if (nr > video_num_lines - y) - nr = video_num_lines - y; - else if (!nr) - nr=1; - scrup(currcons,y,bottom,nr); - need_wrap = 0; -} - -/* console_sem is held (except via vc_init->reset_terminal */ -static void save_cur(int currcons) -{ - saved_x = x; - saved_y = y; - s_intensity = intensity; - s_underline = underline; - s_blink = blink; - s_reverse = reverse; - s_charset = charset; - s_color = color; - saved_G0 = G0_charset; - saved_G1 = G1_charset; -} - -/* console_sem is held */ -static void restore_cur(int currcons) -{ - gotoxy(currcons,saved_x,saved_y); - intensity = s_intensity; - underline = s_underline; - blink = s_blink; - reverse = s_reverse; - charset = s_charset; - color = s_color; - G0_charset = saved_G0; - G1_charset = saved_G1; - translate = set_translate(charset ? G1_charset : G0_charset,currcons); - update_attr(currcons); - need_wrap = 0; -} - -enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, - EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, - ESpalette }; - -/* console_sem is held (except via vc_init()) */ -static void reset_terminal(int currcons, int do_clear) -{ - top = 0; - bottom = video_num_lines; - vc_state = ESnormal; - ques = 0; - translate = set_translate(LAT1_MAP,currcons); - G0_charset = LAT1_MAP; - G1_charset = GRAF_MAP; - charset = 0; - need_wrap = 0; - report_mouse = 0; - utf = 0; - utf_count = 0; - - disp_ctrl = 0; - toggle_meta = 0; - - decscnm = 0; - decom = 0; - decawm = 1; - deccm = 1; - decim = 0; - - set_kbd(decarm); - clr_kbd(decckm); - clr_kbd(kbdapplic); - clr_kbd(lnm); - kbd_table[currcons].lockstate = 0; - kbd_table[currcons].slockstate = 0; - kbd_table[currcons].ledmode = LED_SHOW_FLAGS; - kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate; - set_leds(); - - cursor_type = CUR_DEFAULT; - complement_mask = s_complement_mask; - - default_attr(currcons); - update_attr(currcons); - - tab_stop[0] = 0x01010100; - tab_stop[1] = - tab_stop[2] = - tab_stop[3] = - tab_stop[4] = 0x01010101; - - bell_pitch = DEFAULT_BELL_PITCH; - bell_duration = DEFAULT_BELL_DURATION; - - gotoxy(currcons,0,0); - save_cur(currcons); - if (do_clear) - csi_J(currcons,2); -} - -/* console_sem is held */ -static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c) -{ - /* - * Control characters can be used in the _middle_ - * of an escape sequence. - */ - switch (c) { - case 0: - return; - case 7: - if (bell_duration) - kd_mksound(bell_pitch, bell_duration); - return; - case 8: - bs(currcons); - return; - case 9: - pos -= (x << 1); - while (x < video_num_columns - 1) { - x++; - if (tab_stop[x >> 5] & (1 << (x & 31))) - break; - } - pos += (x << 1); - return; - case 10: case 11: case 12: - lf(currcons); - if (!is_kbd(lnm)) - return; - case 13: - cr(currcons); - return; - case 14: - charset = 1; - translate = set_translate(G1_charset,currcons); - disp_ctrl = 1; - return; - case 15: - charset = 0; - translate = set_translate(G0_charset,currcons); - disp_ctrl = 0; - return; - case 24: case 26: - vc_state = ESnormal; - return; - case 27: - vc_state = ESesc; - return; - case 127: - del(currcons); - return; - case 128+27: - vc_state = ESsquare; - return; - } - switch(vc_state) { - case ESesc: - vc_state = ESnormal; - switch (c) { - case '[': - vc_state = ESsquare; - return; - case ']': - vc_state = ESnonstd; - return; - case '%': - vc_state = ESpercent; - return; - case 'E': - cr(currcons); - lf(currcons); - return; - case 'M': - ri(currcons); - return; - case 'D': - lf(currcons); - return; - case 'H': - tab_stop[x >> 5] |= (1 << (x & 31)); - return; - case 'Z': - respond_ID(tty); - return; - case '7': - save_cur(currcons); - return; - case '8': - restore_cur(currcons); - return; - case '(': - vc_state = ESsetG0; - return; - case ')': - vc_state = ESsetG1; - return; - case '#': - vc_state = EShash; - return; - case 'c': - reset_terminal(currcons,1); - return; - case '>': /* Numeric keypad */ - clr_kbd(kbdapplic); - return; - case '=': /* Appl. keypad */ - set_kbd(kbdapplic); - return; - } - return; - case ESnonstd: - if (c=='P') { /* palette escape sequence */ - for (npar=0; npar='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { - par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ; - if (npar==7) { - int i = par[0]*3, j = 1; - palette[i] = 16*par[j++]; - palette[i++] += par[j++]; - palette[i] = 16*par[j++]; - palette[i++] += par[j++]; - palette[i] = 16*par[j++]; - palette[i] += par[j]; - set_palette(currcons); - vc_state = ESnormal; - } - } else - vc_state = ESnormal; - return; - case ESsquare: - for(npar = 0 ; npar < NPAR ; npar++) - par[npar] = 0; - npar = 0; - vc_state = ESgetpars; - if (c == '[') { /* Function key */ - vc_state=ESfunckey; - return; - } - ques = (c=='?'); - if (ques) - return; - case ESgetpars: - if (c==';' && npar='0' && c<='9') { - par[npar] *= 10; - par[npar] += c-'0'; - return; - } else vc_state=ESgotpars; - case ESgotpars: - vc_state = ESnormal; - switch(c) { - case 'h': - set_mode(currcons,1); - return; - case 'l': - set_mode(currcons,0); - return; - case 'c': - if (ques) { - if (par[0]) - cursor_type = par[0] | (par[1]<<8) | (par[2]<<16); - else - cursor_type = CUR_DEFAULT; - return; - } - break; - case 'm': - if (ques) { - clear_selection(); - if (par[0]) - complement_mask = par[0]<<8 | par[1]; - else - complement_mask = s_complement_mask; - return; - } - break; - case 'n': - if (!ques) { - if (par[0] == 5) - status_report(tty); - else if (par[0] == 6) - cursor_report(currcons,tty); - } - return; - } - if (ques) { - ques = 0; - return; - } - switch(c) { - case 'G': case '`': - if (par[0]) par[0]--; - gotoxy(currcons,par[0],y); - return; - case 'A': - if (!par[0]) par[0]++; - gotoxy(currcons,x,y-par[0]); - return; - case 'B': case 'e': - if (!par[0]) par[0]++; - gotoxy(currcons,x,y+par[0]); - return; - case 'C': case 'a': - if (!par[0]) par[0]++; - gotoxy(currcons,x+par[0],y); - return; - case 'D': - if (!par[0]) par[0]++; - gotoxy(currcons,x-par[0],y); - return; - case 'E': - if (!par[0]) par[0]++; - gotoxy(currcons,0,y+par[0]); - return; - case 'F': - if (!par[0]) par[0]++; - gotoxy(currcons,0,y-par[0]); - return; - case 'd': - if (par[0]) par[0]--; - gotoxay(currcons,x,par[0]); - return; - case 'H': case 'f': - if (par[0]) par[0]--; - if (par[1]) par[1]--; - gotoxay(currcons,par[1],par[0]); - return; - case 'J': - csi_J(currcons,par[0]); - return; - case 'K': - csi_K(currcons,par[0]); - return; - case 'L': - csi_L(currcons,par[0]); - return; - case 'M': - csi_M(currcons,par[0]); - return; - case 'P': - csi_P(currcons,par[0]); - return; - case 'c': - if (!par[0]) - respond_ID(tty); - return; - case 'g': - if (!par[0]) - tab_stop[x >> 5] &= ~(1 << (x & 31)); - else if (par[0] == 3) { - tab_stop[0] = - tab_stop[1] = - tab_stop[2] = - tab_stop[3] = - tab_stop[4] = 0; - } - return; - case 'm': - csi_m(currcons); - return; - case 'q': /* DECLL - but only 3 leds */ - /* map 0,1,2,3 to 0,1,2,4 */ - if (par[0] < 4) - setledstate(kbd_table + currcons, - (par[0] < 3) ? par[0] : 4); - return; - case 'r': - if (!par[0]) - par[0]++; - if (!par[1]) - par[1] = video_num_lines; - /* Minimum allowed region is 2 lines */ - if (par[0] < par[1] && - par[1] <= video_num_lines) { - top=par[0]-1; - bottom=par[1]; - gotoxay(currcons,0,0); - } - return; - case 's': - save_cur(currcons); - return; - case 'u': - restore_cur(currcons); - return; - case 'X': - csi_X(currcons, par[0]); - return; - case '@': - csi_at(currcons,par[0]); - return; - case ']': /* setterm functions */ - setterm_command(currcons); - return; - } - return; - case ESpercent: - vc_state = ESnormal; - switch (c) { - case '@': /* defined in ISO 2022 */ - utf = 0; - return; - case 'G': /* prelim official escape code */ - case '8': /* retained for compatibility */ - utf = 1; - return; - } - return; - case ESfunckey: - vc_state = ESnormal; - return; - case EShash: - vc_state = ESnormal; - if (c == '8') { - /* DEC screen alignment test. kludge :-) */ - video_erase_char = - (video_erase_char & 0xff00) | 'E'; - csi_J(currcons, 2); - video_erase_char = - (video_erase_char & 0xff00) | ' '; - do_update_region(currcons, origin, screenbuf_size/2); - } - return; - case ESsetG0: - if (c == '0') - G0_charset = GRAF_MAP; - else if (c == 'B') - G0_charset = LAT1_MAP; - else if (c == 'U') - G0_charset = IBMPC_MAP; - else if (c == 'K') - G0_charset = USER_MAP; - if (charset == 0) - translate = set_translate(G0_charset,currcons); - vc_state = ESnormal; - return; - case ESsetG1: - if (c == '0') - G1_charset = GRAF_MAP; - else if (c == 'B') - G1_charset = LAT1_MAP; - else if (c == 'U') - G1_charset = IBMPC_MAP; - else if (c == 'K') - G1_charset = USER_MAP; - if (charset == 1) - translate = set_translate(G1_charset,currcons); - vc_state = ESnormal; - return; - default: - vc_state = ESnormal; - } -} - -/* This is a temporary buffer used to prepare a tty console write - * so that we can easily avoid touching user space while holding the - * console spinlock. It is allocated in con_init and is shared by - * this code and the vc_screen read/write tty calls. - * - * We have to allocate this statically in the kernel data section - * since console_init (and thus con_init) are called before any - * kernel memory allocation is available. - */ -char con_buf[PAGE_SIZE]; -#define CON_BUF_SIZE PAGE_SIZE -DECLARE_MUTEX(con_buf_sem); - -/* acquires console_sem */ -static int do_con_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) -{ -#ifdef VT_BUF_VRAM_ONLY -#define FLUSH do { } while(0); -#else -#define FLUSH if (draw_x >= 0) { \ - sw->con_putcs(vc_cons[currcons].d, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \ - draw_x = -1; \ - } -#endif - - int c, tc, ok, n = 0, draw_x = -1; - unsigned int currcons; - unsigned long draw_from = 0, draw_to = 0; - struct vt_struct *vt = (struct vt_struct *)tty->driver_data; - u16 himask, charmask; - const unsigned char *orig_buf = NULL; - int orig_count; - - if (in_interrupt()) - return count; - - currcons = vt->vc_num; - if (!vc_cons_allocated(currcons)) { - /* could this happen? */ - static int error = 0; - if (!error) { - error = 1; - printk("con_write: tty %d not allocated\n", currcons+1); - } - return 0; - } - - orig_buf = buf; - orig_count = count; - - if (from_user) { - down(&con_buf_sem); - -again: - if (count > CON_BUF_SIZE) - count = CON_BUF_SIZE; - console_conditional_schedule(); - if (copy_from_user(con_buf, buf, count)) { - n = 0; /* ?? are error codes legal here ?? */ - goto out; - } - - buf = con_buf; - } - - /* At this point 'buf' is guarenteed to be a kernel buffer - * and therefore no access to userspace (and therefore sleeping) - * will be needed. The con_buf_sem serializes all tty based - * console rendering and vcs write/read operations. We hold - * the console spinlock during the entire write. - */ - - acquire_console_sem(); - - himask = hi_font_mask; - charmask = himask ? 0x1ff : 0xff; - - /* undraw cursor first */ - if (IS_FG) - hide_cursor(currcons); - - while (!tty->stopped && count) { - c = *buf; - buf++; - n++; - count--; - - if (utf) { - /* Combine UTF-8 into Unicode */ - /* Incomplete characters silently ignored */ - if(c > 0x7f) { - if (utf_count > 0 && (c & 0xc0) == 0x80) { - utf_char = (utf_char << 6) | (c & 0x3f); - utf_count--; - if (utf_count == 0) - tc = c = utf_char; - else continue; - } else { - if ((c & 0xe0) == 0xc0) { - utf_count = 1; - utf_char = (c & 0x1f); - } else if ((c & 0xf0) == 0xe0) { - utf_count = 2; - utf_char = (c & 0x0f); - } else if ((c & 0xf8) == 0xf0) { - utf_count = 3; - utf_char = (c & 0x07); - } else if ((c & 0xfc) == 0xf8) { - utf_count = 4; - utf_char = (c & 0x03); - } else if ((c & 0xfe) == 0xfc) { - utf_count = 5; - utf_char = (c & 0x01); - } else - utf_count = 0; - continue; - } - } else { - tc = c; - utf_count = 0; - } - } else { /* no utf */ - tc = translate[toggle_meta ? (c|0x80) : c]; - } - - /* If the original code was a control character we - * only allow a glyph to be displayed if the code is - * not normally used (such as for cursor movement) or - * if the disp_ctrl mode has been explicitly enabled. - * Certain characters (as given by the CTRL_ALWAYS - * bitmap) are always displayed as control characters, - * as the console would be pretty useless without - * them; to display an arbitrary font position use the - * direct-to-font zone in UTF-8 mode. - */ - ok = tc && (c >= 32 || - (!utf && !(((disp_ctrl ? CTRL_ALWAYS - : CTRL_ACTION) >> c) & 1))) - && (c != 127 || disp_ctrl) - && (c != 128+27); - - if (vc_state == ESnormal && ok) { - /* Now try to find out how to display it */ - tc = conv_uni_to_pc(vc_cons[currcons].d, tc); - if ( tc == -4 ) { - /* If we got -4 (not found) then see if we have - defined a replacement character (U+FFFD) */ - tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd); - - /* One reason for the -4 can be that we just - did a clear_unimap(); - try at least to show something. */ - if (tc == -4) - tc = c; - } else if ( tc == -3 ) { - /* Bad hash table -- hope for the best */ - tc = c; - } - if (tc & ~charmask) - continue; /* Conversion failed */ - - if (need_wrap || decim) - FLUSH - if (need_wrap) { - cr(currcons); - lf(currcons); - } - if (decim) - insert_char(currcons, 1); - scr_writew(himask ? - ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : - (attr << 8) + tc, - (u16 *) pos); - if (DO_UPDATE && draw_x < 0) { - draw_x = x; - draw_from = pos; - } - if (x == video_num_columns - 1) { - need_wrap = decawm; - draw_to = pos+2; - } else { - x++; - draw_to = (pos+=2); - } - continue; - } - FLUSH - do_con_trol(tty, currcons, c); - } - FLUSH - console_conditional_schedule(); - release_console_sem(); - -out: - if (from_user) { - /* If the user requested something larger than - * the CON_BUF_SIZE, and the tty is not stopped, - * keep going. - */ - if ((orig_count > CON_BUF_SIZE) && !tty->stopped) { - orig_count -= CON_BUF_SIZE; - orig_buf += CON_BUF_SIZE; - count = orig_count; - buf = orig_buf; - goto again; - } - - up(&con_buf_sem); - } - - return n; -#undef FLUSH -} - -/* - * This is the console switching callback. - * - * Doing console switching in a process context allows - * us to do the switches asynchronously (needed when we want - * to switch due to a keyboard interrupt). Synchronization - * with other console code and prevention of re-entrancy is - * ensured with console_sem. - */ -static void console_callback(void *ignored) -{ - acquire_console_sem(); - - if (want_console >= 0) { - if (want_console != fg_console && vc_cons_allocated(want_console)) { - hide_cursor(fg_console); - change_console(want_console); - /* we only changed when the console had already - been allocated - a new console is not created - in an interrupt routine */ - } - want_console = -1; - } - if (do_poke_blanked_console) { /* do not unblank for a LED change */ - do_poke_blanked_console = 0; - poke_blanked_console(); - } - if (scrollback_delta) { - int currcons = fg_console; - clear_selection(); - if (vcmode == KD_TEXT) - sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta); - scrollback_delta = 0; - } - - release_console_sem(); -} - -void set_console(int nr) -{ - want_console = nr; - schedule_console_callback(); -} - -#ifdef CONFIG_VT_CONSOLE - -/* - * Console on virtual terminal - * - * The console must be locked when we get here. - */ - -void vt_console_print(struct console *co, const char * b, unsigned count) -{ - int currcons = fg_console; - unsigned char c; - static unsigned long printing; - const ushort *start; - ushort cnt = 0; - ushort myx; - - /* console busy or not yet initialized */ - if (!printable || test_and_set_bit(0, &printing)) - return; - - pm_access(pm_con); - - if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) - currcons = kmsg_redirect - 1; - - /* read `x' only after setting currecons properly (otherwise - the `x' macro will read the x of the foreground console). */ - myx = x; - - if (!vc_cons_allocated(currcons)) { - /* impossible */ - /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */ - goto quit; - } - - if (vcmode != KD_TEXT) - goto quit; - - /* undraw cursor first */ - if (IS_FG) - hide_cursor(currcons); - - start = (ushort *)pos; - - /* Contrived structure to try to emulate original need_wrap behaviour - * Problems caused when we have need_wrap set on '\n' character */ - while (count--) { - c = *b++; - if (c == 10 || c == 13 || c == 8 || need_wrap) { - if (cnt > 0) { - if (IS_VISIBLE) - sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x); - x += cnt; - if (need_wrap) - x--; - cnt = 0; - } - if (c == 8) { /* backspace */ - bs(currcons); - start = (ushort *)pos; - myx = x; - continue; - } - if (c != 13) - lf(currcons); - cr(currcons); - start = (ushort *)pos; - myx = x; - if (c == 10 || c == 13) - continue; - } - scr_writew((attr << 8) + c, (unsigned short *) pos); - cnt++; - if (myx == video_num_columns - 1) { - need_wrap = 1; - continue; - } - pos+=2; - myx++; - } - if (cnt > 0) { - if (IS_VISIBLE) - sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x); - x += cnt; - if (x == video_num_columns) { - x--; - need_wrap = 1; - } - } - set_cursor(currcons); - - if (!oops_in_progress) - poke_blanked_console(); - -quit: - clear_bit(0, &printing); -} - -static kdev_t vt_console_device(struct console *c) -{ - return mk_kdev(TTY_MAJOR, c->index ? c->index : fg_console + 1); -} - -struct console vt_console_driver = { - name: "tty", - write: vt_console_print, - device: vt_console_device, - unblank: unblank_screen, - flags: CON_PRINTBUFFER, - index: -1, -}; -#endif - -/* - * Handling of Linux-specific VC ioctls - */ - -/* - * Generally a bit racy with respect to console_sem(). - * - * There are some functions which don't need it. - * - * There are some functions which can sleep for arbitrary periods (paste_selection) - * but we don't need the lock there anyway. - * - * set_selection has locking, and definitely needs it - */ - -int tioclinux(struct tty_struct *tty, unsigned long arg) -{ - char type, data; - int ret; - - if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) - return -EINVAL; - if (current->tty != tty && !capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(type, (char *)arg)) - return -EFAULT; - ret = 0; - switch (type) - { - case 2: - acquire_console_sem(); - ret = set_selection(arg, tty, 1); - release_console_sem(); - break; - case 3: - ret = paste_selection(tty); - break; - case 4: - unblank_screen(); - break; - case 5: - ret = sel_loadlut(arg); - break; - case 6: - - /* - * Make it possible to react to Shift+Mousebutton. - * Note that 'shift_state' is an undocumented - * kernel-internal variable; programs not closely - * related to the kernel should not use this. - */ - data = shift_state; - ret = __put_user(data, (char *) arg); - break; - case 7: - data = mouse_reporting(); - ret = __put_user(data, (char *) arg); - break; - case 10: - set_vesa_blanking(arg); - break;; - case 11: /* set kmsg redirect */ - if (!capable(CAP_SYS_ADMIN)) { - ret = -EPERM; - } else { - if (get_user(data, (char *)arg+1)) - ret = -EFAULT; - else - kmsg_redirect = data; - } - break; - case 12: /* get fg_console */ - ret = fg_console; - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -/* - * /dev/ttyN handling - */ - -static int con_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) -{ - int retval; - - pm_access(pm_con); - retval = do_con_write(tty, from_user, buf, count); - con_flush_chars(tty); - - return retval; -} - -static void con_put_char(struct tty_struct *tty, unsigned char ch) -{ - if (in_interrupt()) - return; /* n_r3964 calls put_char() from interrupt context */ - pm_access(pm_con); - do_con_write(tty, 0, &ch, 1); -} - -static int con_write_room(struct tty_struct *tty) -{ - if (tty->stopped) - return 0; - return 4096; /* No limit, really; we're not buffering */ -} - -static int con_chars_in_buffer(struct tty_struct *tty) -{ - return 0; /* we're not buffering */ -} - -/* - * con_throttle and con_unthrottle are only used for - * paste_selection(), which has to stuff in a large number of - * characters... - */ -static void con_throttle(struct tty_struct *tty) -{ -} - -static void con_unthrottle(struct tty_struct *tty) -{ - struct vt_struct *vt = (struct vt_struct *) tty->driver_data; - - wake_up_interruptible(&vt->paste_wait); -} - -/* - * Turn the Scroll-Lock LED on when the tty is stopped - */ -static void con_stop(struct tty_struct *tty) -{ - int console_num; - if (!tty) - return; - console_num = minor(tty->device) - (tty->driver.minor_start); - if (!vc_cons_allocated(console_num)) - return; - set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); - set_leds(); -} - -/* - * Turn the Scroll-Lock LED off when the console is started - */ -static void con_start(struct tty_struct *tty) -{ - int console_num; - if (!tty) - return; - console_num = minor(tty->device) - (tty->driver.minor_start); - if (!vc_cons_allocated(console_num)) - return; - clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); - set_leds(); -} - -static void con_flush_chars(struct tty_struct *tty) -{ - struct vt_struct *vt; - - if (in_interrupt()) /* from flush_to_ldisc */ - return; - - pm_access(pm_con); - - /* if we race with con_close(), vt may be null */ - acquire_console_sem(); - vt = (struct vt_struct *)tty->driver_data; - if (vt) - set_cursor(vt->vc_num); - release_console_sem(); -} - -/* - * Allocate the console screen memory. - */ -static int con_open(struct tty_struct *tty, struct file * filp) -{ - unsigned int currcons; - int i; - - currcons = minor(tty->device) - tty->driver.minor_start; - - i = vc_allocate(currcons); - if (i) - return i; - - vt_cons[currcons]->vc_num = currcons; - tty->driver_data = vt_cons[currcons]; - - if (!tty->winsize.ws_row && !tty->winsize.ws_col) { - tty->winsize.ws_row = video_num_lines; - tty->winsize.ws_col = video_num_columns; - } - if (tty->count == 1) - vcs_make_devfs (currcons, 0); - return 0; -} - -static void con_close(struct tty_struct *tty, struct file * filp) -{ - if (!tty) - return; - if (tty->count != 1) return; - vcs_make_devfs (minor(tty->device) - tty->driver.minor_start, 1); - tty->driver_data = 0; -} - -static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int do_clear) -{ - int j, k ; - - video_num_columns = cols; - video_num_lines = rows; - video_size_row = cols<<1; - screenbuf_size = video_num_lines * video_size_row; - - set_origin(currcons); - pos = origin; - reset_vc(currcons); - for (j=k=0; j<16; j++) { - vc_cons[currcons].d->vc_palette[k++] = default_red[j] ; - vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ; - vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ; - } - def_color = 0x07; /* white */ - ulcolor = 0x0f; /* bold white */ - halfcolor = 0x08; /* grey */ - init_waitqueue_head(&vt_cons[currcons]->paste_wait); - reset_terminal(currcons, do_clear); -} - -/* - * This routine initializes console interrupts, and does nothing - * else. If you want the screen to clear, call tty_write with - * the appropriate escape-sequence. - */ - -struct tty_driver console_driver; -static int console_refcount; - -void __init con_init(void) -{ - const char *display_desc = NULL; - unsigned int currcons = 0; - - if (conswitchp) - display_desc = conswitchp->con_startup(); - if (!display_desc) { - fg_console = 0; - return; - } - - memset(&console_driver, 0, sizeof(struct tty_driver)); - console_driver.magic = TTY_DRIVER_MAGIC; - console_driver.name = "vc/%d"; - console_driver.name_base = 1; - console_driver.major = TTY_MAJOR; - console_driver.minor_start = 1; - console_driver.num = MAX_NR_CONSOLES; - console_driver.type = TTY_DRIVER_TYPE_CONSOLE; - console_driver.init_termios = tty_std_termios; - console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; - /* Tell tty_register_driver() to skip consoles because they are - * registered before kmalloc() is ready. We'll patch them in later. - * See comments at console_init(); see also con_init_devfs(). - */ - console_driver.flags |= TTY_DRIVER_NO_DEVFS; - console_driver.refcount = &console_refcount; - console_driver.table = console_table; - console_driver.termios = console_termios; - console_driver.termios_locked = console_termios_locked; - - console_driver.open = con_open; - console_driver.close = con_close; - console_driver.write = con_write; - console_driver.write_room = con_write_room; - console_driver.put_char = con_put_char; - console_driver.flush_chars = con_flush_chars; - console_driver.chars_in_buffer = con_chars_in_buffer; - console_driver.ioctl = vt_ioctl; - console_driver.stop = con_stop; - console_driver.start = con_start; - console_driver.throttle = con_throttle; - console_driver.unthrottle = con_unthrottle; - - if (tty_register_driver(&console_driver)) - panic("Couldn't register console driver\n"); - - init_timer(&console_timer); - console_timer.function = blank_screen; - if (blankinterval) { - mod_timer(&console_timer, jiffies + blankinterval); - } - - /* - * kmalloc is not running yet - we use the bootmem allocator. - */ - for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { - vc_cons[currcons].d = (struct vc_data *) - alloc_bootmem(sizeof(struct vc_data)); - vt_cons[currcons] = (struct vt_struct *) - alloc_bootmem(sizeof(struct vt_struct)); - visual_init(currcons, 1); - screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size); - kmalloced = 0; - vc_init(currcons, video_num_lines, video_num_columns, - currcons || !sw->con_save_screen); - } - currcons = fg_console = 0; - master_display_fg = vc_cons[currcons].d; - set_origin(currcons); - save_screen(currcons); - gotoxy(currcons,x,y); - csi_J(currcons, 0); - update_screen(fg_console); - printk("Console: %s %s %dx%d", - can_do_color ? "colour" : "mono", - display_desc, video_num_columns, video_num_lines); - printable = 1; - printk("\n"); - -#ifdef CONFIG_VT_CONSOLE - register_console(&vt_console_driver); -#endif -} - -#ifndef VT_SINGLE_DRIVER - -static void clear_buffer_attributes(int currcons) -{ - unsigned short *p = (unsigned short *) origin; - int count = screenbuf_size/2; - int mask = hi_font_mask | 0xff; - - for (; count > 0; count--, p++) { - scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p); - } -} - -/* - * If we support more console drivers, this function is used - * when a driver wants to take over some existing consoles - * and become default driver for newly opened ones. - */ - -void take_over_console(const struct consw *csw, int first, int last, int deflt) -{ - int i, j = -1; - const char *desc; - - desc = csw->con_startup(); - if (!desc) return; - if (deflt) - conswitchp = csw; - - for (i = first; i <= last; i++) { - int old_was_color; - int currcons = i; - - con_driver_map[i] = csw; - - if (!vc_cons[i].d || !vc_cons[i].d->vc_sw) - continue; - - j = i; - if (IS_VISIBLE) - save_screen(i); - old_was_color = vc_cons[i].d->vc_can_do_color; - vc_cons[i].d->vc_sw->con_deinit(vc_cons[i].d); - visual_init(i, 0); - update_attr(i); - - /* If the console changed between mono <-> color, then - * the attributes in the screenbuf will be wrong. The - * following resets all attributes to something sane. - */ - if (old_was_color != vc_cons[i].d->vc_can_do_color) - clear_buffer_attributes(i); - - if (IS_VISIBLE) - update_screen(i); - } - printk("Console: switching "); - if (!deflt) - printk("consoles %d-%d ", first+1, last+1); - if (j >= 0) - printk("to %s %s %dx%d\n", - vc_cons[j].d->vc_can_do_color ? "colour" : "mono", - desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows); - else - printk("to %s\n", desc); -} - -void give_up_console(const struct consw *csw) -{ - int i; - - for(i = 0; i < MAX_NR_CONSOLES; i++) - if (con_driver_map[i] == csw) - con_driver_map[i] = NULL; -} - -#endif - -/* - * Screen blanking - */ - -static void set_vesa_blanking(unsigned long arg) -{ - char *argp = (char *)arg + 1; - unsigned int mode; - get_user(mode, argp); - vesa_blank_mode = (mode < 4) ? mode : 0; -} - -/* We can't register the console with devfs during con_init(), because it - * is called before kmalloc() works. This function is called later to - * do the registration. - */ -void __init con_init_devfs (void) -{ - int i; - - for (i = 0; i < console_driver.num; i++) - tty_register_devfs (&console_driver, DEVFS_FL_AOPEN_NOTIFY, - console_driver.minor_start + i); -} - -/* - * This is called by a timer handler - */ -static void vesa_powerdown(void) -{ - struct vc_data *c = vc_cons[fg_console].d; - /* - * Power down if currently suspended (1 or 2), - * suspend if currently blanked (0), - * else do nothing (i.e. already powered down (3)). - * Called only if powerdown features are allowed. - */ - switch (vesa_blank_mode) { - case VESA_NO_BLANKING: - c->vc_sw->con_blank(c, VESA_VSYNC_SUSPEND+1); - break; - case VESA_VSYNC_SUSPEND: - case VESA_HSYNC_SUSPEND: - c->vc_sw->con_blank(c, VESA_POWERDOWN+1); - break; - } -} - -/* - * This is a timer handler - */ -static void vesa_powerdown_screen(unsigned long dummy) -{ - console_timer.function = unblank_screen_t; - - vesa_powerdown(); -} - -static void timer_do_blank_screen(int entering_gfx, int from_timer_handler) -{ - int currcons = fg_console; - int i; - - if (console_blanked) - return; - - /* entering graphics mode? */ - if (entering_gfx) { - hide_cursor(currcons); - save_screen(currcons); - sw->con_blank(vc_cons[currcons].d, -1); - console_blanked = fg_console + 1; - set_origin(currcons); - return; - } - - /* don't blank graphics */ - if (vcmode != KD_TEXT) { - console_blanked = fg_console + 1; - return; - } - - hide_cursor(currcons); - if (!from_timer_handler) - del_timer_sync(&console_timer); - if (vesa_off_interval) { - console_timer.function = vesa_powerdown_screen; - mod_timer(&console_timer, jiffies + vesa_off_interval); - } else { - if (!from_timer_handler) - del_timer_sync(&console_timer); - console_timer.function = unblank_screen_t; - } - - save_screen(currcons); - /* In case we need to reset origin, blanking hook returns 1 */ - i = sw->con_blank(vc_cons[currcons].d, 1); - console_blanked = fg_console + 1; - if (i) - set_origin(currcons); - - if (console_blank_hook && console_blank_hook(1)) - return; - if (vesa_blank_mode) - sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1); -} - -void do_blank_screen(int entering_gfx) -{ - timer_do_blank_screen(entering_gfx, 0); -} - -/* - * This is a timer handler - */ -static void unblank_screen_t(unsigned long dummy) -{ - unblank_screen(); -} - -/* - * Called by timer as well as from vt_console_driver - */ -void unblank_screen(void) -{ - int currcons; - - if (!console_blanked) - return; - if (!vc_cons_allocated(fg_console)) { - /* impossible */ - printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); - return; - } - currcons = fg_console; - if (vcmode != KD_TEXT) - return; /* but leave console_blanked != 0 */ - - console_timer.function = blank_screen; - if (blankinterval) { - mod_timer(&console_timer, jiffies + blankinterval); - } - - console_blanked = 0; - if (console_blank_hook) - console_blank_hook(0); - set_palette(currcons); - if (sw->con_blank(vc_cons[currcons].d, 0)) - /* Low-level driver cannot restore -> do it ourselves */ - update_screen(fg_console); - set_cursor(fg_console); -} - -/* - * This is both a user-level callable and a timer handler - */ -static void blank_screen(unsigned long dummy) -{ - timer_do_blank_screen(0, 1); -} - -void poke_blanked_console(void) -{ - del_timer(&console_timer); - if (!vt_cons[fg_console] || vt_cons[fg_console]->vc_mode == KD_GRAPHICS) - return; - if (console_blanked) { - console_timer.function = unblank_screen_t; - mod_timer(&console_timer, jiffies); /* Now */ - } else if (blankinterval) { - mod_timer(&console_timer, jiffies + blankinterval); - } -} - -/* - * Palettes - */ - -void set_palette(int currcons) -{ - if (vcmode != KD_GRAPHICS) - sw->con_set_palette(vc_cons[currcons].d, color_table); -} - -static int set_get_cmap(unsigned char *arg, int set) -{ - int i, j, k; - - for (i = 0; i < 16; i++) - if (set) { - get_user(default_red[i], arg++); - get_user(default_grn[i], arg++); - get_user(default_blu[i], arg++); - } else { - put_user(default_red[i], arg++); - put_user(default_grn[i], arg++); - put_user(default_blu[i], arg++); - } - if (set) { - for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i)) { - for (j = k = 0; j < 16; j++) { - vc_cons[i].d->vc_palette[k++] = default_red[j]; - vc_cons[i].d->vc_palette[k++] = default_grn[j]; - vc_cons[i].d->vc_palette[k++] = default_blu[j]; - } - set_palette(i); - } - } - return 0; -} - -/* - * Load palette into the DAC registers. arg points to a colour - * map, 3 bytes per colour, 16 colours, range from 0 to 255. - */ - -int con_set_cmap(unsigned char *arg) -{ - return set_get_cmap (arg,1); -} - -int con_get_cmap(unsigned char *arg) -{ - return set_get_cmap (arg,0); -} - -void reset_palette(int currcons) -{ - int j, k; - for (j=k=0; j<16; j++) { - palette[k++] = default_red[j]; - palette[k++] = default_grn[j]; - palette[k++] = default_blu[j]; - } - set_palette(currcons); -} - -/* - * Font switching - * - * Currently we only support fonts up to 32 pixels wide, at a maximum height - * of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, - * depending on width) reserved for each character which is kinda wasty, but - * this is done in order to maintain compatibility with the EGA/VGA fonts. It - * is upto the actual low-level console-driver convert data into its favorite - * format (maybe we should add a `fontoffset' field to the `display' - * structure so we wont have to convert the fontdata all the time. - * /Jes - */ - -#define max_font_size 65536 - -int con_font_op(int currcons, struct console_font_op *op) -{ - int rc = -EINVAL; - int size = max_font_size, set; - u8 *temp = NULL; - struct console_font_op old_op; - - if (vt_cons[currcons]->vc_mode != KD_TEXT) - goto quit; - memcpy(&old_op, op, sizeof(old_op)); - if (op->op == KD_FONT_OP_SET) { - if (!op->data) - return -EINVAL; - if (op->charcount > 512) - goto quit; - if (!op->height) { /* Need to guess font height [compat] */ - int h, i; - u8 *charmap = op->data, tmp; - - /* If from KDFONTOP ioctl, don't allow things which can be done in userland, - so that we can get rid of this soon */ - if (!(op->flags & KD_FONT_FLAG_OLD)) - goto quit; - rc = -EFAULT; - for (h = 32; h > 0; h--) - for (i = 0; i < op->charcount; i++) { - if (get_user(tmp, &charmap[32*i+h-1])) - goto quit; - if (tmp) - goto nonzero; - } - rc = -EINVAL; - goto quit; - nonzero: - rc = -EINVAL; - op->height = h; - } - if (op->width > 32 || op->height > 32) - goto quit; - size = (op->width+7)/8 * 32 * op->charcount; - if (size > max_font_size) - return -ENOSPC; - set = 1; - } else if (op->op == KD_FONT_OP_GET) - set = 0; - else - return sw->con_font_op(vc_cons[currcons].d, op); - if (op->data) { - temp = kmalloc(size, GFP_KERNEL); - if (!temp) - return -ENOMEM; - if (set && copy_from_user(temp, op->data, size)) { - rc = -EFAULT; - goto quit; - } - op->data = temp; - } - - acquire_console_sem(); - rc = sw->con_font_op(vc_cons[currcons].d, op); - release_console_sem(); - - op->data = old_op.data; - if (!rc && !set) { - int c = (op->width+7)/8 * 32 * op->charcount; - - if (op->data && op->charcount > old_op.charcount) - rc = -ENOSPC; - if (!(op->flags & KD_FONT_FLAG_OLD)) { - if (op->width > old_op.width || - op->height > old_op.height) - rc = -ENOSPC; - } else { - if (op->width != 8) - rc = -EIO; - else if ((old_op.height && op->height > old_op.height) || - op->height > 32) - rc = -ENOSPC; - } - if (!rc && op->data && copy_to_user(op->data, temp, c)) - rc = -EFAULT; - } -quit: if (temp) - kfree(temp); - return rc; -} - -/* - * Interface exported to selection and vcs. - */ - -/* used by selection */ -u16 screen_glyph(int currcons, int offset) -{ - u16 w = scr_readw(screenpos(currcons, offset, 1)); - u16 c = w & 0xff; - - if (w & hi_font_mask) - c |= 0x100; - return c; -} - -/* used by vcs - note the word offset */ -unsigned short *screen_pos(int currcons, int w_offset, int viewed) -{ - return screenpos(currcons, 2 * w_offset, viewed); -} - -void getconsxy(int currcons, char *p) -{ - p[0] = x; - p[1] = y; -} - -void putconsxy(int currcons, char *p) -{ - gotoxy(currcons, p[0], p[1]); - set_cursor(currcons); -} - -u16 vcs_scr_readw(int currcons, const u16 *org) -{ - if ((unsigned long)org == pos && softcursor_original != -1) - return softcursor_original; - return scr_readw(org); -} - -void vcs_scr_writew(int currcons, u16 val, u16 *org) -{ - scr_writew(val, org); - if ((unsigned long)org == pos) { - softcursor_original = -1; - add_softcursor(currcons); - } -} - -static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data) -{ - switch (rqst) - { - case PM_RESUME: - unblank_screen(); - break; - case PM_SUSPEND: - do_blank_screen(0); - break; - } - return 0; -} - -/* - * Visible symbols for modules - */ - -EXPORT_SYMBOL(color_table); -EXPORT_SYMBOL(default_red); -EXPORT_SYMBOL(default_grn); -EXPORT_SYMBOL(default_blu); -EXPORT_SYMBOL(video_font_height); -EXPORT_SYMBOL(video_scan_lines); -EXPORT_SYMBOL(vc_resize); -EXPORT_SYMBOL(fg_console); -EXPORT_SYMBOL(console_blank_hook); -#ifdef CONFIG_VT -EXPORT_SYMBOL(vt_cons); -#endif -#ifndef VT_SINGLE_DRIVER -EXPORT_SYMBOL(take_over_console); -EXPORT_SYMBOL(give_up_console); -#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/console_macros.h linux-2.5/drivers/char/console_macros.h --- linux-2.5.5/drivers/char/console_macros.h Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/char/console_macros.h Sun Mar 3 23:50:41 2002 @@ -1,70 +1,99 @@ -#define cons_num (vc_cons[currcons].d->vc_num) -#define sw (vc_cons[currcons].d->vc_sw) -#define screenbuf (vc_cons[currcons].d->vc_screenbuf) -#define screenbuf_size (vc_cons[currcons].d->vc_screenbuf_size) -#define origin (vc_cons[currcons].d->vc_origin) -#define scr_top (vc_cons[currcons].d->vc_scr_top) -#define visible_origin (vc_cons[currcons].d->vc_visible_origin) -#define scr_end (vc_cons[currcons].d->vc_scr_end) -#define pos (vc_cons[currcons].d->vc_pos) -#define top (vc_cons[currcons].d->vc_top) -#define bottom (vc_cons[currcons].d->vc_bottom) -#define x (vc_cons[currcons].d->vc_x) -#define y (vc_cons[currcons].d->vc_y) -#define vc_state (vc_cons[currcons].d->vc_state) -#define npar (vc_cons[currcons].d->vc_npar) -#define par (vc_cons[currcons].d->vc_par) -#define ques (vc_cons[currcons].d->vc_ques) -#define attr (vc_cons[currcons].d->vc_attr) -#define saved_x (vc_cons[currcons].d->vc_saved_x) -#define saved_y (vc_cons[currcons].d->vc_saved_y) -#define translate (vc_cons[currcons].d->vc_translate) -#define G0_charset (vc_cons[currcons].d->vc_G0_charset) -#define G1_charset (vc_cons[currcons].d->vc_G1_charset) -#define saved_G0 (vc_cons[currcons].d->vc_saved_G0) -#define saved_G1 (vc_cons[currcons].d->vc_saved_G1) -#define utf (vc_cons[currcons].d->vc_utf) -#define utf_count (vc_cons[currcons].d->vc_utf_count) -#define utf_char (vc_cons[currcons].d->vc_utf_char) -#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char) -#define disp_ctrl (vc_cons[currcons].d->vc_disp_ctrl) -#define toggle_meta (vc_cons[currcons].d->vc_toggle_meta) -#define decscnm (vc_cons[currcons].d->vc_decscnm) -#define decom (vc_cons[currcons].d->vc_decom) -#define decawm (vc_cons[currcons].d->vc_decawm) -#define deccm (vc_cons[currcons].d->vc_deccm) -#define decim (vc_cons[currcons].d->vc_decim) -#define deccolm (vc_cons[currcons].d->vc_deccolm) -#define need_wrap (vc_cons[currcons].d->vc_need_wrap) -#define kmalloced (vc_cons[currcons].d->vc_kmalloced) -#define report_mouse (vc_cons[currcons].d->vc_report_mouse) -#define color (vc_cons[currcons].d->vc_color) -#define s_color (vc_cons[currcons].d->vc_s_color) -#define def_color (vc_cons[currcons].d->vc_def_color) +#define cons_num (vc->vc_num) +#define video_num_columns (vc->vc_cols) +#define video_num_lines (vc->vc_rows) +#define video_size_row (vc->vc_size_row) +#define vcmode (vc->vc_mode) +#define can_do_color (vc->vc_can_do_color) +#define screenbuf (vc->vc_screenbuf) +#define screenbuf_size (vc->vc_screenbuf_size) +#define origin (vc->vc_origin) +#define scr_top (vc->vc_scr_top) +#define visible_origin (vc->vc_visible_origin) +#define scr_end (vc->vc_scr_end) +#define pos (vc->vc_pos) +#define top (vc->vc_top) +#define bottom (vc->vc_bottom) +#define x (vc->vc_x) +#define y (vc->vc_y) +#define vc_state (vc->vc_state) +#define npar (vc->vc_npar) +#define par (vc->vc_par) +#define ques (vc->vc_ques) +#define attr (vc->vc_attr) +#define saved_x (vc->vc_saved_x) +#define saved_y (vc->vc_saved_y) +#define translate (vc->vc_translate) +#define G0_charset (vc->vc_G0_charset) +#define G1_charset (vc->vc_G1_charset) +#define saved_G0 (vc->vc_saved_G0) +#define saved_G1 (vc->vc_saved_G1) +#define utf (vc->vc_utf) +#define utf_count (vc->vc_utf_count) +#define utf_char (vc->vc_utf_char) +#define video_erase_char (vc->vc_video_erase_char) +#define disp_ctrl (vc->vc_disp_ctrl) +#define toggle_meta (vc->vc_toggle_meta) +#define decscnm (vc->vc_decscnm) +#define decom (vc->vc_decom) +#define decawm (vc->vc_decawm) +#define deccm (vc->vc_deccm) +#define decim (vc->vc_decim) +#define deccolm (vc->vc_deccolm) +#define need_wrap (vc->vc_need_wrap) +#define kmalloced (vc->vc_kmalloced) +#define report_mouse (vc->vc_report_mouse) +#define color (vc->vc_color) +#define s_color (vc->vc_s_color) +#define def_color (vc->vc_def_color) #define foreground (color & 0x0f) #define background (color & 0xf0) -#define charset (vc_cons[currcons].d->vc_charset) -#define s_charset (vc_cons[currcons].d->vc_s_charset) -#define intensity (vc_cons[currcons].d->vc_intensity) -#define underline (vc_cons[currcons].d->vc_underline) -#define blink (vc_cons[currcons].d->vc_blink) -#define reverse (vc_cons[currcons].d->vc_reverse) -#define s_intensity (vc_cons[currcons].d->vc_s_intensity) -#define s_underline (vc_cons[currcons].d->vc_s_underline) -#define s_blink (vc_cons[currcons].d->vc_s_blink) -#define s_reverse (vc_cons[currcons].d->vc_s_reverse) -#define ulcolor (vc_cons[currcons].d->vc_ulcolor) -#define halfcolor (vc_cons[currcons].d->vc_halfcolor) -#define tab_stop (vc_cons[currcons].d->vc_tab_stop) -#define palette (vc_cons[currcons].d->vc_palette) -#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch) -#define bell_duration (vc_cons[currcons].d->vc_bell_duration) -#define cursor_type (vc_cons[currcons].d->vc_cursor_type) -#define display_fg (vc_cons[currcons].d->vc_display_fg) -#define complement_mask (vc_cons[currcons].d->vc_complement_mask) -#define s_complement_mask (vc_cons[currcons].d->vc_s_complement_mask) -#define hi_font_mask (vc_cons[currcons].d->vc_hi_font_mask) +#define charset (vc->vc_charset) +#define s_charset (vc->vc_s_charset) +#define intensity (vc->vc_intensity) +#define underline (vc->vc_underline) +#define blink (vc->vc_blink) +#define reverse (vc->vc_reverse) +#define s_intensity (vc->vc_s_intensity) +#define s_underline (vc->vc_s_underline) +#define s_blink (vc->vc_s_blink) +#define s_reverse (vc->vc_s_reverse) +#define ulcolor (vc->vc_ulcolor) +#define halfcolor (vc->vc_halfcolor) +#define tab_stop (vc->vc_tab_stop) +#define palette (vc->vc_palette) +#define bell_pitch (vc->vc_bell_pitch) +#define bell_duration (vc->vc_bell_duration) +#define cursor_type (vc->vc_cursor_type) +#define complement_mask (vc->vc_complement_mask) +#define s_complement_mask (vc->vc_s_complement_mask) +#define hi_font_mask (vc->vc_hi_font_mask) -#define vcmode (vt_cons[currcons]->vc_mode) +#define dectcem (vc->vc_dectcem) +#define decscl (vc->vc_decscl) +#define c8bit (vc->vc_c8bit) +#define d8bit (vc->vc_d8bit) +#define shift (vc->vc_shift) +#define priv1 (vc->vc_priv1) +#define priv2 (vc->vc_priv2) +#define priv3 (vc->vc_priv3) +#define priv4 (vc->vc_priv4) +#define decckm (vc->vc_decckm) +#define decsclm (vc->vc_decsclm) +#define decarm (vc->vc_decarm) +#define decnrcm (vc->vc_decnrcm) +#define decnkm (vc->vc_decnkm) +#define kam (vc->vc_kam) +#define crm (vc->vc_crm) +#define lnm (vc->vc_lnm) +#define irm (vc->vc_irm) +#define GL_charset (vc->vc_GL_charset) +#define GR_charset (vc->vc_GR_charset) +#define G2_charset (vc->vc_G2_charset) +#define G3_charset (vc->vc_G3_charset) +#define GS_charset (vc->vc_GS_charset) +#define saved_G2 (vc->vc_saved_G2) +#define saved_G3 (vc->vc_saved_G3) +#define saved_GS (vc->vc_saved_GS) -#define structsize (sizeof(struct vc_data) + sizeof(struct vt_struct)) +#define sw (vc->display_fg->vt_sw) +#define softcursor_original (vc->display_fg->cursor_original) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/consolemap.c linux-2.5/drivers/char/consolemap.c --- linux-2.5.5/drivers/char/consolemap.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/char/consolemap.c Sun Mar 3 23:50:41 2002 @@ -19,7 +19,6 @@ #include #include #include -#include #include static unsigned short translations[][256] = { @@ -182,7 +181,7 @@ static struct uni_pagedir *dflt; -static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i) +static void set_inverse_transl(struct vc_data *vc, struct uni_pagedir *p, int i) { int j, glyph; unsigned short *t = translations[i]; @@ -199,7 +198,7 @@ memset(q, 0, MAX_GLYPH); for (j = 0; j < E_TABSZ; j++) { - glyph = conv_uni_to_pc(conp, t[j]); + glyph = conv_uni_to_pc(vc, t[j]); if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) { /* prefer '-' above SHY etc. */ q[glyph] = j; @@ -207,10 +206,10 @@ } } -unsigned short *set_translate(int m,int currcons) +void set_translate(struct vc_data *vc, int m) { - inv_translate[currcons] = m; - return translations[m]; + inv_translate[vc->vc_num] = m; + vc->vc_translate = translations[m]; } /* @@ -220,29 +219,32 @@ * was active, or using Unicode. * Still, it is now possible to a certain extent to cut and paste non-ASCII. */ -unsigned char inverse_translate(struct vc_data *conp, int glyph) +unsigned char inverse_translate(struct vc_data *vc, int glyph) { struct uni_pagedir *p; if (glyph < 0 || glyph >= MAX_GLYPH) return 0; - else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) || - !p->inverse_translations[inv_translate[conp->vc_num]]) + else if (!(p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc) || + !p->inverse_translations[inv_translate[vc->vc_num]]) return glyph; else - return p->inverse_translations[inv_translate[conp->vc_num]][glyph]; + return p->inverse_translations[inv_translate[vc->vc_num]][glyph]; } static void update_user_maps(void) { - int i; struct uni_pagedir *p, *q = NULL; + struct vc_data *vc; + int i; for (i = 0; i < MAX_NR_CONSOLES; i++) { - if (!vc_cons_allocated(i)) + vc = vt_cons->vc_cons[i]; + + if (!vc) continue; - p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p && p != q) { - set_inverse_transl(vc_cons[i].d, p, USER_MAP); + set_inverse_transl(vc, p, USER_MAP); q = p; } } @@ -286,7 +288,7 @@ for (i=0; ivc_cons[fg_console], p[i]); __put_user((ch & ~0xff) ? 0 : ch, arg+i); } return 0; @@ -363,28 +365,29 @@ } } -void con_free_unimap(int con) +void con_free_unimap(struct vc_data *vc) { struct uni_pagedir *p; - struct vc_data *conp = vc_cons[con].d; - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (!p) return; - *conp->vc_uni_pagedir_loc = 0; + *vc->vc_uni_pagedir_loc = 0; if (--p->refcount) return; con_release_unimap(p); kfree(p); } -static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p) +static int con_unify_unimap(struct vc_data *vc, struct uni_pagedir *p) { int i, j, k; struct uni_pagedir *q; for (i = 0; i < MAX_NR_CONSOLES; i++) { - if (!vc_cons_allocated(i)) + struct vc_data *tmp = vc->display_fg->vc_cons[i]; + + if (!tmp) continue; - q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; + q = (struct uni_pagedir *)*tmp->vc_uni_pagedir_loc; if (!q || q == p || q->sum != p->sum) continue; for (j = 0; j < 32; j++) { @@ -407,7 +410,7 @@ } if (j == 32) { q->refcount++; - *conp->vc_uni_pagedir_loc = (unsigned long)q; + *vc->vc_uni_pagedir_loc = (unsigned long)q; con_release_unimap(p); kfree(p); return 1; @@ -443,12 +446,11 @@ } /* ui is a leftover from using a hashtable, but might be used again */ -int con_clear_unimap(int con, struct unimapinit *ui) +int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) { struct uni_pagedir *p, *q; - struct vc_data *conp = vc_cons[con].d; - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p && p->readonly) return -EIO; if (!p || --p->refcount) { q = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL); @@ -458,7 +460,7 @@ } memset(q, 0, sizeof(*q)); q->refcount=1; - *conp->vc_uni_pagedir_loc = (unsigned long)q; + *vc->vc_uni_pagedir_loc = (unsigned long)q; } else { if (p == dflt) dflt = NULL; p->refcount++; @@ -469,13 +471,12 @@ } int -con_set_unimap(int con, ushort ct, struct unipair *list) +con_set_unimap(struct vc_data *vc, ushort ct, struct unipair *list) { - int err = 0, err1, i; struct uni_pagedir *p, *q; - struct vc_data *conp = vc_cons[con].d; - - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + int err = 0, err1, i; + + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p->readonly) return -EIO; if (!ct) return 0; @@ -484,10 +485,10 @@ int j, k; u16 **p1, *p2, l; - err1 = con_clear_unimap(con, NULL); + err1 = con_clear_unimap(vc, NULL); if (err1) return err1; - q = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; for (i = 0, l = 0; i < 32; i++) if ((p1 = p->uni_pgdir[i])) for (j = 0; j < 32; j++) @@ -497,7 +498,7 @@ err1 = con_insert_unipair(q, l, p2[k]); if (err1) { p->refcount++; - *conp->vc_uni_pagedir_loc = (unsigned long)p; + *vc->vc_uni_pagedir_loc = (unsigned long)p; con_release_unimap(q); kfree(q); return err1; @@ -516,12 +517,11 @@ list++; } - if (con_unify_unimap(conp, p)) + if (con_unify_unimap(vc, p)) return err; for (i = 0; i <= 3; i++) - set_inverse_transl(conp, p, i); /* Update all inverse translations */ - + set_inverse_transl(vc, p, i); /* Update all inverse translations */ return err; } @@ -531,19 +531,18 @@ PIO_FONTRESET ioctl is called. */ int -con_set_default_unimap(int con) +con_set_default_unimap(struct vc_data *vc) { int i, j, err = 0, err1; u16 *q; struct uni_pagedir *p; - struct vc_data *conp = vc_cons[con].d; if (dflt) { - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p == dflt) return 0; dflt->refcount++; - *conp->vc_uni_pagedir_loc = (unsigned long)dflt; + *vc->vc_uni_pagedir_loc = (unsigned long)dflt; if (p && --p->refcount) { con_release_unimap(p); kfree(p); @@ -552,11 +551,10 @@ } /* The default font is always 256 characters */ - - err = con_clear_unimap(con,NULL); + err = con_clear_unimap(vc, NULL); if (err) return err; - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; q = dfont_unitable; for (i = 0; i < 256; i++) @@ -566,29 +564,27 @@ err = err1; } - if (con_unify_unimap(conp, p)) { - dflt = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + if (con_unify_unimap(vc, p)) { + dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; return err; } for (i = 0; i <= 3; i++) - set_inverse_transl(conp, p, i); /* Update all inverse translations */ + set_inverse_transl(vc, p, i); /* Update all inverse translations */ dflt = p; return err; } int -con_copy_unimap(int dstcon, int srccon) +con_copy_unimap(struct vc_data *dconp, struct vc_data *sconp) { - struct vc_data *sconp = vc_cons[srccon].d; - struct vc_data *dconp = vc_cons[dstcon].d; struct uni_pagedir *q; - if (!vc_cons_allocated(srccon) || !*sconp->vc_uni_pagedir_loc) + if (!sconp || !*sconp->vc_uni_pagedir_loc) return -EINVAL; if (*dconp->vc_uni_pagedir_loc == *sconp->vc_uni_pagedir_loc) return 0; - con_free_unimap(dstcon); + con_free_unimap(dconp); q = (struct uni_pagedir *)*sconp->vc_uni_pagedir_loc; q->refcount++; *dconp->vc_uni_pagedir_loc = (long)q; @@ -596,16 +592,15 @@ } int -con_get_unimap(int con, ushort ct, ushort *uct, struct unipair *list) +con_get_unimap(struct vc_data *vc, ushort ct, ushort *uct, struct unipair *list) { int i, j, k, ect; u16 **p1, *p2; struct uni_pagedir *p; - struct vc_data *conp = vc_cons[con].d; ect = 0; - if (*conp->vc_uni_pagedir_loc) { - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + if (*vc->vc_uni_pagedir_loc) { + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; for (i = 0; i < 32; i++) if ((p1 = p->uni_pgdir[i])) for (j = 0; j < 32; j++) @@ -625,16 +620,16 @@ return ((ect <= ct) ? 0 : -ENOMEM); } -void con_protect_unimap(int con, int rdonly) +void con_protect_unimap(struct vc_data *vc, int rdonly) { struct uni_pagedir *p = (struct uni_pagedir *) - *vc_cons[con].d->vc_uni_pagedir_loc; + *vc->vc_uni_pagedir_loc; if (p) p->readonly = rdonly; } int -conv_uni_to_pc(struct vc_data *conp, long ucs) +conv_uni_to_pc(struct vc_data *vc, long ucs) { int h; u16 **p1, *p2; @@ -655,10 +650,10 @@ else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE) return ucs & UNI_DIRECT_MASK; - if (!*conp->vc_uni_pagedir_loc) + if (!*vc->vc_uni_pagedir_loc) return -3; - p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; + p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if ((p1 = p->uni_pgdir[ucs >> 11]) && (p2 = p1[(ucs >> 6) & 0x1f]) && (h = p2[ucs & 0x3f]) < MAX_GLYPH) @@ -677,7 +672,10 @@ { int i; - for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc) - con_set_default_unimap(i); + for (i = 0; i < MAX_NR_CONSOLES; i++) { + struct vc_data *vc = vt_cons->vc_cons[i]; + + if (vc && !*vc->vc_uni_pagedir_loc) + con_set_default_unimap(vc); + } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/cyclades.c linux-2.5/drivers/char/cyclades.c --- linux-2.5.5/drivers/char/cyclades.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/char/cyclades.c Sun Jan 6 01:38:26 2002 @@ -4965,6 +4965,8 @@ uclong Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0; uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS]; unsigned char Ze_irq[NR_CARDS]; + struct resource *resource; + unsigned long res_start, res_len; for (i = 0; i < NR_CARDS; i++) { /* look for a Cyclades card by vendor and device id */ @@ -5012,7 +5014,15 @@ /* Although we don't use this I/O region, we should request it from the kernel anyway, to avoid problems with other drivers accessing it. */ - request_region(cy_pci_phys1, CyPCI_Yctl, "Cyclom-Y"); + resource = request_region(cy_pci_phys1, + CyPCI_Yctl, "Cyclom-Y"); + if (resource == NULL) { + printk(KERN_ERR "cyclades: failed to allocate IO " + "resource at 0x%lx\n", cy_pci_phys1); + continue; + } + res_start = cy_pci_phys1; + res_len = CyPCI_Yctl; #if defined(__alpha__) if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ @@ -5083,7 +5093,11 @@ cy_card[j].bus_index = 1; cy_card[j].first_line = cy_next_channel; cy_card[j].num_chips = cy_pci_nchan/4; - + cy_card[j].resource = resource; + cy_card[j].res_start = res_start; + cy_card[j].res_len = res_len; + resource = NULL; /* For next card */ + /* enable interrupts in the PCI interface */ plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f; switch (plx_ver) { @@ -5162,8 +5176,16 @@ /* Although we don't use this I/O region, we should request it from the kernel anyway, to avoid problems with other drivers accessing it. */ - request_region(cy_pci_phys1, CyPCI_Zctl, "Cyclades-Z"); - + resource = request_region(cy_pci_phys1, + CyPCI_Zctl, "Cyclades-Z"); + if (resource == NULL) { + printk(KERN_ERR "cyclades: failed ot allocate IO resource " + "at 0x%lx\n", cy_pci_phys1); + continue; + } + res_start = cy_pci_phys1; + res_len = CyPCI_Zctl; + if (mailbox == ZE_V1) { cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win); if (ZeIndex == NR_CARDS) { @@ -5261,6 +5283,10 @@ cy_card[j].bus_index = 1; cy_card[j].first_line = cy_next_channel; cy_card[j].num_chips = -1; + cy_card[j].resource = resource; + cy_card[j].res_start = res_start; + cy_card[j].res_len = res_len; + resource = NULL; /* For next card */ /* print message */ #ifdef CONFIG_CYZ_INTR @@ -5279,7 +5305,7 @@ printk("%d channels starting from port %d.\n", cy_pci_nchan,cy_next_channel); cy_next_channel += cy_pci_nchan; - } + } } for (; ZeIndex != 0 && i < NR_CARDS; i++) { @@ -5787,6 +5813,8 @@ #endif /* CONFIG_CYZ_INTR */ ) free_irq(cy_card[i].irq, &cy_card[i]); + if (cy_card[i].resource) + release_region(cy_card[i].res_start, cy_card[i].res_len); } } if (tmp_buf) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/decvte.c linux-2.5/drivers/char/decvte.c --- linux-2.5.5/drivers/char/decvte.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/decvte.c Sun Mar 3 23:50:41 2002 @@ -0,0 +1,2029 @@ +/* + * decvte.c - DEC VT terminal emulation code. + * Copyright (C) 2000 James Simmons + * + * I moved all the VT emulation code out of console.c to here. It makes life + * much easier and the code smaller. It also allows other devices to emulate + * a TTY besides the video system. People can also change the makefile to + * support a different emulation if they wanted. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "console_macros.h" + +/* + * DEC VT emulator + */ + +/* Different states of the emulator */ +enum { ESinit, + /* ESC substates */ + ESesc, ESacs, ESscf, ESgzd4, ESg1d4, ESg2d4, + ESg3d4, ESg1d6, ESg2d6, ESg3d6, ESdocs, + /* CSI substates */ + EScsi, EScsi_getpars, EScsi_gotpars, EScsi_space, + EScsi_exclam, EScsi_dquote, EScsi_dollar, EScsi_and, + EScsi_squote, EScsi_star, EScsi_plus, + /* OSC substates */ + ESosc, ESpalette, + /* Misc. states */ + ESfunckey, ESignore, +}; + +#define __VTE_CSI (c8bit == 0 ? "\033[" : "\233") +#define __VTE_DCS (c8bit == 0 ? "\033P" : "\220") +#define __VTE_ST (c8bit == 0 ? "\033\\" : "\234") +#define __VTE_APC (c8bit == 0 ? "\033_" : "\237") + +/* + * this is what the terminal answers to a ESC-Z or csi0c query. + */ +#define VT100ID "\033[?1;2c" +#define VT102ID "\033[?6c" + +/* + * Here is the default bell parameters: 750HZ, 1/8th of a second + */ +#define DEFAULT_BELL_PITCH 750 +#define DEFAULT_BELL_DURATION (HZ/8) + +/* + * LINE FEED (LF) + */ +void vte_lf(struct vc_data *vc) +{ + /* don't scroll if above bottom of scrolling region, or + * if below scrolling region + */ + if (y+1 == bottom) + scrup(vc, top, bottom, 1); + else if (y < video_num_lines-1) { + y++; + pos += video_size_row; + } + need_wrap = 0; +} + +/* + * REVERSE LINE FEED (RI) + */ +static void vte_ri(struct vc_data *vc) +{ + /* don't scroll if below top of scrolling region, or + * if above scrolling region + */ + if (y == top) + scrdown(vc, top, bottom, 1); + else if (y > 0) { + y--; + pos -= video_size_row; + } + need_wrap = 0; +} + +/* + * CARRIAGE RETURN (CR) + */ +inline void vte_cr(struct vc_data *vc) +{ + pos -= x<<1; + need_wrap = x = 0; +} + +/* + * BACK SPACE (BS) + */ +inline void vte_bs(struct vc_data *vc) +{ + if (x) { + pos -= 2; + x--; + need_wrap = 0; + } +} + +/* + * CURSOR LINE TABULATION (CVT) + * + * NOTE: + * In accordance with our interpretation of VT as LF we will treat CVT as + * (par[0] * LF). Not very creative, but at least consequent. + */ +static void vte_cvt(struct vc_data *vc, int vpar) +{ + int i; + + for (i = 0; i < vpar; i++) { + vte_lf(vc); + } +} + +/* + * CURSOR BACKWARD TABULATION (CBT) + */ +static void vte_cbt(struct vc_data *vc, int vpar) +{ + int i; + + for (i = 0; i < vpar; i++) { + pos -= (x << 1); + while (x > 0) { + x--; + if (tab_stop[x >> 5] & (1 << (x & 31))) + break; + } + pos += (x << 1); + } +} + +/* + * CURSOR FORWARD TABULATION (CHT) + */ +static void vte_cht(struct vc_data *vc, int vpar) +{ + int i; + + for (i = 0; i < vpar; i++) { + pos -= (x << 1); + while (x < video_num_columns - 1) { + x++; + if (tab_stop[x >> 5] & (1 << (x & 31))) + break; + } + pos += (x << 1); + } +} + +/* + * ERASE IN PAGE (ED) + */ +void vte_ed(struct vc_data *vc, int vpar) +{ + unsigned short *start; + unsigned int count; + + switch (vpar) { + case 0: /* erase from cursor to end of display */ + count = (scr_end-pos)>>1; + start = (unsigned short *) pos; + /* do in two stages */ + clear_region(vc, x, y, video_num_columns-x, 1); + clear_region(vc, 0, y+1, video_num_columns, + video_num_lines-y-1); + break; + case 1: /* erase from start to cursor */ + count = ((pos-origin)>>1)+1; + start = (unsigned short *) origin; + /* do in two stages */ + clear_region(vc, 0, 0, video_num_columns, y); + clear_region(vc, 0, y, x + 1, 1); + break; + case 2: /* erase whole display */ + count = video_num_columns * video_num_lines; + start = (unsigned short *) origin; + clear_region(vc, 0, 0, video_num_columns, + video_num_lines); + break; + default: + return; + } + scr_memsetw(start, video_erase_char, 2*count); + need_wrap = 0; +} + +/* + * ERASE IN LINE (EL) + */ +static void vte_el(struct vc_data *vc, int vpar) +{ + unsigned int count; + unsigned short * start; + + switch (vpar) { + case 0: /* erase from cursor to end of line */ + count = video_num_columns-x; + start = (unsigned short *) pos; + clear_region(vc, x, y, video_num_columns-x, 1); + break; + case 1: /* erase from start of line to cursor */ + start = (unsigned short *) (pos - (x<<1)); + count = x+1; + clear_region(vc, 0, y, x + 1, 1); + break; + case 2: /* erase whole line */ + start = (unsigned short *) (pos - (x<<1)); + count = video_num_columns; + clear_region(vc, 0, y, video_num_columns, 1); + break; + default: + return; + } + scr_memsetw(start, video_erase_char, 2 * count); + need_wrap = 0; +} + +/* + * Erase character (ECH) + * + * NOTE: This function is not available in DEC VT1xx terminals. + */ +static void vte_ech(struct vc_data *vc, int vpar) +{ + int count; + + if (!vpar) + vpar++; + count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar; + + scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count); + clear_region(vc, x, y, count, 1); + need_wrap = 0; +} + +/* + * SELECT GRAPHIC RENDITION (SGR) + * + * NOTE: The DEC vt1xx series only implements attribute values 0,1,4,5 and 7. + */ +static void vte_sgr(struct vc_data *vc) +{ + int i; + + for (i=0;i<=npar;i++) + switch (par[i]) { + case 0: /* all attributes off */ + default_attr(vc); + break; + case 1: /* bold or increased intensity */ + intensity = 2; + break; + case 2: /* faint or decreased intensity */ + intensity = 0; + break; + case 4: /* singly underlined. */ + underline = 1; + break; + case 5: /* slowly blinking (< 2.5 Hz) */ + case 6: /* rapidly blinking (>= 2.5 Hz) */ + blink = 1; + break; + case 7: /* negative image */ + reverse = 1; + break; + case 10:/* primary (default) font + * ANSI X3.64-1979 (SCO-ish?) + * Select primary font, don't display + * control chars if defined, don't set + * bit 8 on output. + */ + set_translate(vc, charset == 0 ? + G0_charset : G1_charset); + disp_ctrl = 0; + toggle_meta = 0; + break; + case 11:/* first alternative font + * ANSI X3.64-1979 (SCO-ish?) + * Select first alternate font, lets + * chars < 32 be displayed as ROM chars. + */ + set_translate(vc, IBMPC_MAP); + disp_ctrl = 1; + toggle_meta = 0; + break; + case 12:/* second alternative font + * Select second alternate font, toggle + * high bit before displaying as ROM char. + */ + set_translate(vc, IBMPC_MAP); + disp_ctrl = 1; + toggle_meta = 1; + break; + case 21:/* normal intensity */ + case 22:/* normal intensity */ + intensity = 1; + break; + case 24:/* not underlined (neither singly nor doubly) */ + underline = 0; + break; + case 25:/* steady (not blinking) */ + blink = 0; + break; + case 27:/* positive image */ + reverse = 0; + break; + case 38:/* foreground color (ISO 8613-6/ITU T.416) + * Enables underscore, white foreground + * with white underscore (Linux - use + * default foreground). + */ + color = (def_color & 0x0f) | background; + underline = 1; + break; + case 39:/* default display color */ + color = (def_color & 0x0f) | background; + underline = 0; + break; + case 49:/* default background color */ + color = (def_color & 0xf0) | foreground; + break; + default: + if (par[i] >= 30 && par[i] <= 37) + color = color_table[par[i]-30] + | background; + else if (par[i] >= 40 && par[i] <= 47) + color = (color_table[par[i]-40]<<4) + | foreground; + break; + } + update_attr(vc); +} + +/* + * Fake a DEC DSR for non-implemented features + */ +static void vte_fake_dec_dsr(struct tty_struct *tty, char *reply) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + sprintf(buf, "%s?%sn", __VTE_CSI, reply); + respond_string(buf, tty); +} + +/* + * CURSOR POSITION REPORT (CPR) + * DEC EXTENDED CURSOR POSITION REPORT (DECXCPR) + */ +static void vte_cpr(struct tty_struct *tty, int ext) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + if (ext) { + /* + * NOTE: Since we do not (yet?) implement any form of page + * memory, we will always return the cursor position in page 1. + */ + sprintf(buf, "%s?%d;%d;1R", __VTE_CSI, + y + (decom ? top + 1 : 1), x+1); + } else { + sprintf(buf, "%s%d;%dR", __VTE_CSI, + y + (decom ? top + 1 : 1), x+1); + } + respond_string(buf, tty); +} + +/* + * DEVICE STATUS REPORT (DSR) + */ +static inline void vte_dsr(struct tty_struct * tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + sprintf(buf, "%s0n", __VTE_CSI); + respond_string(buf, tty); +} + +/* + * ANSWERBACK MESSAGE + */ +static inline void vte_answerback(struct tty_struct *tty) +{ + respond_string("l i n u x", tty); +} + +/* + * DA - DEVICE ATTRIBUTE + */ +static inline void vte_da(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + /* We claim VT220 compatibility... */ + sprintf(buf, "%s?62;1;2;6;7;8;9c", __VTE_CSI); + respond_string(buf, tty); +} + +#define VTE_VERSION 211 +/* + * DA - SECONDARY DEVICE ATTRIBUTE [VT220 and up] + * + * Reply parameters: + * 1 = Model (1=vt220, 18=vt330, 19=vt340, 41=vt420) + * 2 = Firmware version (nn = n.n) + * 3 = Installed options (0 = none) + */ +static void vte_dec_da2(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + sprintf(buf, "%s>%d;%d;0c", __VTE_CSI, 1, VTE_VERSION / 10); + respond_string(buf, tty); +} + +/* + * DA - TERTIARY DEVICE ATTRIBUTE [VT220 and up] + * + * Reply: unit ID (we report "0") + */ +static void vte_dec_da3(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + sprintf(buf, "%s!|%s%s", __VTE_DCS, "0", __VTE_ST); + respond_string(buf, tty); +} + +/* + * DECREPTPARM - DEC REPORT TERMINAL PARAMETERS [VT1xx/VT2xx/VT320] + */ +static void vte_decreptparm(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + sprintf(buf, "\033[%d;1;1;120;120;1;0x", par[0] + 2); + respond_string(buf, tty); +} + +/* + * SM - SET MODE / + * RM - RESET MODE + */ +static void set_mode(struct vc_data *vc, int on_off) +{ + int i; + + for (i=0; i<=npar; i++) + /* DEC private modes set/reset */ + if (priv4) switch(par[i]) { + case 1: /* DECCKM - Cursor keys mode */ + if (on_off) + set_kbd_mode(&vc->kbd_table, VC_CKMODE); + else + clr_kbd_mode(&vc->kbd_table, VC_CKMODE); + break; + case 2: /* DECANM - ANSI mode */ + break; + case 3: /* DECCOLM - Column mode */ +#if 0 + deccolm = on_off; + (void) vc_resize(video_num_lines, deccolm ? 132 +: 80); + /* this alone does not suffice; some user mode + utility has to change the hardware regs */ +#endif + break; + case 4: /* DECSCLM - Scrolling mode */ + break; + case 5: /* DECSCNM - Screen mode */ + if (decscnm != on_off) { + decscnm = on_off; + invert_screen(vc, 0, screenbuf_size, 0); + update_attr(vc); + } + break; + case 6: /* DECOM - Origin mode */ + decom = on_off; + gotoxay(vc, 0, 0); + break; + case 7: /* DECAWM - Autowrap mode */ + decawm = on_off; + break; + case 8: /* DECARM - Autorepeat mode */ + decarm = on_off; + if (on_off) + set_kbd_mode(&vc->kbd_table, VC_REPEAT); + else + clr_kbd_mode(&vc->kbd_table, VC_REPEAT); + break; + case 9: + report_mouse = on_off ? 1 : 0; + break; + case 25: /* DECTCEM - Text cursor enable mode */ + dectcem = on_off; + break; + case 42: /* DECNCRS - National character set replacement mode */ + break; + case 60: /* DECHCCM - Horizontal cursor coupling mode */ break; + case 61: /* DECVCCM - Vertical cursor coupling mode */ + break; + case 64: /* DECPCCM - Page cursor coupling mode */ + break; + case 66: /* DECNKM - Numeric keybad mode */ + decnkm = on_off; + if (on_off) + set_kbd_mode(&vc->kbd_table, VC_APPLIC); + else + clr_kbd_mode(&vc->kbd_table, VC_APPLIC); + break; + case 67: /* DECBKM - Backarrow key mode */ + break; + case 68: /* DECKBUM - Keyboard usage mode */ + break; + case 69: /* DECVSSM - Vertical split screen mode +*/ + break; + case 73: /* DECXRLM - Transfer rate limiting mode */ + break; + case 81: /* DECKPM - Keyboard position mode */ + break; + case 1000: + report_mouse = on_off ? 2 : 0; + break; + } else switch(par[i]) { /* ANSI modes set/reset */ + case 3: /* Monitor (display ctrls) */ + disp_ctrl = on_off; + break; + case 4: /* Insert Mode on/off */ + irm = on_off; + break; + case 20: /* Lf, Enter == CrLf/Lf */ + if (on_off) + set_kbd_mode(&vc->kbd_table, VC_CRLF); + else + clr_kbd_mode(&vc->kbd_table, VC_CRLF); + break; + } +} + +/* + * DECCIR - Cursor information report + */ +static void vte_deccir(struct tty_struct *tty) +{ + /* not yet implemented */ +} + +/* + * DECMSR - Macro space report + */ +static void vte_decmsr(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + sprintf(buf, "%s%d*{", __VTE_CSI, 0); /* No space left */ + respond_string(buf, tty); +} + +/* + * DECRPM - Report mode + */ +static void vte_decrpm(struct tty_struct *tty, int priv, int mode, int status) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char buf[40]; + + if (status == 0) { + status = 2; + } else { + if (status == 2) { + status = 0; + } + } + + if (priv) + sprintf(buf, "%s?%d;%d$y", __VTE_CSI, mode, status); + else + sprintf(buf, "%s%d;%d$y", __VTE_CSI, mode, status); + respond_string(buf, tty); +} + +/* + * DECRQM - Request mode + * + * Reply codes: + * 0 = reset + * 1 = set + * 2 = unknown + * 3 = premanently set + * 4 = permanently reset + */ +static void vte_decrqm(struct tty_struct *tty, int priv) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + + if (priv) { + switch (par[0]) { + case 1: /* DECCKM - Cursor keys mode */ + vte_decrpm(tty, priv, par[0], decckm); + break; + case 2: /* DECANM */ + case 3: /* DECCOLM */ + case 4: /* DECSCLM */ + vte_decrpm(tty, priv, par[0], 4); + break; + case 5: /* DECSCNM */ + vte_decrpm(tty, priv, par[0], decscnm); + break; + case 6: /* DECOM */ + vte_decrpm(tty, priv, par[0], decom); + break; + case 7: /* DECAWM */ + vte_decrpm(tty, priv, par[0], decawm); + break; + case 8: /* DECARM */ + vte_decrpm(tty, priv, par[0], decarm); + break; + case 25: /* DECTCEM */ + vte_decrpm(tty, priv, par[0], dectcem); + break; + case 42: /* DECNCRM */ + case 60: /* DECHCCM */ + case 61: /* DECVCCM */ + case 64: /* DECPCCM */ + vte_decrpm(tty, priv, par[0], 4); + break; + case 66: /* DECNKM */ + vte_decrpm(tty, priv, par[0], decnkm); + break; + case 67: /* DECBKM */ + case 68: /* DECKBUM */ + case 69: /* DECVSSM */ + case 73: /* DECXRLM */ + case 81: /* DECKPM */ + vte_decrpm(tty, priv, par[0], 4); + break; + default: + vte_decrpm(tty, priv, par[0], 2); + } + } else { + switch (par[0]) { + case 1: /* GATM */ + vte_decrpm(tty, priv, par[0], 4); + break; + case 2: /* KAM */ + vte_decrpm(tty, priv, par[0], kam); + break; + case 3: /* CRM */ + vte_decrpm(tty, priv, par[0], 4); + break; + case 4: /* IRM */ + vte_decrpm(tty, priv, par[0], irm); + break; + case 5: /* SRTM */ + case 6: /* ERM */ + case 7: /* VEM */ + case 8: /* BDSM */ + case 9: /* DCSM */ + case 10: /* HEM */ + case 11: /* PUM */ + case 12: /* SRM */ + case 13: /* FEAM */ + case 14: /* FETM */ + case 15: /* MATM */ + case 16: /* TTM */ + case 17: /* SATM */ + case 18: /* TSM */ + case 19: /* EBM */ + vte_decrpm(tty, priv, par[0], 4); + break; + case 20: /* LNM */ + vte_decrpm(tty, priv, par[0], lnm); + break; + case 21: /* GRCM */ + case 22: /* ZDM */ + vte_decrpm(tty, priv, par[0], 4); + break; + default: + vte_decrpm(tty, priv, par[0], 2); + } + } +} + +/* + * DECSCL - Set operating level + */ +static void vte_decscl(struct vc_data *vc) +{ + switch (par[0]) { + case 61: /* VT100 mode */ + if (npar == 1) { + decscl = 1; + c8bit = 0; + } + break; + case 62: /* VT200 mode */ + case 63: /* VT300 mode */ + case 64: /* VT400 mode */ + if (npar <= 2) { + decscl = 4; + if (par[1] == 1) + c8bit = 0; + else + c8bit = 1; + } + break; + } + return; +} + +/* + * DECTABSR - Tabulation stop report + */ +void vte_dectabsr(struct tty_struct *tty) +{ + /* not yet implemented */ +} + +/* + * DECTSR - Terminal state report + */ +void vte_dectsr(struct tty_struct *tty) +{ + /* not yet implemented */ +} + +static void setterm_command(struct vc_data *vc) +{ + switch(par[0]) { + case 1: /* set color for underline mode */ + if (can_do_color && par[1] < 16) { + ulcolor = color_table[par[1]]; + if (underline) + update_attr(vc); + } + break; + case 2: /* set color for half intensity mode */ + if (can_do_color && par[1] < 16) { + halfcolor = color_table[par[1]]; + if (intensity == 0) + update_attr(vc); + } + break; + case 8: /* store colors as defaults */ + def_color = attr; + if (hi_font_mask == 0x100) + def_color >>= 1; + default_attr(vc); + update_attr(vc); + break; + case 9: /* set blanking interval */ + vc->display_fg->blank_interval = + ((par[1] < 60) ? par[1] : 60) * 60 * HZ; + poke_blanked_console(vc->display_fg); + break; + case 10: /* set bell frequency in Hz */ + if (npar >= 1) + bell_pitch = par[1]; + else + bell_pitch = DEFAULT_BELL_PITCH; + break; + case 11: /* set bell duration in msec */ + if (npar >= 1) + bell_duration = (par[1] < 2000) ? + par[1]*HZ/1000 : 0; + else + bell_duration = DEFAULT_BELL_DURATION; + break; + case 12: /* bring specified console to the front */ + if (par[1] >= 1 && vc_cons_allocated(par[1]-1)) + set_console(par[1] - 1); + break; + case 13: /* unblank the screen */ + poke_blanked_console(vc->display_fg); + break; + case 14: /* set vesa powerdown interval */ + vc->display_fg->off_interval = + ((par[1] < 60) ? par[1] : 60) * 60 * HZ; + break; + } +} + +/* + * ICH - INSERT CHARACTER [VT220] + */ +static void vte_ich(struct vc_data *vc, unsigned int nr) +{ + if (nr > video_num_columns - x) + nr = video_num_columns - x; + else if (!nr) + nr = 1; + insert_char(vc, nr); +} + +/* + * IL - INSERT LINE + */ +static void vte_il(struct vc_data *vc, unsigned int nr) +{ + if (nr > video_num_lines - y) + nr = video_num_lines - y; + else if (!nr) + nr = 1; + insert_line(vc, nr); +} + +/* + * DCH - DELETE CHARACTER + */ +static void vte_dch(struct vc_data *vc, unsigned int nr) +{ + if (nr > video_num_columns - x) + nr = video_num_columns - x; + else if (!nr) + nr = 1; + delete_char(vc, nr); +} + +/* + * DL - DELETE LINE + */ +static void vte_dl(struct vc_data *vc, unsigned int nr) +{ + if (nr > video_num_lines - y) + nr = video_num_lines - y; + else if (!nr) + nr=1; + delete_line(vc, nr); +} + +/* + * DECSC - SAVE CURSOR + * + * This saves the following states: + * - cursor position + * - graphic rendition + * - character set shift state + * - state of wrap flag + * - state of origin mode + * - state of selective erase (not implemented) + */ +void vte_decsc(struct vc_data *vc) +{ + saved_x = x; + saved_y = y; + s_intensity = intensity; + s_underline = underline; + s_blink = blink; + s_reverse = reverse; + s_charset = charset; + s_color = color; + saved_G0 = G0_charset; + saved_G1 = G1_charset; + saved_G2 = G2_charset; + saved_G3 = G3_charset; +} + +/* + * DECRC - RESTORE CURSOR + */ +static void vte_decrc(struct vc_data *vc) +{ + gotoxy(vc, saved_x, saved_y); + intensity = s_intensity; + underline = s_underline; + blink = s_blink; + reverse = s_reverse; + charset = s_charset; + color = s_color; + G0_charset = saved_G0; + G1_charset = saved_G1; + G2_charset = saved_G2; + G3_charset = saved_G3; + set_translate(vc, charset ? G1_charset : G0_charset); + update_attr(vc); + need_wrap = 0; +} + +/* + * RIS - RESET TO INITIAL STATE + * + * On DEC terminals this causes the following: + * - all set-up parameters are replaced by power-up defaults + * - all communications lines are disconnected (should we send SIGHUP to + * controlling process?) + * - all user-defined keys are cleared (not implemented) + * - the screen is cleared + * - cursor is place to upper-left corner + * - SGR state is set to normal + * - selective erase attribute write state is set to "non-selective erase" + * (not implemented) + * - all character sets are set to default (not implemented) + */ +void vte_ris(struct vc_data *vc, int do_clear) +{ + top = 0; + bottom = video_num_lines; + vc_state = ESinit; + priv1 = 0; + priv2 = 0; + priv3 = 0; + priv4 = 0; + set_translate(vc, LAT1_MAP); + G0_charset = LAT1_MAP; + G1_charset = GRAF_MAP; + charset = 0; + need_wrap = 0; + report_mouse = 0; + utf = 0; + utf_count = 0; + + disp_ctrl = 0; + toggle_meta = 0; + + c8bit = 0; /* disable 8-bit controls */ + decckm = 0; /* cursor key sequences */ + decsclm = 0; /* jump scroll */ + decscnm = 0; /* normal screen */ + decom = 0; /* absolute adressing */ + decawm = 1; /* autowrap disabled */ + decarm = 1; /* autorepeat enabled */ + dectcem = 1; /* text cursor enabled */ + + kam = 0; /* keyboard enabled */ + crm = 0; /* execute control functions */ + irm = 0; /* replace */ + lnm = 0; /* line feed */ + + set_kbd_mode(&vc->kbd_table, VC_REPEAT); + clr_kbd_mode(&vc->kbd_table, VC_CKMODE); + clr_kbd_mode(&vc->kbd_table, VC_APPLIC); + clr_kbd_mode(&vc->kbd_table, VC_CRLF); + vc->kbd_table.lockstate = KBD_DEFLOCK; + vc->kbd_table.slockstate = 0; + vc->kbd_table.ledmode = LED_SHOW_FLAGS; + vc->kbd_table.ledflagstate = + vc->kbd_table.default_ledflagstate = KBD_DEFLEDS; + vc->kbd_table.modeflags = KBD_DEFMODE; + vc->kbd_table.kbdmode = VC_XLATE; + set_leds(); + + cursor_type = CUR_DEFAULT; + complement_mask = s_complement_mask; + + default_attr(vc); + update_attr(vc); + + tab_stop[0] = 0x01010100; + tab_stop[1] = + tab_stop[2] = + tab_stop[3] = + tab_stop[4] = 0x01010101; + + bell_pitch = DEFAULT_BELL_PITCH; + bell_duration = DEFAULT_BELL_DURATION; + + gotoxy(vc, 0, 0); + vte_decsc(vc); + if (do_clear) + vte_ed(vc, 2); +} + +/* + * TABULATION CLEAR (TBC) + * + * NOTE: + * In case of parameters 0 and 2 the number of lines affected depends on the + * setting of the Tabulation Stop Mode (TSM). Since we don't implement TSM, + * this is silently ignored. + * + * Parameters 1 and 4 are similiar to 0 and 3, but affect only line tabulation + * stops, which are not implemented. + * + * Parameter 2 may only be interpreted, when we implement a tabulation stop map + * per display line. + */ +static void vte_tbc(struct vc_data *vc, int vpar) +{ + switch (vpar) { + case 0: + /* + * The character tabulation stop at the active + * presentation position is cleared. + */ + tab_stop[x >> 5] &= ~(1 << (x & 31)); + return; + case 2: + /* + * All character tabulation stops in the active + * line are cleared. + */ + case 3: + /* + * All character tabulation stops are cleared. + */ + case 5: + /* + * All tabulation stops are cleared. + */ + tab_stop[0] = tab_stop[1] = tab_stop[2] = tab_stop[3] = + tab_stop[4] = 0; + } +} + +void terminal_emulation(struct tty_struct *tty, int c) +{ + /* + * C0 CONTROL CHARACTERS + * + * NOTE: Control characters can be used in the _middle_ + * of an escape sequence. (XXX: Really? Test!) + */ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + + switch (c) { + case 0x00: /* NUL - Null */ + case 0x01: /* SOH - Start of header */ + case 0x02: /* STX - */ + case 0x03: /* ETX - */ + case 0x04: /* EOT - End of transmission */ + return; + case 0x05: /* ENQ - Enquiry */ + vte_answerback(tty); + return; + case 0x06: /* ACK - Acknowledge */ + return; + case 0x07: /* BEL - Bell */ + if (bell_duration) + kd_mksound(bell_pitch, bell_duration); + return; + case 0x08: /* BS - Back space */ + vte_bs(vc); + return; + case 0x09: /* HT - Character tabulation */ + pos -= (x << 1); + while (x < video_num_columns - 1) { + x++; + if (tab_stop[x >> 5] & (1 << (x & 31))) + break; + } + pos += (x << 1); + return; + case 0x0a: /* LF - Line feed */ + case 0x0b: /* VT - Line tabulation */ + /* + * Since line tabulation is not implemented in the DEC VT + * series (except VT131 ?), the DEC VT series treats any + * VT as LF. + */ + case 0x0c: /* FF - Form feed */ + /* + * DEC VT series processes FF as LF. + */ + vte_lf(vc); + if (!get_kbd_mode(&vc->kbd_table, VC_CRLF)) + return; + case 0x0d: /* CR - Carriage return */ + vte_cr(vc); + return; + case 0x0e: /* SO - Shift out / LS1 - Locking shift 1 */ + charset = 1; + set_translate(vc, G1_charset); + disp_ctrl = 1; + return; + case 0x0f: /* SI - Shift in / LS0 - Locking shift 0 */ + charset = 0; + set_translate(vc, G0_charset); + disp_ctrl = 0; + return; + case 0x10: /* DLE - */ + case 0x11: /* DC1 - Device control 1 */ + case 0x12: /* DC2 - Device control 1 */ + case 0x13: /* DC3 - Device control 1 */ + case 0x14: /* DC4 - Device control 1 */ + case 0x15: /* NAK - Negative acknowledge */ + case 0x16: /* SYN - Synchronize */ + case 0x17: /* ETB - */ + return; + case 0x18: /* CAN - Cancel */ + vc_state = ESinit; + return; + case 0x19: /* EM - */ + return; + case 0x1a: /* SUB - Substitute */ + vc_state = ESinit; + return; + case 0x1b: /* ESC - Escape */ + vc_state = ESesc; + return; + case 0x1c: /* IS4 - */ + case 0x1d: /* IS3 - */ + case 0x1e: /* IS2 - */ + case 0x1f: /* IS1 - */ + return; + case 0x7f: /* DEL - Delete */ + /* + * This character is ignored, unless a 96-set has been mapped, + * but this is not supported at the moment. + */ + return; + } + + if (c8bit == 1) + /* + * C1 control functions (8-bit mode). + */ + switch (c) { + case 0x80: /* unused */ + case 0x81: /* unused */ + case 0x82: /* BPH - Break permitted here */ + case 0x83: /* NBH - No break here */ + return; + case 0x84: /* IND - Line feed (DEC only) */ +#ifndef VTE_STRICT_ISO + vte_lf(vc); +#endif /* ndef VTE_STRICT_ISO */ + return; + case 0x85: /* NEL - Next line */ + vte_lf(vc); + vte_cr(vc); + return; + case 0x86: /* SSA - Start of selected area */ + case 0x87: /* ESA - End of selected area */ + return; + case 0x88: /* HTS - Character tabulation set */ + tab_stop[x >> 5] |= (1 << (x & 31)); + return; + case 0x89: /* HTJ - Character tabulation with justify */ + case 0x8a: /* VTS - Line tabulation set */ + case 0x8b: /* PLD - Partial line down */ + case 0x8c: /* PLU - Partial line up */ + return; + case 0x8d: /* RI - Reverse line feed */ + vte_ri(vc); + return; +#if 0 + case 0x8e: /* SS2 - Single shift 2 */ + need_shift = 1; + GS_charset = G2_charset; /* G2 -> GS */ + return; + case 0x8f: /* SS3 - Single shift 3 */ + need_shift = 1; + GS_charset = G3_charset; /* G3 -> GS */ + return; +#endif + case 0x90: /* DCS - Device control string */ + return; + case 0x91: /* PU1 - Private use 1 */ + case 0x92: /* PU2 - Private use 2 */ + case 0x93: /* STS - Set transmit state*/ + case 0x94: /* CCH - Cancel character */ + case 0x95: /* MW - Message waiting */ + case 0x96: /* SPA - Start of guarded area */ + case 0x97: /* EPA - End of guarded area */ + case 0x98: /* SOS - Start of string */ + case 0x99: /* unused */ + return; + case 0x9a: /* SCI - Single character introducer */ +#ifndef VTE_STRICT_ISO + vte_da(tty); +#endif /* ndef VTE_STRICT_ISO */ + return; + case 0x9b: /* CSI - Control sequence introducer */ + vc_state = EScsi; + return; + case 0x9c: /* ST - String Terminator */ + case 0x9d: /* OSC - Operating system command */ + case 0x9e: /* PM - Privacy message */ + case 0x9f: /* APC - Application program command */ + return; + } + + switch(vc_state) { + case ESesc: + vc_state = ESinit; + switch (c) { + + case ' ': /* ACS - Announce code structure */ + vc_state = ESacs; + return; + case '#': /* SCF - Single control functions */ + vc_state = ESscf; + return; + case '%': /* DOCS - Designate other coding system */ + vc_state = ESdocs; + return; +#ifdef CONFIG_VT_HP + case '&': /* HP terminal emulation */ + vc_state = ESesc_and; + return; +#endif /* def CONFIG_VT_HP */ + case '(': /* GZD4 - G0-designate 94-set */ + vc_state = ESgzd4; + return; + case ')': /* G1D4 - G1-designate 94-set */ + vc_state = ESg1d4; + return; +#if 0 + case '*': /* G2D4 - G2-designate 94-set */ + vc_state = ESg2d4; + return; + case '+': /* G3D4 - G3-designate 94-set */ + vc_state = ESg3d4; + return; + case '-': /* G1D6 - G1-designate 96-set */ + vc_state = ESg1d6; + return; + case '.': /* G2D6 - G2-designate 96-set */ + vc_state = ESg2d6; + return; + case '/': /* G3D6 - G3-designate 96-set */ + vc_state = ESg3d6; + return; +#endif + /* ===== Private control functions ===== */ + + case '6': /* DECBI - Back index */ + return; + case '7': /* DECSC - Save cursor */ + vte_decsc(vc); + return; + case '8': /* DECRC - Restore cursor */ + vte_decrc(vc); + return; + case '9': /* DECFI - Forward index */ + return; + case '=': /* DECKPAM - Keypad application mode */ + decnkm = 1; + set_kbd_mode(&vc->kbd_table, VC_APPLIC); + return; + case '>': /* DECKPNM - Keypad numeric mode */ + decnkm = 0; + clr_kbd_mode(&vc->kbd_table, VC_APPLIC); + return; + + /* ===== C1 control functions ===== */ + case '@': /* unallocated */ + case 'A': /* unallocated */ + case 'B': /* BPH - Break permitted here */ + case 'C': /* NBH - No break here */ + case 'D': /* IND - Line feed (DEC only) */ +#ifndef VTE_STRICT_ISO + vte_lf(vc); +#endif /* ndef VTE_STRICT_ISO */ + return; + case 'E': /* NEL - Next line */ + vte_cr(vc); + vte_lf(vc); + return; + case 'F': /* SSA - Start of selected area */ + case 'G': /* ESA - End of selected area */ + return; + case 'H': /* HTS - Character tabulation set */ + tab_stop[x >> 5] |= (1 << (x & 31)); + return; + case 'I': /* HTJ - Character tabulation with justify */ + case 'J': /* VTS - Line tabulation set */ + case 'K': /* PLD - Partial line down */ + case 'L': /* PLU - Partial line up */ + return; + case 'M': /* RI - Reverse line feed */ + vte_ri(vc); + return; + case 'N': /* SS2 - Single shift 2 */ + shift = 1; + GS_charset = G2_charset; /* G2 -> GS */ + return; + case 'O': /* SS3 - Single shift 3 */ + shift = 1; + GS_charset = G3_charset; + return; + case 'P': /* DCS - Device control string */ + return; + case 'Q': /* PU1 - Private use 1 */ + case 'R': /* PU2 - Private use 2 */ + case 'S': /* STS - Set transmit state */ + case 'T': /* CCH - Cancel character */ + case 'U': /* MW - Message waiting */ + case 'V': /* SPA - Start of guarded area */ + case 'W': /* EPA - End of guarded area */ + case 'X': /* SOS - Start of string */ + case 'Y': /* unallocated */ + return; + case 'Z': /* SCI - Single character introducer */ +#ifndef VTE_STRICT_ISO + vte_da(tty); +#endif /* ndef VTE_STRICT_ISO */ + return; + case '[': /* CSI - Control sequence introducer */ + vc_state = EScsi; + return; + case '\\': /* ST - String Terminator */ + return; + case ']': /* OSC - Operating system command */ + /* XXX: Fixme! Wrong sequence and format! */ + vc_state = ESosc; + return; + case '^': /* PM - Privacy Message */ + case '_': /* APC - Application Program Command */ + return; + + /* ===== Single control functions ===== */ + case '`': /* DMI - Disable manual input */ + kam = 0; + return; + case 'b': /* EMI - Enable manual input */ + kam = 1; + return; + case 'c': /* RIS - Reset ti initial state */ + vte_ris(vc, 1); + return; + case 'd': /* CMD - Coding Method Delimiter */ + return; +#if 0 + case 'n': /* LS2 - Locking shift G2 */ + GL_charset = G2_charset; /* (G2 -> GL) */ + return; + case 'o': /* LS3 - Locking shift G3 */ + GL_charset = G3_charset; /* (G3 -> GL) */ + return; + case '|': /* LS3R - Locking shift G3 right */ + GR_charset = G3_charset; /* G3 -> GR */ + return; + case '}': /* LS2R - Locking shift G2 right */ + GR_charset = G2_charset; /* G2 -> GR */ + return; + case '~': /* LS1R - Locking shift G1 right */ + GR_charset = G1_charset; /* G1 -> GR */ + return; +#endif + } + return; + case ESacs: + vc_state = ESinit; + switch (c) { + case 'F': /* Select 7-bit C1 control transmission */ + if (decscl != 1) /* Ignore if in VT100 mode */ + c8bit = 0; + return; + case 'G': /* Select 8-Bit C1 control transmission */ + if (decscl != 1) /* Ignore if in VT100 mode */ + c8bit = 1; + return; + case 'L': /* ANSI conformance level 1 */ + case 'M': /* ANSI conformance level 2 */ + case 'N': /* ANSI conformance level 3 */ + /* Not yet implemented. */ + return; + } + return; + case ESosc: + vc_state = ESinit; + switch (c) { + case 'P': /* palette escape sequence */ + for (npar = 0; npar < NPAR; npar++) + par[npar] = 0; + npar = 0; + vc_state = ESpalette; + return; + case 'R': /* reset palette */ + reset_palette(vc); + vc_state = ESinit; + return; + } + return; + case ESpalette: + if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) +{ + par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ; + if (npar==7) { + int i = par[0]*3, j = 1; + palette[i] = 16*par[j++]; + palette[i++] += par[j++]; + palette[i] = 16*par[j++]; + palette[i++] += par[j++]; + palette[i] = 16*par[j++]; + palette[i] += par[j]; + set_palette(vc); + vc_state = ESinit; + } + } else + vc_state = ESinit; + return; + case EScsi: + for(npar = 0 ; npar < NPAR ; npar++) + par[npar] = 0; + npar = 0; + vc_state = EScsi_getpars; + if (c == '[') { + /* Function key */ + vc_state = ESfunckey; + return; + } + priv1 = (c == '<'); + priv2 = (c == '='); + priv3 = (c == '>'); + priv4 = (c == '?'); + if (priv1) { + vc_state = ESinit; + return; + } + if (priv2 || priv3 || priv4) { + return; + } + case EScsi_getpars: + if (c==';' && npar='0' && c<='9') { + par[npar] *= 10; + par[npar] += c-'0'; + return; + } else vc_state=EScsi_gotpars; + case EScsi_gotpars: + vc_state = ESinit; + /* + * Process control functions with private parameter flag. + */ + switch(c) { + case '$': + if (priv4) { + vc_state = EScsi_dollar; + return; + } + break; + case 'J': + if (priv4) { + /* DECSED - Selective erase in display */ + return; + } + break; + case 'K': + if (priv4) { + /* DECSEL - Selective erase in display */ + return; + } + break; + case 'h': /* SM - Set Mode */ + set_mode(vc, 1); + return; + case 'l': /* RM - Reset Mode */ + set_mode(vc, 0); + return; + case 'c': + if (priv2) { + if (!par[0]) + vte_dec_da3(tty); + priv2 = 0; + return; + } + if (priv3) { + if (!par[0]) + vte_dec_da2(tty); + priv3 = 0; + return; + } + if (priv4) { + if (par[0]) + cursor_type = par[0] | (par[1]<<8) | (par[2]<<16); + else + cursor_type = CUR_DEFAULT; + priv4 = 0; + return; + } + break; + case 'm': + if (priv4) { + clear_selection(); + if (par[0]) + complement_mask = par[0]<<8 | par[1]; + else + complement_mask = s_complement_mask; + priv4 = 0; + return; + } + break; + case 'n': + if (priv4) { + switch (par[0]) { + case 6: /* DECXCPR - Extended CPR */ + vte_cpr(tty, 1); + break; + case 15: /* DEC printer status */ + vte_fake_dec_dsr(tty, "13"); + break; + case 25: /* DEC UDK status */ + vte_fake_dec_dsr(tty, "21"); + break; + case 26: /* DEC keyboard status */ + vte_fake_dec_dsr(tty, "27;1;0;1"); + break; + case 53: /* DEC locator status */ + vte_fake_dec_dsr(tty, "53"); + break; + case 62: /* DEC macro space */ + vte_decmsr(tty); + break; + case 75: /* DEC data integrity */ + vte_fake_dec_dsr(tty, "70"); + break; + case 85: /* DEC multiple session status */ vte_fake_dec_dsr(tty, "83"); + break; + } + } else + switch (par[0]) { + case 5: /* DSR - Device status report */ + vte_dsr(tty); + break; + case 6: /* CPR - Cursor position report */ + vte_cpr(tty, 0); + break; + } + priv4 = 0; + return; + } + if (priv1 || priv2 || priv3 || priv4) { + priv1 = + priv2 = + priv3 = + priv4 = 0; + return; + } + /* + * Process control functions with standard parameter strings. + */ + switch(c) { + + /* ===== Control functions w/ intermediate byte ===== */ + case ' ': /* Intermediate byte: SP (ISO 6429) */ + vc_state = EScsi_space; + return; + case '!': /* Intermediate byte: ! (DEC VT series) */ + vc_state = EScsi_exclam; + return; + case '"': /* Intermediate byte: " (DEC VT series) */ + vc_state = EScsi_dquote; + return; + case '$': /* Intermediate byte: $ (DEC VT series) */ + vc_state = EScsi_dollar; + return; + case '&': /* Intermediate byte: & (DEC VT series) */ + vc_state = EScsi_and; + return; + case '*': /* Intermediate byte: * (DEC VT series) */ + vc_state = EScsi_star; + return; + case '+': /* Intermediate byte: + (DEC VT series) */ + vc_state = EScsi_plus; + return; + /* ==== Control functions w/o intermediate byte ==== */ + case '@': /* ICH - Insert character */ + vte_ich(vc, par[0]); + return; + case 'A': /* CUU - Cursor up */ + case 'k': /* VPB - Line position backward */ + if (!par[0]) par[0]++; + gotoxy(vc, x, y-par[0]); + return; + case 'B': /* CUD - Cursor down */ + case 'e': /* VPR - Line position forward */ + if (!par[0]) par[0]++; + gotoxy(vc, x, y+par[0]); + return; + case 'C': /* CUF - Cursor right */ + case 'a': /* HPR - Character position forward */ + if (!par[0]) par[0]++; + gotoxy(vc, x+par[0], y); + return; + case 'D': /* CUB - Cursor left */ + case 'j': /* HPB - Character position backward */ + if (!par[0]) par[0]++; + gotoxy(vc, x-par[0], y); + return; + case 'E': /* CNL - Cursor next line */ + if (!par[0]) par[0]++; + gotoxy(vc, 0, y+par[0]); + return; + case 'F': /* CPL - Cursor preceeding line */ + if (!par[0]) par[0]++; + gotoxy(vc, 0, y-par[0]); + return; + case 'G': /* CHA - Cursor character absolute */ + case '`': /* HPA - Character position absolute */ + if (par[0]) par[0]--; + gotoxy(vc, par[0], y); + return; + case 'H': /* CUP - Cursor position */ + case 'f': /* HVP - Horizontal and vertical position */ + if (par[0]) par[0]--; + if (par[1]) par[1]--; + gotoxay(vc, par[1], par[0]); + return; + case 'I': /* CHT - Cursor forward tabulation */ + if (!par[0]) + par[0]++; + vte_cht(vc, par[0]); + return; + case 'J': /* ED - Erase in page */ + vte_ed(vc, par[0]); + return; + case 'K': /* EL - Erase in line */ + vte_el(vc, par[0]); + return; + case 'L': /* IL - Insert line */ + vte_il(vc, par[0]); + return; + case 'M': /* DL - Delete line */ + vte_dl(vc, par[0]); + return; + case 'P': /* DCH - Delete character */ + vte_dch(vc, par[0]); + return; + case 'U': /* NP - Next page */ + case 'V': /* PP - Preceeding page */ + return; + case 'W': /* CTC - Cursor tabulation control */ + switch (par[0]) { + case 0: /* Set character tab stop at current position */ tab_stop[x >> 5] |= (1 << (x & 31)); + return; + case 2: /* Clear character tab stop at curr. position */ vte_tbc(vc, 0); + return; + case 5: /* All character tab stops are cleared. */ + vte_tbc(vc, 5); + return; + } + return; + case 'X': /* ECH - Erase character */ + vte_ech(vc, par[0]); + return; + case 'Y': /* CVT - Cursor line tabulation */ + if (!par[0]) + par[0]++; + vte_cvt(vc, par[0]); + return; + case 'Z': /* CBT - Cursor backward tabulation */ + vte_cbt(vc, par[0]); + return; + case ']': +#ifndef VT_STRICT_ISO + setterm_command(vc); +#endif /* def VT_STRICT_ISO */ + return; + case 'c': /* DA - Device attribute */ + if (!par[0]) + vte_da(tty); + return; + case 'd': /* VPA - Line position absolute */ + if (par[0]) par[0]--; + gotoxay(vc, x, par[0]); + return; + case 'g': /* TBC - Tabulation clear */ + vte_tbc(vc, par[0]); + return; + case 'm': /* SGR - Select graphics rendition */ + vte_sgr(vc); + return; + + /* ===== Private control sequences ===== */ + + case 'q': /* DECLL - but only 3 leds */ + switch (par[0]) { + case 0: /* all LEDs off */ + case 1: /* LED 1 on */ + case 2: /* LED 2 on */ + case 3: /* LED 3 on */ + setledstate(&vc->kbd_table, + (par[0] < 3) ? par[0] : 4); + case 4: /* LED 4 on */ + ; + } + return; + case 'r': /* DECSTBM - Set top and bottom margin */ + if (!par[0]) + par[0]++; + if (!par[1]) + par[1] = video_num_lines; + /* Minimum allowed region is 2 lines */ + if (par[0] < par[1] && + par[1] <= video_num_lines) { + top=par[0]-1; + bottom=par[1]; + gotoxay(vc, 0, 0); + } + return; + case 's': /* DECSLRM - Set left and right margin */ + return; + case 't': /* DECSLPP - Set lines per page */ + return; + case 'x': /* DECREQTPARM - Request terminal parameters */ + vte_decreptparm(tty); + return; + case 'y': + if (par[0] == 4) { + /* DECTST - Invoke confidence test */ + return; + } + } + return; + case EScsi_space: + vc_state = ESinit; + switch (c) { + /* + * Note: All codes betweem 0x40 and 0x6f are subject to + * standardisation by the ISO. The codes netweem 0x70 + * and 0x7f are free for private use. + */ + case '@': /* SL - Scroll left */ + case 'A': /* SR - Scroll right */ + return; + case 'P': /* PPA - Page position absolute */ + case 'Q': /* PPR - Page position forward */ + case 'R': /* PPB - Page position backward */ + return; + } + return; + case EScsi_exclam: + vc_state = ESinit; + switch (c) { + case 'p': /* DECSTR - Soft terminal reset */ + /* + * Note: On a true DEC VT there are differences + * between RIS and DECSTR. Right now we ignore + * this... -dbk + */ + vte_ris(vc, 1); + return; + } + return; + case EScsi_dquote: + vc_state = ESinit; + switch (c) { + case 'p': /* DECSCL - Set operating level */ + vte_decscl(vc); + return; + case 'q': /* DECSCA - Select character protection +attribute */ + return; + case 'v': /* DECRQDE - Request window report */ + ; + } + return; + case EScsi_dollar: + vc_state = ESinit; + switch (c) { + case 'p': /* DECRQM - Request mode */ + vte_decrqm(tty, priv4); + return; + case 'r': /* DECCARA - Change attributes in rectangular area */ + return; + case 't': /* DECRARA - Reverse attributes in rectangular area */ + return; + case 'u': /* DECRQTSR - Request terminal state */ + if (par[0] == 1) + vte_dectsr(tty); + return; + case 'v': /* DECCRA - Copy rectangular area */ + return; + case 'w': /* DECRQPSR - Request presentation status */ + switch (par[0]) { + case 1: + vte_deccir(tty); + break; + case 2: + vte_dectabsr(tty); + break; + } + return; + case 'x': /* DECFRA - Fill rectangular area */ + return; + case 'z': /* DECERA - Erase rectangular area */ + return; + case '{': /* DECSERA - Selective erase rectangular area */ + return; + case '|': /* DECSCPP - Set columns per page */ + return; + case '}': /* DECSASD - Select active status display */ + return; + case '~': /* DECSSDT - Select status display type +*/ + return; + } + return; + case EScsi_and: + vc_state = ESinit; + switch (c) { + case 'u': /* DECRQUPSS - Request user-preferred supplemental set */ + return; + case 'x': /* Enable Session Command */ + return; + } + return; + case EScsi_squote: + vc_state = ESinit; + switch (c) { + case '}': /* DECIC - Insert column */ + return; + case '~': /* DECDC - Delete column */ + return; + } + case EScsi_star: + vc_state = ESinit; + switch (c) { + case 'x': /* DECSACE - Select attribute change extent */ + return; + case 'y': /* DECRQCRA - Request checksum on rectangular area */ + return; + case 'z': /* DECINVM - Invoke macro */ + return; + case '|': /* DECSNLS - Select number of lines */ + return; + case '}': /* DECLFKC - Local function key control +*/ + return; + } + return; + case EScsi_plus: + vc_state = ESinit; + switch (c) { + case 'p': /* DECSR - Secure reset */ + return; + } + return; + case ESdocs: + vc_state = ESinit; + switch (c) { + case '@': /* defined in ISO 2022 */ + utf = 0; + return; + case 'G': /* prelim official escape code */ + case '8': /* retained for compatibility */ + utf = 1; + return; + } + return; +#ifdef CONFIG_VT_HP + case ESesc_and: + vc_state = ESinit; + switch (c) { + case 'f': /* Set function key label */ + return; + case 'j': /* Display function key labels */ + return; + } + return; +#endif + case ESfunckey: + vc_state = ESinit; + return; + case ESscf: + vc_state = ESinit; + if (c == '8') { + /* DEC screen alignment test. kludge :-) */ + video_erase_char = + (video_erase_char & 0xff00) | 'E'; + vte_ed(vc, 2); + video_erase_char = + (video_erase_char & 0xff00) | ' '; + do_update_region(vc, origin, screenbuf_size/2); + } + return; + case ESgzd4: + switch (c) { + case '0': /* DEC Special graphics */ + G0_charset = GRAF_MAP; + break; +#if 0 + case '>': /* DEC Technical */ + G0_charset = DEC_TECH_MAP; + break; +#endif + case 'A': /* ISO Latin-1 supplemental */ + G0_charset = LAT1_MAP; + break; + case 'B': /* ASCII */ + G0_charset = LAT1_MAP; + break; + case 'U': + G0_charset = IBMPC_MAP; + break; + case 'K': + G0_charset = USER_MAP; + break; + } + if (charset == 0) + set_translate(vc, G0_charset); + vc_state = ESinit; + return; + case ESg1d4: + switch (c) { + case '0': /* DEC Special graphics */ + G1_charset = GRAF_MAP; + break; +#if 0 + case '>': /* DEC Technical */ + G1_charset = DEC_TECH_MAP; + break; +#endif + case 'A': /* ISO Latin-1 supplemental */ + G1_charset = LAT1_MAP; + break; + case 'B': /* ASCII */ + G1_charset = LAT1_MAP; + break; + case 'U': + G1_charset = IBMPC_MAP; + break; + case 'K': + G1_charset = USER_MAP; + break; + } + if (charset == 1) + set_translate(vc, G1_charset); + vc_state = ESinit; + return; + case ESg2d4: + switch (c) { + case '0': /* DEC Special graphics */ + G2_charset = GRAF_MAP; + break; +#if 0 + case '>': /* DEC Technical */ + G2_charset = DEC_TECH_MAP; + break; +#endif + case 'A': /* ISO Latin-1 supplemental */ + G2_charset = LAT1_MAP; + break; + case 'B': /* ASCII */ + G2_charset = LAT1_MAP; + break; + case 'U': + G2_charset = IBMPC_MAP; + break; + case 'K': + G2_charset = USER_MAP; + break; + } + if (charset == 1) + set_translate(vc, G2_charset); + vc_state = ESinit; + return; + case ESg3d4: + switch (c) { + case '0': /* DEC Special graphics */ + G3_charset = GRAF_MAP; + break; +#if 0 + case '>': /* DEC Technical */ + G3_charset = DEC_TECH_MAP; + break; +#endif + case 'A': /* ISO Latin-1 supplemental */ + G3_charset = LAT1_MAP; + break; + case 'B': /* ASCII */ + G3_charset = LAT1_MAP; + break; + case 'U': + G3_charset = IBMPC_MAP; + break; + case 'K': + G3_charset = USER_MAP; + break; + } + if (charset == 1) + set_translate(vc, G3_charset); + vc_state = ESinit; + return; + default: + vc_state = ESinit; + } +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/Config.help linux-2.5/drivers/char/drm/Config.help --- linux-2.5.5/drivers/char/drm/Config.help Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/char/drm/Config.help Mon Feb 25 18:58:39 2002 @@ -37,3 +37,7 @@ card. If M is selected, the module will be called mga.o. AGP support is required for this driver to work. +CONFIG_DRM_SIS + Choose this option if you have a SIS graphics card. AGP support is + required for this driver to work. + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/Config.in linux-2.5/drivers/char/drm/Config.in --- linux-2.5.5/drivers/char/drm/Config.in Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/char/drm/Config.in Thu Dec 13 16:32:35 2001 @@ -13,4 +13,5 @@ dep_tristate ' ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP dep_tristate ' Intel I810' CONFIG_DRM_I810 $CONFIG_AGP dep_tristate ' Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP + dep_tristate ' SiS' CONFIG_DRM_SIS $CONFIG_AGP fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/Makefile linux-2.5/drivers/char/drm/Makefile --- linux-2.5.5/drivers/char/drm/Makefile Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/char/drm/Makefile Thu Dec 13 16:32:35 2001 @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. O_TARGET := drm.o -list-multi := gamma.o tdfx.o r128.o mga.o i810.o radeon.o ffb.o +list-multi := gamma.o tdfx.o r128.o mga.o i810.o radeon.o ffb.o sis.o gamma-objs := gamma_drv.o gamma_dma.o tdfx-objs := tdfx_drv.o @@ -12,6 +12,7 @@ i810-objs := i810_drv.o i810_dma.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o ffb-objs := ffb_drv.o ffb_context.o +sis-objs := sis_drv.o sis_ds.o sis_mm.o obj-$(CONFIG_DRM_GAMMA) += gamma.o obj-$(CONFIG_DRM_TDFX) += tdfx.o @@ -20,6 +21,7 @@ obj-$(CONFIG_DRM_MGA) += mga.o obj-$(CONFIG_DRM_I810) += i810.o obj-$(CONFIG_DRM_FFB) += ffb.o +obj-$(CONFIG_DRM_SIS) += sis.o include $(TOPDIR)/Rules.make @@ -43,3 +45,6 @@ ffb.o: $(ffb-objs) $(lib) $(LD) -r -o $@ $(ffb-objs) $(lib) + +sis.o: $(sis-objs) $(lib) + $(LD) -r -o $@ $(sis-objs) $(lib) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/drm.h linux-2.5/drivers/char/drm/drm.h --- linux-2.5.5/drivers/char/drm/drm.h Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/char/drm/drm.h Tue Mar 5 13:41:33 2002 @@ -104,7 +104,7 @@ #include "i810_drm.h" #include "r128_drm.h" #include "radeon_drm.h" -#ifdef CONFIG_DRM_SIS +#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE) #include "sis_drm.h" #endif @@ -483,7 +483,7 @@ #define DRM_IOCTL_RADEON_INDIRECT DRM_IOWR(0x4d, drm_radeon_indirect_t) #define DRM_IOCTL_RADEON_TEXTURE DRM_IOWR(0x4e, drm_radeon_texture_t) -#ifdef CONFIG_DRM_SIS +#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE) /* SiS specific ioctls */ #define SIS_IOCTL_FB_ALLOC DRM_IOWR(0x44, drm_sis_mem_t) #define SIS_IOCTL_FB_FREE DRM_IOW( 0x45, drm_sis_mem_t) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/drm_context.h linux-2.5/drivers/char/drm/drm_context.h --- linux-2.5.5/drivers/char/drm/drm_context.h Thu Feb 21 17:45:16 2002 +++ linux-2.5/drivers/char/drm/drm_context.h Tue Mar 5 14:05:44 2002 @@ -27,6 +27,10 @@ * Authors: * Rickard E. (Rik) Faith * Gareth Hughes + * ChangeLog: + * 2001-11-16 Torsten Duwe + * added context constructor/destructor hooks, + * needed by SiS driver's memory management. */ #define __NO_VERSION__ @@ -316,6 +320,10 @@ /* Should this return -EBUSY instead? */ return -ENOMEM; } +#ifdef DRIVER_CTX_CTOR + if ( ctx.handle != DRM_KERNEL_CONTEXT ) + DRIVER_CTX_CTOR(ctx.handle); /* XXX: also pass dev ? */ +#endif if ( copy_to_user( (drm_ctx_t *)arg, &ctx, sizeof(ctx) ) ) return -EFAULT; @@ -390,6 +398,9 @@ priv->remove_auth_on_close = 1; } if ( ctx.handle != DRM_KERNEL_CONTEXT ) { +#ifdef DRIVER_CTX_DTOR + DRIVER_CTX_DTOR(ctx.handle); /* XXX: also pass dev ? */ +#endif DRM(ctxbitmap_free)( dev, ctx.handle ); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/drm_scatter.h linux-2.5/drivers/char/drm/drm_scatter.h --- linux-2.5.5/drivers/char/drm/drm_scatter.h Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/char/drm/drm_scatter.h Tue Feb 26 21:24:48 2002 @@ -66,9 +66,6 @@ drm_scatter_gather_t request; drm_sg_mem_t *entry; unsigned long pages, i, j; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte, pte_entry; DRM_DEBUG( "%s\n", __FUNCTION__ ); @@ -135,25 +132,9 @@ DRM_DEBUG( "sg alloc virtual = %p\n", entry->virtual ); for ( i = entry->handle, j = 0 ; j < pages ; i += PAGE_SIZE, j++ ) { - pgd = pgd_offset_k( i ); - if ( !pgd_present( *pgd ) ) + entry->pagelist[j] = vmalloc_to_page((void *)i); + if (!entry->pagelist[j]) goto failed; - - pmd = pmd_offset( pgd, i ); - if ( !pmd_present( *pmd ) ) - goto failed; - - preempt_disable(); - pte = pte_offset_map(pmd, i); - pte_entry = *pte; - pte_unmap(pte); - preempt_enable(); - - if (!pte_present(pte_entry)) - goto failed; - - entry->pagelist[j] = pte_page(pte_entry); - SetPageReserved(entry->pagelist[j]); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/drm_vm.h linux-2.5/drivers/char/drm/drm_vm.h --- linux-2.5.5/drivers/char/drm/drm_vm.h Thu Feb 21 17:45:16 2002 +++ linux-2.5/drivers/char/drm/drm_vm.h Tue Mar 5 14:05:44 2002 @@ -152,9 +152,6 @@ #endif unsigned long offset; unsigned long i; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte, entry; struct page *page; if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ @@ -162,26 +159,9 @@ offset = address - vma->vm_start; i = (unsigned long)map->handle + offset; - /* We have to walk page tables here because we need large SAREA's, and - * they need to be virtually contiguous in kernel space. - */ - pgd = pgd_offset_k( i ); - if (!pgd_present(*pgd)) - goto oom; - pmd = pmd_offset( pgd, i ); - if (!pmd_present(*pmd)) - goto oom; - - preempt_disable(); - pte = pte_offset_map(pmd, i); - entry = *pte; - pte_unmap(pte); - preempt_enable(); - - if (!pte_present(entry)) - goto oom; - - page = pte_page(entry); + page = vmalloc_to_page((void *)i); + if (!page) + return NOPAGE_OOM; get_page(page); DRM_DEBUG("shm_nopage 0x%lx\n", address); @@ -190,8 +170,6 @@ #else return page; #endif -oom: - return NOPAGE_OOM; } /* Special close routine which deletes map information if we are the last diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/i810_dma.c linux-2.5/drivers/char/drm/i810_dma.c --- linux-2.5.5/drivers/char/drm/i810_dma.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/char/drm/i810_dma.c Fri Mar 1 17:57:58 2002 @@ -73,7 +73,7 @@ *(volatile unsigned int *)(virt + outring) = n; \ outring += 4; \ outring &= ringmask; \ -} while (0); +} while (0) static inline void i810_print_status_page(drm_device_t *dev) { @@ -286,8 +286,8 @@ if(address == 0UL) return 0; - atomic_inc(&virt_to_page(address)->count); - set_bit(PG_locked, &virt_to_page(address)->flags); + get_page(virt_to_page(address)); + LockPage(virt_to_page(address)); return address; } @@ -296,9 +296,8 @@ { if (page) { struct page *p = virt_to_page(page); - atomic_dec(p); - clear_bit(PG_locked, &p->flags); - wake_up_page(p); + put_page(p); + UnlockPage(p); free_page(page); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/sis.h linux-2.5/drivers/char/drm/sis.h --- linux-2.5.5/drivers/char/drm/sis.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis.h Thu Dec 13 16:32:35 2001 @@ -0,0 +1,56 @@ +/* sis_drv.h -- Private header for sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/sis.h,v 1.1 2001/05/19 18:29:22 dawes Exp $ */ + +#ifndef __SIS_H__ +#define __SIS_H__ + +/* This remains constant for all DRM template files. + * Name it sisdrv_##x as there's a conflict with sis_free/malloc in the kernel + * that's used for fb devices + */ +#define DRM(x) sisdrv_##x + +/* General customization: + */ +#define __HAVE_AGP 1 +#define __MUST_HAVE_AGP 0 +#define __HAVE_MTRR 1 +#define __HAVE_CTX_BITMAP 1 + +/* Buffer customization: + */ +#define DRIVER_AGP_BUFFERS_MAP( dev ) \ + ((drm_sis_private_t *)((dev)->dev_private))->buffers + +extern int sis_init_context(int context); +extern int sis_final_context(int context); + +#define DRIVER_CTX_CTOR sis_init_context +#define DRIVER_CTX_DTOR sis_final_context + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/sis_drm.h linux-2.5/drivers/char/drm/sis_drm.h --- linux-2.5.5/drivers/char/drm/sis_drm.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_drm.h Thu Dec 13 16:32:35 2001 @@ -0,0 +1,36 @@ + +#ifndef _sis_drm_public_h_ +#define _sis_drm_public_h_ + +typedef struct { + int context; + unsigned int offset; + unsigned int size; + unsigned int free; +} drm_sis_mem_t; + +typedef struct { + unsigned int offset, size; +} drm_sis_agp_t; + +typedef struct { + unsigned int left, right; +} drm_sis_flip_t; + +#ifdef __KERNEL__ + +int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); + +int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); + +#endif + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/sis_drv.c linux-2.5/drivers/char/drm/sis_drv.c --- linux-2.5.5/drivers/char/drm/sis_drv.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_drv.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,74 @@ +/* sis.c -- sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include "sis.h" +#include "drmP.h" +#include "sis_drm.h" +#include "sis_drv.h" + +#define DRIVER_AUTHOR "SIS" +#define DRIVER_NAME "sis" +#define DRIVER_DESC "SIS 300/630/540" +#define DRIVER_DATE "20010503" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 0 + +#define DRIVER_IOCTLS \ + [DRM_IOCTL_NR(SIS_IOCTL_FB_ALLOC)] = { sis_fb_alloc, 1, 0 }, \ + [DRM_IOCTL_NR(SIS_IOCTL_FB_FREE)] = { sis_fb_free, 1, 0 }, \ + /* AGP Memory Management */ \ + [DRM_IOCTL_NR(SIS_IOCTL_AGP_INIT)] = { sisp_agp_init, 1, 0 }, \ + [DRM_IOCTL_NR(SIS_IOCTL_AGP_ALLOC)] = { sisp_agp_alloc, 1, 0 }, \ + [DRM_IOCTL_NR(SIS_IOCTL_AGP_FREE)] = { sisp_agp_free, 1, 0 } +#if 0 /* these don't appear to be defined */ + /* SIS Stereo */ + [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { sis_control, 1, 1 }, + [DRM_IOCTL_NR(SIS_IOCTL_FLIP)] = { sis_flip, 1, 1 }, + [DRM_IOCTL_NR(SIS_IOCTL_FLIP_INIT)] = { sis_flip_init, 1, 1 }, + [DRM_IOCTL_NR(SIS_IOCTL_FLIP_FINAL)] = { sis_flip_final, 1, 1 } +#endif + +#define __HAVE_COUNTERS 5 + +#include "drm_auth.h" +#include "drm_agpsupport.h" +#include "drm_bufs.h" +#include "drm_context.h" +#include "drm_dma.h" +#include "drm_drawable.h" +#include "drm_drv.h" +#include "drm_fops.h" +#include "drm_init.h" +#include "drm_ioctl.h" +#include "drm_lists.h" +#include "drm_lock.h" +#include "drm_memory.h" +#include "drm_proc.h" +#include "drm_vm.h" +#include "drm_stub.h" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/sis_drv.h linux-2.5/drivers/char/drm/sis_drv.h --- linux-2.5.5/drivers/char/drm/sis_drv.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_drv.h Thu Dec 13 16:32:35 2001 @@ -0,0 +1,45 @@ +/* sis_drv.h -- Private header for sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _SIS_DRV_H_ +#define _SIS_DRV_H_ + +typedef struct drm_sis_private { + drm_map_t *buffers; +} drm_sis_private_t; + +/* Stereo ? - this was never committed */ + +int sis_flip(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sis_flip_init(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sis_flip_final(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +void flip_final(void); + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/sis_ds.c linux-2.5/drivers/char/drm/sis_ds.c --- linux-2.5.5/drivers/char/drm/sis_ds.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_ds.c Fri Feb 15 18:02:54 2002 @@ -0,0 +1,406 @@ +/* sis_ds.c -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin + * + */ + +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sis_ds.h" + +/* Set Data Structure, not check repeated value + * temporarily used + */ + +set_t *setInit(void) +{ + int i; + set_t *set; + + set = (set_t *)MALLOC(sizeof(set_t)); + for(i = 0; i < SET_SIZE; i++){ + set->list[i].free_next = i+1; + set->list[i].alloc_next = -1; + } + set->list[SET_SIZE-1].free_next = -1; + set->free = 0; + set->alloc = -1; + set->trace = -1; + + return set; +} + +int setAdd(set_t *set, ITEM_TYPE item) +{ + int free = set->free; + + if(free != -1){ + set->list[free].val = item; + set->free = set->list[free].free_next; + } + else{ + return 0; + } + + set->list[free].alloc_next = set->alloc; + set->alloc = free; + set->list[free].free_next = -1; + + return 1; +} + +int setDel(set_t *set, ITEM_TYPE item) +{ + int alloc = set->alloc; + int prev = -1; + + while(alloc != -1){ + if(set->list[alloc].val == item){ + if(prev != -1) + set->list[prev].alloc_next = set->list[alloc].alloc_next; + else + set->alloc = set->list[alloc].alloc_next; + break; + } + prev = alloc; + alloc = set->list[alloc].alloc_next; + } + + if(alloc == -1) + return 0; + + set->list[alloc].free_next = set->free; + set->free = alloc; + set->list[alloc].alloc_next = -1; + + return 1; +} + +/* setFirst -> setAdd -> setNext is wrong */ + +int setFirst(set_t *set, ITEM_TYPE *item) +{ + if(set->alloc == -1) + return 0; + + *item = set->list[set->alloc].val; + set->trace = set->list[set->alloc].alloc_next; + + return 1; +} + +int setNext(set_t *set, ITEM_TYPE *item) +{ + if(set->trace == -1) + return 0; + + *item = set->list[set->trace].val; + set->trace = set->list[set->trace].alloc_next; + + return 1; +} + +int setDestroy(set_t *set) +{ + FREE(set); + + return 1; +} + +/* + * GLX Hardware Device Driver common code + * Copyright (C) 1999 Keith Whitwell + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#define ISFREE(bptr) ((bptr)->free) + +#define PRINTF(fmt, arg...) do{}while(0) +#define fprintf(fmt, arg...) do{}while(0) + +static void *calloc(size_t nmemb, size_t size) +{ + void *addr; + addr = kmalloc(nmemb*size, GFP_KERNEL); + memset(addr, 0, nmemb*size); + return addr; +} +#define free(n) kfree(n) + +void mmDumpMemInfo( memHeap_t *heap ) +{ + TMemBlock *p; + + PRINTF ("Memory heap %p:\n", heap); + if (heap == 0) { + PRINTF (" heap == 0\n"); + } else { + p = (TMemBlock *)heap; + while (p) { + PRINTF (" Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size, + p->free ? '.':'U', + p->reserved ? 'R':'.'); + p = p->next; + } + } + PRINTF ("End of memory blocks\n"); +} + +memHeap_t *mmInit(int ofs, + int size) +{ + PMemBlock blocks; + + if (size <= 0) { + return 0; + } + blocks = (TMemBlock *) calloc(1,sizeof(TMemBlock)); + if (blocks) { + blocks->ofs = ofs; + blocks->size = size; + blocks->free = 1; + return (memHeap_t *)blocks; + } else + return 0; +} + +/* Kludgey workaround for existing i810 server. Remove soon. + */ +memHeap_t *mmAddRange( memHeap_t *heap, + int ofs, + int size ) +{ + PMemBlock blocks; + blocks = (TMemBlock *) calloc(2,sizeof(TMemBlock)); + if (blocks) { + blocks[0].size = size; + blocks[0].free = 1; + blocks[0].ofs = ofs; + blocks[0].next = &blocks[1]; + + /* Discontinuity - stops JoinBlock from trying to join non-adjacent + * ranges. + */ + blocks[1].size = 0; + blocks[1].free = 0; + blocks[1].ofs = ofs+size; + blocks[1].next = (PMemBlock) heap; + return (memHeap_t *)blocks; + } + else + return heap; +} + +static TMemBlock* SliceBlock(TMemBlock *p, + int startofs, int size, + int reserved, int alignment) +{ + TMemBlock *newblock; + + /* break left */ + if (startofs > p->ofs) { + newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock)); + newblock->ofs = startofs; + newblock->size = p->size - (startofs - p->ofs); + newblock->free = 1; + newblock->next = p->next; + p->size -= newblock->size; + p->next = newblock; + p = newblock; + } + + /* break right */ + if (size < p->size) { + newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock)); + newblock->ofs = startofs + size; + newblock->size = p->size - size; + newblock->free = 1; + newblock->next = p->next; + p->size = size; + p->next = newblock; + } + + /* p = middle block */ + p->align = alignment; + p->free = 0; + p->reserved = reserved; + return p; +} + +PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch) +{ + int mask,startofs,endofs; + TMemBlock *p; + + if (!heap || align2 < 0 || size <= 0) + return NULL; + mask = (1 << align2)-1; + startofs = 0; + p = (TMemBlock *)heap; + while (p) { + if (ISFREE(p)) { + startofs = (p->ofs + mask) & ~mask; + if ( startofs < startSearch ) { + startofs = startSearch; + } + endofs = startofs+size; + if (endofs <= (p->ofs+p->size)) + break; + } + p = p->next; + } + if (!p) + return NULL; + p = SliceBlock(p,startofs,size,0,mask+1); + p->heap = heap; + return p; +} + +static __inline__ int Join2Blocks(TMemBlock *p) +{ + if (p->free && p->next && p->next->free) { + TMemBlock *q = p->next; + p->size += q->size; + p->next = q->next; + free(q); + return 1; + } + return 0; +} + +int mmFreeMem(PMemBlock b) +{ + TMemBlock *p,*prev; + + if (!b) + return 0; + if (!b->heap) { + fprintf(stderr, "no heap\n"); + return -1; + } + p = b->heap; + prev = NULL; + while (p && p != b) { + prev = p; + p = p->next; + } + if (!p || p->free || p->reserved) { + if (!p) + fprintf(stderr, "block not found in heap\n"); + else if (p->free) + fprintf(stderr, "block already free\n"); + else + fprintf(stderr, "block is reserved\n"); + return -1; + } + p->free = 1; + Join2Blocks(p); + if (prev) + Join2Blocks(prev); + return 0; +} + +int mmReserveMem(memHeap_t *heap, int offset,int size) +{ + int endofs; + TMemBlock *p; + + if (!heap || size <= 0) + return -1; + endofs = offset+size; + p = (TMemBlock *)heap; + while (p && p->ofs <= offset) { + if (ISFREE(p) && endofs <= (p->ofs+p->size)) { + SliceBlock(p,offset,size,1,1); + return 0; + } + p = p->next; + } + return -1; +} + +int mmFreeReserved(memHeap_t *heap, int offset) +{ + TMemBlock *p,*prev; + + if (!heap) + return -1; + p = (TMemBlock *)heap; + prev = NULL; + while (p && p->ofs != offset) { + prev = p; + p = p->next; + } + if (!p || !p->reserved) + return -1; + p->free = 1; + p->reserved = 0; + Join2Blocks(p); + if (prev) + Join2Blocks(prev); + return 0; +} + +void mmDestroy(memHeap_t *heap) +{ + TMemBlock *p,*q; + + if (!heap) + return; + p = (TMemBlock *)heap; + while (p) { + q = p->next; + free(p); + p = q; + } +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/sis_ds.h linux-2.5/drivers/char/drm/sis_ds.h --- linux-2.5.5/drivers/char/drm/sis_ds.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_ds.h Thu Dec 13 16:32:35 2001 @@ -0,0 +1,163 @@ +/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin + * + */ + +#ifndef _sis_ds_h_ +#define _sis_ds_h_ + +/* Set Data Structure */ + +#define SET_SIZE 5000 +#define MALLOC(s) kmalloc(s, GFP_KERNEL) +#define FREE(s) kfree(s) + +typedef unsigned int ITEM_TYPE; + +typedef struct { + ITEM_TYPE val; + int alloc_next, free_next; +} list_item_t; + +typedef struct { + int alloc; + int free; + int trace; + list_item_t list[SET_SIZE]; +} set_t; + +set_t *setInit(void); +int setAdd(set_t *set, ITEM_TYPE item); +int setDel(set_t *set, ITEM_TYPE item); +int setFirst(set_t *set, ITEM_TYPE *item); +int setNext(set_t *set, ITEM_TYPE *item); +int setDestroy(set_t *set); + +#endif + +/* + * GLX Hardware Device Driver common code + * Copyright (C) 1999 Keith Whitwell + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef MM_INC +#define MM_INC + +struct mem_block_t { + struct mem_block_t *next; + struct mem_block_t *heap; + int ofs,size; + int align; + int free:1; + int reserved:1; +}; +typedef struct mem_block_t TMemBlock; +typedef struct mem_block_t *PMemBlock; + +/* a heap is just the first block in a chain */ +typedef struct mem_block_t memHeap_t; + +static __inline__ int mmBlockSize(PMemBlock b) +{ return b->size; } + +static __inline__ int mmOffset(PMemBlock b) +{ return b->ofs; } + +static __inline__ void mmMarkReserved(PMemBlock b) +{ b->reserved = 1; } + +/* + * input: total size in bytes + * return: a heap pointer if OK, NULL if error + */ +memHeap_t *mmInit( int ofs, int size ); + + + +memHeap_t *mmAddRange( memHeap_t *heap, + int ofs, + int size ); + + +/* + * Allocate 'size' bytes with 2^align2 bytes alignment, + * restrict the search to free memory after 'startSearch' + * depth and back buffers should be in different 4mb banks + * to get better page hits if possible + * input: size = size of block + * align2 = 2^align2 bytes alignment + * startSearch = linear offset from start of heap to begin search + * return: pointer to the allocated block, 0 if error + */ +PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch ); + +/* + * Free block starts at offset + * input: pointer to a block + * return: 0 if OK, -1 if error + */ +int mmFreeMem( PMemBlock b ); + +/* + * Reserve 'size' bytes block start at offset + * This is used to prevent allocation of memory already used + * by the X server for the front buffer, pixmaps, and cursor + * input: size, offset + * output: 0 if OK, -1 if error + */ +int mmReserveMem( memHeap_t *heap, int offset,int size ); +int mmFreeReserved( memHeap_t *heap, int offset ); + +/* + * destroy MM + */ +void mmDestroy( memHeap_t *mmInit ); + +/* For debuging purpose. */ +void mmDumpMemInfo( memHeap_t *mmInit ); + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/drm/sis_mm.c linux-2.5/drivers/char/drm/sis_mm.c --- linux-2.5.5/drivers/char/drm/sis_mm.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/drm/sis_mm.c Thu Dec 13 16:32:35 2001 @@ -0,0 +1,307 @@ +/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin + * + */ + +#define __NO_VERSION__ +#include "sis.h" +#include +#include "drmP.h" +#include "sis_drm.h" +#include "sis_drv.h" +#include "sis_ds.h" + +#define MAX_CONTEXT 100 +#define VIDEO_TYPE 0 +#define AGP_TYPE 1 + +typedef struct { + int used; + int context; + set_t *sets[2]; /* 0 for video, 1 for AGP */ +} sis_context_t; + +static sis_context_t global_ppriv[MAX_CONTEXT]; + +static int add_alloc_set(int context, int type, unsigned int val) +{ + int i, retval = 0; + + for(i = 0; i < MAX_CONTEXT; i++) + if(global_ppriv[i].used && global_ppriv[i].context == context){ + retval = setAdd(global_ppriv[i].sets[type], val); + break; + } + return retval; +} + +static int del_alloc_set(int context, int type, unsigned int val) +{ + int i, retval = 0; + for(i = 0; i < MAX_CONTEXT; i++) + if(global_ppriv[i].used && global_ppriv[i].context == context){ + retval = setDel(global_ppriv[i].sets[type], val); + break; + } + return retval; +} + +/* fb management via fb device */ +#if 1 +int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t fb; + struct sis_memreq req; + int retval = 0; + + if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb))) + return -EFAULT; + + req.size = fb.size; + sis_malloc(&req); + if(req.offset){ + /* TODO */ + fb.offset = req.offset; + fb.free = req.offset; + if(!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)){ + DRM_DEBUG("adding to allocation set fails\n"); + sis_free(req.offset); + retval = -1; + } + } + else{ + fb.offset = 0; + fb.size = 0; + fb.free = 0; + } + + if (copy_to_user((drm_sis_mem_t *)arg, &fb, sizeof(fb))) return -EFAULT; + + DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset); + + return retval; +} + +int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t fb; + int retval = 0; + + if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb))) + return -EFAULT; + + if(!fb.free){ + return -1; + } + + sis_free(fb.free); + if(!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) + retval = -1; + + DRM_DEBUG("free fb, offset = %d\n", fb.free); + + return retval; +} + +#else + +int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return -1; +} + +int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return 0; +} + +#endif + +/* agp memory management */ +#if 1 + +static memHeap_t *AgpHeap = NULL; + +int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_agp_t agp; + + if (copy_from_user(&agp, (drm_sis_agp_t *)arg, sizeof(agp))) + return -EFAULT; + + AgpHeap = mmInit(agp.offset, agp.size); + + DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size); + + return 0; +} + +int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t agp; + PMemBlock block; + int retval = 0; + + if(!AgpHeap) + return -1; + + if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp))) + return -EFAULT; + + block = mmAllocMem(AgpHeap, agp.size, 0, 0); + if(block){ + /* TODO */ + agp.offset = block->ofs; + agp.free = (unsigned int)block; + if(!add_alloc_set(agp.context, AGP_TYPE, agp.free)){ + DRM_DEBUG("adding to allocation set fails\n"); + mmFreeMem((PMemBlock)agp.free); + retval = -1; + } + } + else{ + agp.offset = 0; + agp.size = 0; + agp.free = 0; + } + + if (copy_to_user((drm_sis_mem_t *)arg, &agp, sizeof(agp))) return -EFAULT; + + DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset); + + return retval; +} + +int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t agp; + int retval = 0; + + if(!AgpHeap) + return -1; + + if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp))) + return -EFAULT; + + if(!agp.free){ + return -1; + } + + mmFreeMem((PMemBlock)agp.free); + if(!del_alloc_set(agp.context, AGP_TYPE, agp.free)) + retval = -1; + + DRM_DEBUG("free agp, free = %d\n", agp.free); + + return retval; +} + +#endif + +int sis_init_context(int context) +{ + int i; + + for(i = 0; i < MAX_CONTEXT ; i++) + if(global_ppriv[i].used && (global_ppriv[i].context == context)) + break; + + if(i >= MAX_CONTEXT){ + for(i = 0; i < MAX_CONTEXT ; i++){ + if(!global_ppriv[i].used){ + global_ppriv[i].context = context; + global_ppriv[i].used = 1; + global_ppriv[i].sets[0] = setInit(); + global_ppriv[i].sets[1] = setInit(); + DRM_DEBUG("init allocation set, socket=%d, context = %d\n", + i, context); + break; + } + } + if((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) || + (global_ppriv[i].sets[1] == NULL)){ + return 0; + } + } + + return 1; +} + +int sis_final_context(int context) +{ + int i; + + for(i=0; i +#include +#include + +void kbd_leds(unsigned char leds) +{ +} + +int kbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + return (scancode == keycode) ? 0 : -EINVAL; +} + +int kbd_getkeycode(unsigned int scancode) +{ + return scancode; +} + +int kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + *keycode = scancode; + + return 1; +} + +char kbd_unexpected_up(unsigned char keycode) +{ + return 0x80; +} + +void __init kbd_init_hw(void) +{ + printk("Dummy keyboard driver installed.\n"); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/dz.c linux-2.5/drivers/char/dz.c --- linux-2.5.5/drivers/char/dz.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/char/dz.c Sun Mar 3 17:54:35 2002 @@ -14,41 +14,31 @@ * after patches by harald to irq code. * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout * field from "current" - somewhere between 2.1.121 and 2.1.131 -Qua Jun 27 15:02:26 BRT 2001 + Qua Jun 27 15:02:26 BRT 2001 * [27-JUN-2001] Arnaldo Carvalho de Melo - cleanups * * Parts (C) 1999 David Airlie, airlied@linux.ie * [07-SEP-99] Bugfixes */ -/* #define DEBUG_DZ 1 */ - -#include -#include +#define DEBUG_DZ 1 #include +#include #include #include -#include +#include #include #include #include +#include #include #include #include -#include -#include #include -#include /* for definition of SERIAL */ +#include -/* for definition of struct console */ -#ifdef CONFIG_SERIAL_CONSOLE -#define CONSOLE_LINE (3) -#endif /* ifdef CONFIG_SERIAL_CONSOLE */ -#if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) #include -#endif /* if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) */ - #include #include #include @@ -59,15 +49,15 @@ #include #include -#ifdef DEBUG_DZ #include #include #include -extern int (*prom_printf) (char *,...); -#endif +#define CONSOLE_LINE (3) /* for definition of struct console */ +extern int (*prom_printf) (char *,...); +struct console dz_sercons; #include "dz.h" @@ -75,16 +65,15 @@ DECLARE_TASK_QUEUE(tq_serial); +extern wait_queue_head_t keypress_wait; static struct dz_serial *lines[4]; static unsigned char tmp_buffer[256]; - - #ifdef DEBUG_DZ /* * debugging code to send out chars via prom */ -static void debug_console( const char *s,int count) +static void debug_console(const char *s,int count) { unsigned i; @@ -105,17 +94,19 @@ * ------------------------------------------------------------ */ -static inline unsigned short dz_in (struct dz_serial *info, unsigned offset) +static inline unsigned short dz_in(struct dz_serial *info, unsigned offset) { - volatile u16 *addr = (volatile u16 *)(info->port + offset); - + volatile unsigned short *addr = + (volatile unsigned short *) (info->port + offset); return *addr; } -static inline void dz_out (struct dz_serial *info, unsigned offset, - unsigned short value) +static inline void dz_out(struct dz_serial *info, unsigned offset, + unsigned short value) { - volatile u16 *addr = (volatile u16 *)(info->port + offset); + + volatile unsigned short *addr = + (volatile unsigned short *) (info->port + offset); *addr = value; } @@ -129,33 +120,34 @@ * ------------------------------------------------------------ */ -static void dz_stop (struct tty_struct *tty) +static void dz_stop(struct tty_struct *tty) { - struct dz_serial *info; + struct dz_serial *info; unsigned short mask, tmp; - if (!tty) - return; - - info = (struct dz_serial *)tty->driver_data; + if (tty == 0) + return; + + info = (struct dz_serial *) tty->driver_data; mask = 1 << info->line; - tmp = dz_in (info, DZ_TCR); /* read the TX flag */ + tmp = dz_in(info, DZ_TCR); /* read the TX flag */ - tmp &= ~mask; /* clear the TX flag */ - dz_out (info, DZ_TCR, tmp); + tmp &= ~mask; /* clear the TX flag */ + dz_out(info, DZ_TCR, tmp); } -static void dz_start (struct tty_struct *tty) +static void dz_start(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned short mask, tmp; mask = 1 << info->line; - tmp = dz_in (info, DZ_TCR); /* read the TX flag */ + tmp = dz_in(info, DZ_TCR); /* read the TX flag */ + + tmp |= mask; /* set the TX flag */ + dz_out(info, DZ_TCR, tmp); - tmp |= mask; /* set the TX flag */ - dz_out (info, DZ_TCR, tmp); } /* @@ -186,7 +178,7 @@ * processing in the software interrupt portion of the driver. * ------------------------------------------------------------ */ -static inline void dz_sched_event (struct dz_serial *info, int event) +static inline void dz_sched_event(struct dz_serial *info, int event) { info->event |= 1 << event; queue_task(&info->tqueue, &tq_serial); @@ -200,8 +192,9 @@ * This routine deals with inputs from any lines. * ------------------------------------------------------------ */ -static inline void receive_chars (struct dz_serial *info_in) +static inline void receive_chars(struct dz_serial *info_in) { + struct dz_serial *info; struct tty_struct *tty = 0; struct async_icount *icount; @@ -235,7 +228,8 @@ if (!tty) break; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; *tty->flip.char_buf_ptr = ch; *tty->flip.flag_buf_ptr = 0; @@ -243,16 +237,15 @@ /* keep track of the statistics */ if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) { - if (status & DZ_PERR) /* parity error */ + if (status & DZ_PERR) /* parity error */ icount->parity++; else if (status & DZ_FERR) /* frame error */ icount->frame++; - if (status & DZ_OERR) /* overrun error */ + if (status & DZ_OERR) /* overrun error */ icount->overrun++; - /* - * Check to see if we should ignore the character and - * mask off conditions that should be ignored + /* check to see if we should ignore the character + and mask off conditions that should be ignored */ if (status & info->ignore_status_mask) { @@ -260,24 +253,18 @@ break; goto ignore_char; } - /* mask off the error conditions we want to ignore */ tmp = status & info->read_status_mask; if (tmp & DZ_PERR) { *tty->flip.flag_buf_ptr = TTY_PARITY; -#ifdef DEBUG_DZ - debug_console("PERR\n",5); -#endif /* DEBUG_DZ */ + debug_console("PERR\n", 5); } else if (tmp & DZ_FERR) { *tty->flip.flag_buf_ptr = TTY_FRAME; -#ifdef DEBUG_DZ - debug_console("FERR\n",5); -#endif /* DEBUG_DZ */ - } if (tmp & DZ_OERR) { -#ifdef DEBUG_DZ - debug_console("OERR\n",5); -#endif /* DEBUG_DZ */ + debug_console("FERR\n", 5); + } + if (tmp & DZ_OERR) { + debug_console("OERR\n", 5); if (tty->flip.count < TTY_FLIPBUF_SIZE) { tty->flip.count++; tty->flip.flag_buf_ptr++; @@ -286,11 +273,10 @@ } } } - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; -ignore_char: - ; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: } while (status & DZ_DVAL); if (tty) @@ -304,26 +290,25 @@ * This routine deals with outputs to any lines. * ------------------------------------------------------------ */ -static inline void transmit_chars (struct dz_serial *info) +static inline void transmit_chars(struct dz_serial *info) { unsigned char tmp; - if (info->x_char) { /* XON/XOFF chars */ + + + if (info->x_char) { /* XON/XOFF chars */ dz_out(info, DZ_TDR, info->x_char); info->icount.tx++; info->x_char = 0; return; } - /* if nothing to do or stopped or hardware stopped */ - if ((info->xmit_cnt <= 0) || info->tty->stopped || - info->tty->hw_stopped) { + if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) { dz_stop(info->tty); return; } - /* - * If something to do ... (rember the dz has no output fifo so we go + * if something to do ... (rember the dz has no output fifo so we go * one char at a time :-< */ tmp = (unsigned short) info->xmit_buf[info->xmit_tail++]; @@ -332,7 +317,8 @@ info->icount.tx++; if (--info->xmit_cnt < WAKEUP_CHARS) - dz_sched_event(info, DZ_EVENT_WRITE_WAKEUP); + dz_sched_event(info, DZ_EVENT_WRITE_WAKEUP); + /* Are we done */ if (info->xmit_cnt <= 0) @@ -346,7 +332,7 @@ * Only valid for the MODEM line duh ! * ------------------------------------------------------------ */ -static inline void check_modem_status (struct dz_serial *info) +static inline void check_modem_status(struct dz_serial *info) { unsigned short status; @@ -355,7 +341,7 @@ return; status = dz_in(info, DZ_MSR); - + /* it's easy, since DSR2 is the only bit in the register */ if (status) info->icount.dsr++; @@ -369,20 +355,20 @@ * It deals with the multiple ports. * ------------------------------------------------------------ */ -static void dz_interrupt (int irq, void *dev, struct pt_regs *regs) +static void dz_interrupt(int irq, void *dev, struct pt_regs *regs) { struct dz_serial *info; unsigned short status; - /* get the reason why we just got an irq */ - status = dz_in((struct dz_serial *)dev, DZ_CSR); - info = lines[LINE(status)]; /* re-arrange info the proper port */ + /* get the reason why we just got an irq */ + status = dz_in((struct dz_serial *) dev, DZ_CSR); + info = lines[LINE(status)]; /* re-arrange info the proper port */ - if (status & DZ_RDONE) + if (status & DZ_RDONE) receive_chars(info); /* the receive function */ - if (status & DZ_TRDY) - transmit_chars (info); + if (status & DZ_TRDY) + transmit_chars(info); } /* @@ -400,12 +386,12 @@ * interrupt driver proper are done; the interrupt driver schedules * them using rs_sched_event(), and they get done here. */ -static void do_serial_bh (void) +static void do_serial_bh(void) { - run_task_queue (&tq_serial); + run_task_queue(&tq_serial); } -static void do_softint (void *private_data) +static void do_softint(void *private_data) { struct dz_serial *info = (struct dz_serial *) private_data; struct tty_struct *tty = info->tty; @@ -414,10 +400,9 @@ return; if (test_and_clear_bit(DZ_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup) (tty); - wake_up_interruptible (&tty->write_wait); + wake_up_interruptible(&tty->write_wait); } } @@ -431,11 +416,11 @@ * do_serial_hangup() -> tty->hangup() -> rs_hangup() * ------------------------------------------------------------------- */ -static void do_serial_hangup (void *private_data) +static void do_serial_hangup(void *private_data) { struct dz_serial *info = (struct dz_serial *) private_data; struct tty_struct *tty = info->tty;; - + if (!tty) return; @@ -449,31 +434,31 @@ * various initialization tasks * ------------------------------------------------------------------- */ -static int startup (struct dz_serial *info) +static int startup(struct dz_serial *info) { unsigned long page, flags; unsigned short tmp; if (info->is_initialized) return 0; - - save_and_cli(flags); + + save_flags(flags); + cli(); if (!info->port) { - if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); restore_flags(flags); return -ENODEV; } - if (!info->xmit_buf) { page = get_free_page(GFP_KERNEL); if (!page) { - restore_flags (flags); - return -ENOMEM; + restore_flags(flags); + return -ENOMEM; } - info->xmit_buf = (unsigned char *)page; + info->xmit_buf = (unsigned char *) page; } - if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); @@ -484,18 +469,24 @@ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - change_speed(info); /* set up the speed */ + /* set up the speed */ + change_speed(info); - /* - * Clear the line transmitter buffer I can't figure out why I need to - * do this - but its necessary - in order for the console portion and - * the interrupt portion to live happily side by side. + /* clear the line transmitter buffer + I can't figure out why I need to do this - but + its necessary - in order for the console portion + and the interrupt portion to live happily side by side. + */ + + /* clear the line transmitter buffer + I can't figure out why I need to do this - but + its necessary - in order for the console portion + and the interrupt portion to live happily side by side. */ info->is_initialized = 1; restore_flags(flags); - return 0; } @@ -507,7 +498,7 @@ * DTR is dropped if the hangup on close termio flag is on. * ------------------------------------------------------------------- */ -static void shutdown (struct dz_serial *info) +static void shutdown(struct dz_serial *info) { unsigned long flags; unsigned short tmp; @@ -515,18 +506,20 @@ if (!info->is_initialized) return; - save_and_cli(flags); + save_flags(flags); + cli(); + + dz_stop(info->tty); + - dz_stop (info->tty); info->cflags &= ~DZ_CREAD; /* turn off receive enable flag */ dz_out(info, DZ_LPR, info->cflags); - if (info->xmit_buf) { /* free Tx buffer */ - free_page((unsigned long)info->xmit_buf); + if (info->xmit_buf) { /* free Tx buffer */ + free_page((unsigned long) info->xmit_buf); info->xmit_buf = 0; } - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { tmp = dz_in(info, DZ_TCR); if (tmp & DZ_MODEM_DTR) { @@ -534,13 +527,11 @@ dz_out(info, DZ_TCR, tmp); } } - if (info->tty) - set_bit (TTY_IO_ERROR, &info->tty->flags); + set_bit(TTY_IO_ERROR, &info->tty->flags); info->is_initialized = 0; - - restore_flags (flags); + restore_flags(flags); } /* @@ -550,7 +541,7 @@ * set the baud rate. * ------------------------------------------------------------------- */ -static void change_speed (struct dz_serial *info) +static void change_speed(struct dz_serial *info) { unsigned long flags; unsigned cflag; @@ -558,26 +549,27 @@ if (!info->tty || !info->tty->termios) return; - - save_and_cli(flags); - + + save_flags(flags); + cli(); + info->cflags = info->line; cflag = info->tty->termios->c_cflag; switch (cflag & CSIZE) { - case CS5: - info->cflags |= DZ_CS5; - break; - case CS6: - info->cflags |= DZ_CS6; - break; - case CS7: - info->cflags |= DZ_CS7; - break; - case CS8: - default: - info->cflags |= DZ_CS8; + case CS5: + info->cflags |= DZ_CS5; + break; + case CS6: + info->cflags |= DZ_CS6; + break; + case CS7: + info->cflags |= DZ_CS7; + break; + case CS8: + default: + info->cflags |= DZ_CS8; } if (cflag & CSTOPB) @@ -586,7 +578,7 @@ info->cflags |= DZ_PARENB; if (cflag & PARODD) info->cflags |= DZ_PARODD; - + baud = tty_get_baud_rate(info->tty); switch (baud) { case 50: @@ -600,19 +592,19 @@ break; case 134: info->cflags |= DZ_B134; - break; + break; case 150: info->cflags |= DZ_B150; break; case 300: info->cflags |= DZ_B300; - break; + break; case 600: info->cflags |= DZ_B600; break; case 1200: info->cflags |= DZ_B1200; - break; + break; case 1800: info->cflags |= DZ_B1800; break; @@ -624,16 +616,16 @@ break; case 3600: info->cflags |= DZ_B3600; - break; + break; case 4800: info->cflags |= DZ_B4800; break; case 7200: info->cflags |= DZ_B7200; - break; - case 9600: + break; + case 9600: default: - info->cflags |= DZ_B9600; + info->cflags |= DZ_B9600; } info->cflags |= DZ_RXENAB; @@ -642,8 +634,8 @@ /* setup accept flag */ info->read_status_mask = DZ_OERR; if (I_INPCK(info->tty)) - info->read_status_mask |= (DZ_FERR | DZ_PERR); - + info->read_status_mask |= (DZ_FERR | DZ_PERR); + /* characters to ignore */ info->ignore_status_mask = 0; if (I_IGNPAR(info->tty)) @@ -659,17 +651,19 @@ * Flush the buffer. * ------------------------------------------------------------------- */ -static void dz_flush_chars (struct tty_struct *tty) +static void dz_flush_chars(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned long flags; - if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !info->xmit_buf) + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !info->xmit_buf) return; - save_and_cli(flags); - dz_start (info->tty); + save_flags(flags); + cli(); + + dz_start(info->tty); + restore_flags(flags); } @@ -681,64 +675,67 @@ * main output routine. * ------------------------------------------------------------------- */ -static int dz_write (struct tty_struct *tty, int from_user, - const unsigned char *buf, int count) +static int dz_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned long flags; int c, ret = 0; - if (!tty ) + if (!tty) return ret; if (!info->xmit_buf) return ret; if (!tmp_buf) tmp_buf = tmp_buffer; + + if (from_user) { - down (&tmp_buf_sem); + + down(&tmp_buf_sem); while (1) { - c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, - DZ_XMIT_SIZE - info->xmit_head)); + c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; - c -= copy_from_user (tmp_buf, buf, c); + c -= copy_from_user(tmp_buf, buf, c); if (!c) { if (!ret) ret = -EFAULT; break; } + save_flags(flags); + cli(); - save_and_cli(flags); - - c = MIN(c, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, - DZ_XMIT_SIZE - info->xmit_head)); + c = MIN(c, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); - info->xmit_head = ((info->xmit_head + c) & - (DZ_XMIT_SIZE - 1)); + info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE - 1)); info->xmit_cnt += c; + restore_flags(flags); buf += c; count -= c; ret += c; } + up(&tmp_buf_sem); } else { + + while (1) { - save_and_cli(flags); + save_flags(flags); + cli(); - c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, - DZ_XMIT_SIZE - info->xmit_head)); + c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head)); if (c <= 0) { - restore_flags (flags); + restore_flags(flags); break; } memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = ((info->xmit_head + c) & - (DZ_XMIT_SIZE-1)); + info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE - 1)); info->xmit_cnt += c; + restore_flags(flags); buf += c; @@ -747,14 +744,14 @@ } } + if (info->xmit_cnt) { if (!tty->stopped) { if (!tty->hw_stopped) { - dz_start (info->tty); + dz_start(info->tty); } } } - return ret; } @@ -765,15 +762,14 @@ * compute the amount of space available for writing. * ------------------------------------------------------------------- */ -static int dz_write_room (struct tty_struct *tty) +static int dz_write_room(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; int ret; ret = DZ_XMIT_SIZE - info->xmit_cnt - 1; if (ret < 0) ret = 0; - return ret; } @@ -784,10 +780,10 @@ * compute the amount of char left to be transmitted * ------------------------------------------------------------------- */ -static int dz_chars_in_buffer (struct tty_struct *tty) +static int dz_chars_in_buffer(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - + struct dz_serial *info = (struct dz_serial *) tty->driver_data; + return info->xmit_cnt; } @@ -798,19 +794,18 @@ * Empty the output buffer * ------------------------------------------------------------------- */ -static void dz_flush_buffer (struct tty_struct *tty) +static void dz_flush_buffer(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; - + struct dz_serial *info = (struct dz_serial *) tty->driver_data; + cli(); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; sti(); - wake_up_interruptible (&tty->write_wait); + wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - tty->ldisc.write_wakeup(tty); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); } /* @@ -821,17 +816,17 @@ * incoming characters should be throttled (or not). * ------------------------------------------------------------ */ -static void dz_throttle (struct tty_struct *tty) +static void dz_throttle(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; if (I_IXOFF(tty)) info->x_char = STOP_CHAR(tty); } -static void dz_unthrottle (struct tty_struct *tty) +static void dz_unthrottle(struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; if (I_IXOFF(tty)) { if (info->x_char) @@ -841,9 +836,9 @@ } } -static void dz_send_xchar (struct tty_struct *tty, char ch) +static void dz_send_xchar(struct tty_struct *tty, char ch) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; info->x_char = ch; @@ -860,11 +855,11 @@ struct serial_struct *retinfo) { struct serial_struct tmp; - + if (!retinfo) return -EFAULT; - memset (&tmp, 0, sizeof(tmp)); + memset(&tmp, 0, sizeof(tmp)); tmp.type = info->type; tmp.line = info->line; @@ -878,8 +873,8 @@ return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; } -static int set_serial_info (struct dz_serial *info, - struct serial_struct *new_info) +static int set_serial_info(struct dz_serial *info, + struct serial_struct *new_info) { struct serial_struct new_serial; struct dz_serial old_info; @@ -910,7 +905,6 @@ info->closing_wait = new_serial.closing_wait; retval = startup(info); - return retval; } @@ -924,17 +918,17 @@ * transmit holding register is empty. This functionality * allows an RS485 driver to be written in user space. */ -static int get_lsr_info (struct dz_serial *info, unsigned int *value) +static int get_lsr_info(struct dz_serial *info, unsigned int *value) { - unsigned short status = dz_in (info, DZ_LPR); + unsigned short status = dz_in(info, DZ_LPR); - return put_user (status, value); + return put_user(status, value); } /* * This routine sends a break character out the serial port. */ -static void send_break (struct dz_serial *info, int duration) +static void send_break(struct dz_serial *info, int duration) { unsigned long flags; unsigned short tmp, mask; @@ -943,33 +937,36 @@ return; mask = 1 << info->line; - tmp = dz_in (info, DZ_TCR); + tmp = dz_in(info, DZ_TCR); tmp |= mask; current->state = TASK_INTERRUPTIBLE; - save_and_cli(flags); + save_flags(flags); + cli(); + dz_out(info, DZ_TCR, tmp); + schedule_timeout(duration); + tmp &= ~mask; dz_out(info, DZ_TCR, tmp); + restore_flags(flags); } static int dz_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - int error; - struct dz_serial * info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; int retval; - if (cmd != TIOCGSERIAL && cmd != TIOCSSERIAL && - cmd != TIOCSERCONFIG && cmd != TIOCSERGWILD && - cmd != TIOCSERSWILD && cmd != TIOCSERGSTRUCT) { + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } - switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); @@ -977,7 +974,7 @@ return retval; tty_wait_until_sent(tty, 0); if (!arg) - send_break(info, HZ/4); /* 1/4 second */ + send_break(info, HZ / 4); /* 1/4 second */ return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ @@ -985,41 +982,32 @@ if (retval) return retval; tty_wait_until_sent(tty, 0); - send_break(info, arg ? arg*(HZ/10) : HZ/4); + send_break(info, arg ? arg * (HZ / 10) : HZ / 4); return 0; case TIOCGSOFTCAR: - error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(long)); - if (error) - return error; - put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); - return 0; + return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); case TIOCSSOFTCAR: - if (get_user (arg, (unsigned long *)arg)) + if (get_user(arg, (unsigned long *) arg)) return -EFAULT; - - tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0); + tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); return 0; case TIOCGSERIAL: - error = verify_area(VERIFY_WRITE, (void *)arg, - sizeof(struct serial_struct)); - if (error) - return error; - return get_serial_info(info, (struct serial_struct *)arg); + return get_serial_info(info, (struct serial_struct *) arg); case TIOCSSERIAL: return set_serial_info(info, (struct serial_struct *) arg); - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info (info, (unsigned int *)arg); + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); case TIOCSERGSTRUCT: - return copy_to_user((struct dz_serial *)arg, info, - sizeof(struct dz_serial)) ? -EFAULT : 0; - + return copy_to_user((struct dz_serial *) arg, info, + sizeof(struct dz_serial)) ? -EFAULT : 0; + default: return -ENOIOCTLCMD; } @@ -1027,15 +1015,15 @@ return 0; } -static void dz_set_termios (struct tty_struct *tty, - struct termios *old_termios) +static void dz_set_termios(struct tty_struct *tty, + struct termios *old_termios) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; if (tty->termios->c_cflag == old_termios->c_cflag) return; - change_speed (info); + change_speed(info); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -1055,37 +1043,36 @@ */ static void dz_close(struct tty_struct *tty, struct file *filp) { - struct dz_serial * info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned long flags; if (!info) return; - - save_and_cli(flags); + + save_flags(flags); + cli(); if (tty_hung_up_p(filp)) { restore_flags(flags); return; } - if ((tty->count == 1) && (info->count != 1)) { /* - * Uh, oh. tty->count is 1, which means that the tty structure - * will be freed. Info->count should always be one in these - * conditions. If it's greater than one, we've got real - * problems, since it means the serial port won't be shutdown. + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. */ printk("dz_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } - if (--info->count < 0) { printk("ds_close: bad serial port count for ttyS%02d: %d\n", info->line, info->count); info->count = 0; } - if (info->count) { restore_flags(flags); return; @@ -1100,8 +1087,8 @@ if (info->flags & DZ_CALLOUT_ACTIVE) info->callout_termios = *tty->termios; /* - * Now we wait for the transmit buffer to clear; and we notify the line - * discipline to only process XON/XOFF characters. + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; @@ -1109,26 +1096,27 @@ tty_wait_until_sent(tty, info->closing_wait); /* - * At this point we stop accepting input. To do this, we disable the - * receive line status interrupts. + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts. */ + shutdown(info); if (tty->driver.flush_buffer) - tty->driver.flush_buffer (tty); + tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer (tty); + tty->ldisc.flush_buffer(tty); tty->closing = 0; info->event = 0; info->tty = 0; if (tty->ldisc.num != ldiscs[N_TTY].num) { if (tty->ldisc.close) - tty->ldisc.close(tty); + (tty->ldisc.close) (tty); tty->ldisc = ldiscs[N_TTY]; tty->termios->c_line = N_TTY; if (tty->ldisc.open) - tty->ldisc.open(tty); + (tty->ldisc.open) (tty); } if (info->blocked_open) { if (info->close_delay) { @@ -1137,7 +1125,6 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE | DZ_CLOSING); wake_up_interruptible(&info->close_wait); @@ -1147,10 +1134,10 @@ /* * dz_hangup () --- called by tty_hangup() when a hangup is signaled. */ -static void dz_hangup (struct tty_struct *tty) +static void dz_hangup(struct tty_struct *tty) { struct dz_serial *info = (struct dz_serial *) tty->driver_data; - + dz_flush_buffer(tty); shutdown(info); info->event = 0; @@ -1165,10 +1152,9 @@ * rs_open() and friends * ------------------------------------------------------------ */ -static int block_til_ready(struct tty_struct *tty, struct file *filp, - struct dz_serial *info) +static int block_til_ready(struct tty_struct *tty, struct file *filp, struct dz_serial *info) { - DECLARE_WAITQUEUE(wait, current); + DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; @@ -1180,7 +1166,6 @@ interruptible_sleep_on(&info->close_wait); return -EAGAIN; } - /* * If this is a callout device, then just make sure the normal * device isn't being used. @@ -1188,47 +1173,44 @@ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { if (info->flags & DZ_NORMAL_ACTIVE) return -EBUSY; - + if ((info->flags & DZ_CALLOUT_ACTIVE) && (info->flags & DZ_SESSION_LOCKOUT) && (info->session != current->session)) return -EBUSY; - + if ((info->flags & DZ_CALLOUT_ACTIVE) && (info->flags & DZ_PGRP_LOCKOUT) && (info->pgrp != current->pgrp)) return -EBUSY; - info->flags |= DZ_CALLOUT_ACTIVE; return 0; } - /* - * If non-blocking mode is set, or the port is not enabled, then make - * the check up front and then exit. + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { if (info->flags & DZ_CALLOUT_ACTIVE) return -EBUSY; info->flags |= DZ_NORMAL_ACTIVE; - return 0; } - if (info->flags & DZ_CALLOUT_ACTIVE) { if (info->normal_termios.c_cflag & CLOCAL) do_clocal = 1; } else { if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; + do_clocal = 1; } /* - * Block waiting for the carrier detect and the line to become free - * (i.e., not in use by the callout). While we are in this loop, - * info->count is dropped by one, so that dz_close() knows when to free - * things. We restore it upon exit, either normal or abnormal. + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * dz_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. */ retval = 0; add_wait_queue(&info->open_wait, &wait); @@ -1237,7 +1219,7 @@ info->blocked_open++; while (1) { set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p (filp) || !(info->is_initialized)) { + if (tty_hung_up_p(filp) || !(info->is_initialized)) { retval = -EAGAIN; break; } @@ -1250,9 +1232,9 @@ } schedule(); } - + current->state = TASK_RUNNING; - remove_wait_queue (&info->open_wait, &wait); + remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) info->count++; info->blocked_open--; @@ -1294,37 +1276,36 @@ /* * Start up serial port */ - retval = startup (info); + retval = startup(info); if (retval) return retval; - retval = block_til_ready (tty, filp, info); + retval = block_til_ready(tty, filp, info); if (retval) return retval; if ((info->count == 1) && (info->flags & DZ_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->normal_termios; - else + else *tty->termios = info->callout_termios; change_speed(info); - } + } info->session = current->session; info->pgrp = current->pgrp; - return 0; } -static void show_serial_version (void) +static void show_serial_version(void) { printk("%s%s\n", dz_name, dz_version); } - int __init dz_init(void) { - int i, flags; + int i, tmp; + long flags; struct dz_serial *info; /* Setup base handler, and timer table. */ @@ -1353,7 +1334,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &dz_sercons; +#endif serial_driver.open = dz_open; serial_driver.close = dz_close; serial_driver.write = dz_write; @@ -1371,8 +1354,8 @@ serial_driver.hangup = dz_hangup; /* - * The callout device is just like normal device except for major - * number and the subtype code. + * The callout device is just like normal device except for + * major number and the subtype code. */ callout_driver = serial_driver; #if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) @@ -1383,21 +1366,22 @@ callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; - if (tty_register_driver (&serial_driver)) - panic("Couldn't register serial driver\n"); - if (tty_register_driver (&callout_driver)) - panic("Couldn't register callout driver\n"); - - save_flags(flags); cli(); - for (i=0; i < DZ_NB_PORT; i++) { - info = &multi[i]; + if (tty_register_driver(&serial_driver)) + panic("Couldn't register serial driver"); + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver"); + save_flags(flags); + cli(); + + for (i = 0; i < DZ_NB_PORT; i++) { + info = &multi[i]; lines[i] = info; info->magic = SERIAL_MAGIC; - if ((mips_machtype == MACH_DS23100) || - (mips_machtype == MACH_DS5100)) + if (mips_machtype == MACH_DS23100 || + mips_machtype == MACH_DS5100) info->port = (unsigned long) KN01_DZ11_BASE; - else + else info->port = (unsigned long) KN02_DZ11_BASE; info->line = i; @@ -1414,76 +1398,71 @@ info->tqueue_hangup.data = info; info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); /* * If we are pointing to address zero then punt - not correctly * set up in setup.c to handle this. */ - if (! info->port) + if (!info->port) return 0; printk("ttyS%02d at 0x%08x (irq = %d)\n", info->line, info->port, SERIAL); tty_register_devfs(&serial_driver, 0, - serial_driver.minor_start + info->line); + serial_driver.minor_start + info->line); tty_register_devfs(&callout_driver, 0, - callout_driver.minor_start + info->line); + callout_driver.minor_start + info->line); } - /* Reset the chip */ + /* reset the chip */ #ifndef CONFIG_SERIAL_CONSOLE - { - int tmp; - dz_out(info, DZ_CSR, DZ_CLR); - while ((tmp = dz_in(info,DZ_CSR)) & DZ_CLR); - wbflush(); - - /* Enable scanning */ - dz_out(info, DZ_CSR, DZ_MSE); - } + dz_out(info, DZ_CSR, DZ_CLR); + while ((tmp = dz_in(info, DZ_CSR)) & DZ_CLR); + wbflush(); + + /* enable scanning */ + dz_out(info, DZ_CSR, DZ_MSE); #endif - - /* - * Order matters here... the trick is that flags is updated... in - * request_irq - to immediatedly obliterate it is unwise. - */ + + /* order matters here... the trick is that flags + is updated... in request_irq - to immediatedly obliterate + it is unwise. */ restore_flags(flags); + if (request_irq(SERIAL, dz_interrupt, SA_INTERRUPT, "DZ", lines[0])) - panic("Unable to register DZ interrupt\n"); - + panic("Unable to register DZ interrupt"); + return 0; } #ifdef CONFIG_SERIAL_CONSOLE -static void dz_console_put_char (unsigned char ch) +static void dz_console_put_char(unsigned char ch) { unsigned long flags; - int loops = 2500; + int loops = 2500; unsigned short tmp = ch; - /* - * this code sends stuff out to serial device - spinning its wheels and - * waiting. - */ + /* this code sends stuff out to serial device - spinning its + wheels and waiting. */ - /* force the issue - point it at lines[3]*/ + /* force the issue - point it at lines[3] */ dz_console = &multi[CONSOLE_LINE]; - save_and_cli(flags); + save_flags(flags); + cli(); + /* spin our wheels */ - while (((dz_in(dz_console, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--) - ; - + while (((dz_in(dz_console, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--); + /* Actually transmit the character. */ dz_out(dz_console, DZ_TDR, tmp); - restore_flags(flags); + restore_flags(flags); } - /* * ------------------------------------------------------------------- * dz_console_print () @@ -1492,12 +1471,12 @@ * The console must be locked when we get here. * ------------------------------------------------------------------- */ -static void dz_console_print (struct console *cons, - const char *str, - unsigned int count) +static void dz_console_print(struct console *cons, + const char *str, + unsigned int count) { #ifdef DEBUG_DZ - prom_printf((char *)str); + prom_printf((char *) str); #endif while (count--) { if (*str == '\n') @@ -1518,7 +1497,7 @@ int parity = 'n'; int cflag = CREAD | HUPCL | CLOCAL; char *s; - unsigned short mask,tmp; + unsigned short mask, tmp; if (options) { baud = simple_strtoul(options, NULL, 10); @@ -1528,11 +1507,10 @@ if (*s) parity = *s++; if (*s) - bits = *s - '0'; + bits = *s - '0'; } - /* - * Now construct a cflag setting. + * Now construct a cflag setting. */ switch (baud) { case 1200: @@ -1572,18 +1550,17 @@ /* TOFIX: force to console line */ dz_console = &multi[CONSOLE_LINE]; - if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) + if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) dz_console->port = KN01_DZ11_BASE; - else - dz_console->port = KN02_DZ11_BASE; + else + dz_console->port = KN02_DZ11_BASE; dz_console->line = CONSOLE_LINE; dz_out(dz_console, DZ_CSR, DZ_CLR); - while ((tmp = dz_in(dz_console,DZ_CSR)) & DZ_CLR) - ; + while ((tmp = dz_in(dz_console, DZ_CSR)) & DZ_CLR); /* enable scanning */ - dz_out(dz_console, DZ_CSR, DZ_MSE); + dz_out(dz_console, DZ_CSR, DZ_MSE); /* Set up flags... */ dz_console->cflags = 0; @@ -1593,16 +1570,16 @@ dz_out(dz_console, DZ_LPR, dz_console->cflags); mask = 1 << dz_console->line; - tmp = dz_in (dz_console, DZ_TCR); /* read the TX flag */ + tmp = dz_in(dz_console, DZ_TCR); /* read the TX flag */ if (!(tmp & mask)) { - tmp |= mask; /* set the TX flag */ - dz_out (dz_console, DZ_TCR, tmp); + tmp |= mask; /* set the TX flag */ + dz_out(dz_console, DZ_TCR, tmp); } - return 0; } -static struct console dz_sercons = { +static struct console dz_sercons = +{ name: "ttyS", write: dz_console_print, device: dz_console_device, @@ -1616,6 +1593,6 @@ register_console(&dz_sercons); } -#endif /* ifdef CONFIG_SERIAL_CONSOLE */ +#endif /* CONFIG_SERIAL_CONSOLE */ MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/dz.h linux-2.5/drivers/char/dz.h --- linux-2.5.5/drivers/char/dz.h Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/char/dz.h Sun Mar 3 17:54:35 2002 @@ -10,6 +10,8 @@ #ifndef DZ_SERIAL_H #define DZ_SERIAL_H +#define SERIAL_MAGIC 0x5301 + /* * Definitions for the Control and Status Received. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/efirtc.c linux-2.5/drivers/char/efirtc.c --- linux-2.5.5/drivers/char/efirtc.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/char/efirtc.c Sun Mar 3 17:54:35 2002 @@ -40,7 +40,7 @@ #include #include -#define EFI_RTC_VERSION "0.2" +#define EFI_RTC_VERSION "0.3" #define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT) /* @@ -315,56 +315,45 @@ spin_unlock_irqrestore(&efi_rtc_lock,flags); p += sprintf(p, - "Time :\n" - "Year : %u\n" - "Month : %u\n" - "Day : %u\n" - "Hour : %u\n" - "Minute : %u\n" - "Second : %u\n" - "Nanosecond: %u\n" - "Daylight : %u\n", - eft.year, eft.month, eft.day, eft.hour, eft.minute, - eft.second, eft.nanosecond, eft.daylight); + "Time : %u:%u:%u.%09u\n" + "Date : %u-%u-%u\n" + "Daylight : %u\n", + eft.hour, eft.minute, eft.second, eft.nanosecond, + eft.year, eft.month, eft.day, + eft.daylight); if ( eft.timezone == EFI_UNSPECIFIED_TIMEZONE) - p += sprintf(p, "Timezone : unspecified\n"); + p += sprintf(p, "Timezone : unspecified\n"); else /* XXX fixme: convert to string? */ - p += sprintf(p, "Timezone : %u\n", eft.timezone); + p += sprintf(p, "Timezone : %u\n", eft.timezone); p += sprintf(p, - "\nWakeup Alm:\n" - "Enabled : %s\n" - "Pending : %s\n" - "Year : %u\n" - "Month : %u\n" - "Day : %u\n" - "Hour : %u\n" - "Minute : %u\n" - "Second : %u\n" - "Nanosecond: %u\n" - "Daylight : %u\n", - enabled == 1 ? "Yes" : "No", - pending == 1 ? "Yes" : "No", - alm.year, alm.month, alm.day, alm.hour, alm.minute, - alm.second, alm.nanosecond, alm.daylight); + "Alarm Time : %u:%u:%u.%09u\n" + "Alarm Date : %u-%u-%u\n" + "Alarm Daylight : %u\n" + "Enabled : %s\n" + "Pending : %s\n", + alm.hour, alm.minute, alm.second, alm.nanosecond, + alm.year, alm.month, alm.day, + alm.daylight, + enabled == 1 ? "yes" : "no", + pending == 1 ? "yes" : "no"); if ( eft.timezone == EFI_UNSPECIFIED_TIMEZONE) - p += sprintf(p, "Timezone : unspecified\n"); + p += sprintf(p, "Timezone : unspecified\n"); else /* XXX fixme: convert to string? */ - p += sprintf(p, "Timezone : %u\n", eft.timezone); + p += sprintf(p, "Timezone : %u\n", alm.timezone); /* * now prints the capabilities */ p += sprintf(p, - "\nClock Cap :\n" - "Resolution: %u\n" - "Accuracy : %u\n" - "SetstoZero: %u\n", + "Resolution : %u\n" + "Accuracy : %u\n" + "SetstoZero : %u\n", cap.resolution, cap.accuracy, cap.sets_to_zero); return p - buf; @@ -390,7 +379,7 @@ misc_register(&efi_rtc_dev); - create_proc_read_entry ("efirtc", 0, NULL, efi_rtc_read_proc, NULL); + create_proc_read_entry ("driver/efirtc", 0, NULL, efi_rtc_read_proc, NULL); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/eurotechwdt.c linux-2.5/drivers/char/eurotechwdt.c --- linux-2.5.5/drivers/char/eurotechwdt.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/char/eurotechwdt.c Sun Jan 13 22:15:01 2002 @@ -20,6 +20,10 @@ * "AS-IS" and at no charge. * * (c) Copyright 1995 Alan Cox * + * + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default */ #include @@ -45,7 +49,6 @@ #include static int eurwdt_is_open; -static int eurwdt_timeout; static spinlock_t eurwdt_lock; /* @@ -58,6 +61,18 @@ static char *ev = "int"; #define WDT_TIMEOUT 60 /* 1 minute */ +static int timeout = WDT_TIMEOUT; + +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Eurotech WDT timeout in seconds (default=60)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); /* @@ -116,6 +131,15 @@ * Programming support */ +static void __init eurwdt_validate_timeout(void) +{ + if (timeout < 0 || timeout > 255) { + timeout = WDT_TIMEOUT; + printk(KERN_INFO "eurwdt: timeout must be 0 < x < 255, using %d\n", + timeout); + } +} + static inline void eurwdt_write_reg(u8 index, u8 data) { outb(index, io); @@ -189,7 +213,7 @@ static void eurwdt_ping(void) { /* Write the watchdog default value */ - eurwdt_set_timeout(eurwdt_timeout); + eurwdt_set_timeout(timeout); } /** @@ -263,7 +287,7 @@ if (time < 0 || time > 255) return -EINVAL; - eurwdt_timeout = time; + timeout = time; eurwdt_set_timeout(time); return 0; } @@ -287,9 +311,11 @@ spin_unlock(&eurwdt_lock); return -EBUSY; } + if (nowayout) { + MOD_INC_USE_COUNT; + } eurwdt_is_open = 1; - eurwdt_timeout = WDT_TIMEOUT; /* initial timeout */ /* Activate the WDT */ eurwdt_activate_timer(); @@ -323,12 +349,12 @@ static int eurwdt_release(struct inode *inode, struct file *file) { if (minor(inode->i_rdev) == WATCHDOG_MINOR) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - eurwdt_disable_timer(); -#endif - eurwdt_is_open = 0; + if (!nowayout) { + eurwdt_disable_timer(); + } + eurwdt_is_open = 0; - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; } return 0; @@ -422,7 +448,8 @@ static int __init eurwdt_init(void) { int ret; - + + eurwdt_validate_timeout(); ret = misc_register(&eurwdt_miscdev); if (ret) { printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/ftape/lowlevel/fdc-io.c linux-2.5/drivers/char/ftape/lowlevel/fdc-io.c --- linux-2.5.5/drivers/char/ftape/lowlevel/fdc-io.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/char/ftape/lowlevel/fdc-io.c Thu Feb 14 02:57:58 2002 @@ -926,7 +926,7 @@ disable_dma(fdc.dma); clear_dma_ff(fdc.dma); set_dma_mode(fdc.dma, mode); - set_dma_addr(fdc.dma, virt_to_bus((void*)addr)); + set_dma_addr(fdc.dma, isa_virt_to_bus((void*)addr)); set_dma_count(fdc.dma, count); enable_dma(fdc.dma); } @@ -945,7 +945,7 @@ /* Program the DMA controller. */ TRACE(ft_t_fdc_dma, - "phys. addr. = %lx", virt_to_bus((void*) buff->ptr)); + "phys. addr. = %lx", isa_virt_to_bus((void*) buff->ptr)); save_flags(flags); cli(); /* could be called from ISR ! */ fdc_setup_dma(DMA_MODE_WRITE, buff->ptr, FT_SECTORS_PER_SEGMENT * 4); @@ -997,7 +997,7 @@ TRACE_ABORT(-EIO, ft_t_bug, "bug: illegal operation parameter"); } - TRACE(ft_t_fdc_dma, "phys. addr. = %lx",virt_to_bus((void*)buff->ptr)); + TRACE(ft_t_fdc_dma, "phys. addr. = %lx", isa_virt_to_bus((void*)buff->ptr)); save_flags(flags); cli(); /* could be called from ISR ! */ if (operation != FDC_VERIFY) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/ftape/zftape/zftape-init.c linux-2.5/drivers/char/ftape/zftape/zftape-init.c --- linux-2.5.5/drivers/char/ftape/zftape/zftape-init.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/char/ftape/zftape/zftape-init.c Tue Feb 12 00:57:58 2002 @@ -28,6 +28,7 @@ #include #include #include +#include #include #ifdef CONFIG_KMOD #include @@ -203,6 +204,7 @@ static struct vm_operations_struct dummy = { NULL, }; vma->vm_ops = &dummy; #endif + vma->vm_flags &= ~VM_IO; } current->blocked = old_sigmask; /* restore mask */ TRACE_EXIT result; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/generic_serial.c linux-2.5/drivers/char/generic_serial.c --- linux-2.5.5/drivers/char/generic_serial.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/char/generic_serial.c Wed Jan 30 17:03:50 2002 @@ -219,8 +219,13 @@ while (1) { c = count; - /* This is safe because we "OWN" the "head". Noone else can - change the "head": we own the port_write_sem. */ + /* Note: This part can be done without + * interrupt routine protection since + * the interrupt routines may only modify + * shared variables in safe ways, in the worst + * case causing us to loop twice in the code + * below. See comments below. */ + /* Don't overrun the end of the buffer */ t = SERIAL_XMIT_SIZE - port->xmit_head; if (t < c) c = t; @@ -511,7 +516,7 @@ void gs_shutdown_port (struct gs_port *port) { - long flags; + unsigned long flags; func_enter(); @@ -594,6 +599,7 @@ int do_clocal = 0; int CD; struct tty_struct *tty; + unsigned long flags; func_enter (); @@ -673,10 +679,11 @@ add_wait_queue(&port->open_wait, &wait); gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); + save_flags(flags); cli(); if (!tty_hung_up_p(filp)) port->count--; - sti(); + restore_flags(flags); port->blocked_open++; while (1) { CD = port->rd->get_CD (port); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/i810-tco.c linux-2.5/drivers/char/i810-tco.c --- linux-2.5.5/drivers/char/i810-tco.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/char/i810-tco.c Sun Jan 13 22:15:01 2002 @@ -1,5 +1,5 @@ /* - * i810-tco 0.02: TCO timer driver for i810 chipsets + * i810-tco 0.03: TCO timer driver for i810 chipsets * * (c) Copyright 2000 kernel concepts , All Rights Reserved. * http://www.kernelconcepts.de @@ -28,6 +28,9 @@ * Initial Version 0.01 * 20000728 Nils Faerber * 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups + * 20011214 Matt Domsch + * 0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Didn't add timeout option as i810_margin already exists. */ #include @@ -60,6 +63,18 @@ static int i810_margin = TIMER_MARGIN; /* steps of 0.6sec */ MODULE_PARM (i810_margin, "i"); +MODULE_PARM_DESC(i810_margin, "Watchdog timeout in steps of 0.6sec, 2 * + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default + * */ #include @@ -92,15 +96,36 @@ #define WD_TIMO 0 /* 30 seconds +/- 20%, from table */ +static int timeout_val = WD_TIMO; /* value in table */ +static int timeout = 30; /* in seconds */ +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, 0 < n < 30, must be even (default=30)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + /* * Kernel methods. */ +static void __init +ibwdt_validate_timeout(void) +{ + timeout_val = (30 - timeout) / 2; + if (timeout_val < 0 || timeout_val > 0xF) timeout_val = WD_TIMO; +} + static void ibwdt_ping(void) { /* Write a watchdog value */ - outb_p(WD_TIMO, WDT_START); + outb_p(timeout_val, WDT_START); } static ssize_t @@ -162,6 +187,9 @@ spin_unlock(&ibwdt_lock); return -EBUSY; } + if (nowayout) { + MOD_INC_USE_COUNT; + } /* * Activate */ @@ -181,9 +209,9 @@ lock_kernel(); if (minor(inode->i_rdev) == WATCHDOG_MINOR) { spin_lock(&ibwdt_lock); -#ifndef CONFIG_WATCHDOG_NOWAYOUT - outb_p(WD_TIMO, WDT_STOP); -#endif + if (!nowayout) { + outb_p(timeout_val, WDT_STOP); + } ibwdt_is_open = 0; spin_unlock(&ibwdt_lock); } @@ -201,7 +229,7 @@ { if (code == SYS_DOWN || code == SYS_HALT) { /* Turn the WDT off */ - outb_p(WD_TIMO, WDT_STOP); + outb_p(timeout_val, WDT_STOP); } return NOTIFY_DONE; } @@ -241,6 +269,7 @@ { printk("WDT driver for IB700 single board computer initialising.\n"); + ibwdt_validate_timeout(); spin_lock_init(&ibwdt_lock); misc_register(&ibwdt_miscdev); #if WDT_START != WDT_STOP diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/indydog.c linux-2.5/drivers/char/indydog.c --- linux-2.5.5/drivers/char/indydog.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/indydog.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,158 @@ +/* + * IndyDog 0.2 A Hardware Watchdog Device for SGI IP22 + * + * (c) Copyright 2002 Guido Guenther , All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * based on softdog.c by Alan Cox + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int indydog_alive; +static struct sgimc_misc_ctrl *mcmisc_regs; + +static void indydog_ping() +{ + mcmisc_regs->watchdogt = 0; +} + + +/* + * Allow only one person to hold it open + */ + +static int indydog_open(struct inode *inode, struct file *file) +{ + u32 mc_ctrl0; + + if(indydog_alive) + return -EBUSY; +#ifdef CONFIG_WATCHDOG_NOWAYOUT + MOD_INC_USE_COUNT; +#endif + /* + * Activate timer + */ + mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000); + + mc_ctrl0 = mcmisc_regs->cpuctrl0 | SGIMC_CCTRL0_WDOG; + mcmisc_regs->cpuctrl0 = mc_ctrl0; + indydog_ping(); + + indydog_alive=1; + printk("Started watchdog timer.\n"); + return 0; +} + +static int indydog_release(struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + * Lock it in if it's a module and we defined ...NOWAYOUT + */ + lock_kernel(); +#ifndef CONFIG_WATCHDOG_NOWAYOUT + { + u32 mc_ctrl0 = mcmisc_regs->cpuctrl0; + mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG; + mcmisc_regs->cpuctrl0 = mc_ctrl0; + printk("Stopped watchdog timer.\n"); + } +#endif + indydog_alive=0; + unlock_kernel(); + return 0; +} + +static ssize_t indydog_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if(len) { + indydog_ping(); + return 1; + } + return 0; +} + +static int indydog_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info ident = { + identity: "Hardware Watchdog for SGI IP22", + }; + switch (cmd) { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) + return -EFAULT; + return 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0,(int *)arg); + case WDIOC_KEEPALIVE: + indydog_ping(); + return 0; + } +} + +static struct file_operations indydog_fops = { + owner: THIS_MODULE, + write: indydog_write, + ioctl: indydog_ioctl, + open: indydog_open, + release: indydog_release, +}; + +static struct miscdevice indydog_miscdev = { + minor: WATCHDOG_MINOR, + name: "watchdog", + fops: &indydog_fops, +}; + +static const char banner[] __initdata = KERN_INFO "Hardware Watchdog Timer for SGI IP22: 0.2\n"; + +static int __init watchdog_init(void) +{ + int ret; + + ret = misc_register(&indydog_miscdev); + + if (ret) + return ret; + + printk(banner); + + return 0; +} + +static void __exit watchdog_exit(void) +{ + misc_deregister(&indydog_miscdev); +} + +module_init(watchdog_init); +module_exit(watchdog_exit); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/ip2/i2cmd.c linux-2.5/drivers/char/ip2/i2cmd.c --- linux-2.5.5/drivers/char/ip2/i2cmd.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/char/ip2/i2cmd.c Thu Dec 13 16:32:35 2001 @@ -139,7 +139,7 @@ //static UCHAR ct86[]={ 2, BTH, 0x56,0 }; // RCV_ENABLE static UCHAR ct87[] = { 1, BYP, 0x57 }; // HW_TEST //static UCHAR ct88[]={ 3, BTH, 0x58,0,0 }; // RCV_THRESHOLD -static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW +//static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW //static UCHAR ct90[]={ 3, BYP, 0x5A,0,0 }; // Set SILO //static UCHAR ct91[]={ 2, BYP, 0x5B,0 }; // timed break diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/ip2/i2lib.c linux-2.5/drivers/char/ip2/i2lib.c --- linux-2.5.5/drivers/char/ip2/i2lib.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/char/ip2/i2lib.c Sun Mar 3 17:54:35 2002 @@ -1330,7 +1330,7 @@ // if expires == 0 then timer poped, then do not need to del_timer if ((timeout > 0) && pCh->BookmarkTimer.expires && - (pCh->BookmarkTimer.expires > jiffies)) { + time_before(jiffies, pCh->BookmarkTimer.expires)) { del_timer( &(pCh->BookmarkTimer) ); pCh->BookmarkTimer.expires = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/ip2.c linux-2.5/drivers/char/ip2.c --- linux-2.5.5/drivers/char/ip2.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/char/ip2.c Thu Dec 13 16:32:35 2001 @@ -33,9 +33,10 @@ */ static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 }; static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; -static int poll_only = 0; #ifdef MODULE + +static int poll_only = 0; # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) MODULE_AUTHOR("Doug McNash"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/keyboard.c linux-2.5/drivers/char/keyboard.c --- linux-2.5.5/drivers/char/keyboard.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/char/keyboard.c Sun Mar 3 23:50:41 2002 @@ -43,298 +43,129 @@ #include #include -#define SIZE(x) (sizeof(x)/sizeof((x)[0])) +extern void ctrl_alt_del(void); -#ifndef KBD_DEFMODE -#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) -#endif +#define SIZE(x) (sizeof(x)/sizeof((x)[0])) -#ifndef KBD_DEFLEDS /* - * Some laptops take the 789uiojklm,. keys as number pad when NumLock - * is on. This seems a good reason to start with NumLock off. + * Exported functions/variables */ -#define KBD_DEFLEDS 0 -#endif - -#ifndef KBD_DEFLOCK -#define KBD_DEFLOCK 0 -#endif void (*kbd_ledfunc)(unsigned int led); EXPORT_SYMBOL(handle_scancode); EXPORT_SYMBOL(kbd_ledfunc); - -extern void ctrl_alt_del(void); - -struct console; +/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ +struct pt_regs *kbd_pt_regs; +void compute_shiftstate(void); /* - * global state includes the following, and various static variables - * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next. - * (last_console is now a global variable) + * Handler Tables. */ -/* shift state counters.. */ -static unsigned char k_down[NR_SHIFT]; -/* keyboard key bitmap */ -static unsigned long key_down[256/BITS_PER_LONG]; - -static int dead_key_next; -/* - * In order to retrieve the shift_state (for the mouse server), either - * the variable must be global, or a new procedure must be created to - * return the value. I chose the former way. - */ -int shift_state; -static int npadch = -1; /* -1 or number assembled on pad */ -static unsigned char diacr; -static char rep; /* flag telling character repeat */ -struct kbd_struct kbd_table[MAX_NR_CONSOLES]; -static struct tty_struct **ttytab; -static struct kbd_struct * kbd = kbd_table; -static struct tty_struct * tty; - -void compute_shiftstate(void); - -typedef void (*k_hand)(unsigned char value, char up_flag); -typedef void (k_handfn)(unsigned char value, char up_flag); - -static k_handfn - do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, - do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, - do_ignore; - -static k_hand key_handler[16] = { - do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, - do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, - do_ignore, do_ignore -}; - /* Key types processed even in raw modes */ #define TYPES_ALLOWED_IN_RAW_MODE ((1 << KT_SPEC) | (1 << KT_SHIFT)) +#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK)) -typedef void (*void_fnp)(void); -typedef void (void_fn)(void); - -static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle, - num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose, - SAK, decr_console, incr_console, spawn_console, bare_num; - -static void_fnp spec_fn_table[] = { - do_null, enter, show_ptregs, show_mem, - show_state, send_intr, lastcons, caps_toggle, - num, hold, scroll_forw, scroll_back, - boot_it, caps_on, compose, SAK, - decr_console, incr_console, spawn_console, bare_num -}; +#define K_HANDLERS\ + k_self, k_fn, k_spec, k_pad,\ + k_dead, k_cons, k_cur, k_shift,\ + k_meta, k_ascii, k_lock, k_lowercase,\ + k_slock, k_dead2, k_ignore, k_ignore + +typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, + char up_flag); +static k_handler_fn K_HANDLERS; +static k_handler_fn *k_handler[16] = { K_HANDLERS }; + +#define FN_HANDLERS\ + fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ + fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ + fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ + fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ + fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num + +typedef void (fn_handler_fn)(struct vc_data *vc); +static fn_handler_fn FN_HANDLERS; +static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; -#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK)) +/* + * Variables/functions exported for vt_ioctl.c + */ /* maximum values each key_handler can handle */ const int max_vals[] = { - 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1, - NR_DEAD - 1, 255, 3, NR_SHIFT - 1, - 255, NR_ASCII - 1, NR_LOCK - 1, 255, - NR_LOCK - 1, 255 + 255, SIZE(func_table) - 1, SIZE(fn_handler) - 1, NR_PAD - 1, + NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, + 255, NR_LOCK - 1, 255 }; - const int NR_TYPES = SIZE(max_vals); -/* N.B. drivers/macintosh/mac_keyb.c needs to call put_queue */ -void put_queue(int); -static unsigned char handle_diacr(unsigned char); - -/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ -struct pt_regs * kbd_pt_regs; - -#ifdef CONFIG_MAGIC_SYSRQ -static int sysrq_pressed; -#endif - -static struct pm_dev *pm_kbd; - -/* - * Many other routines do put_queue, but I think either - * they produce ASCII, or they produce some user-assigned - * string, and in both cases we might assume that it is - * in utf-8 already. - */ -void to_utf8(ushort c) { - if (c < 0x80) - put_queue(c); /* 0******* */ - else if (c < 0x800) { - put_queue(0xc0 | (c >> 6)); /* 110***** 10****** */ - put_queue(0x80 | (c & 0x3f)); - } else { - put_queue(0xe0 | (c >> 12)); /* 1110**** 10****** 10****** */ - put_queue(0x80 | ((c >> 6) & 0x3f)); - put_queue(0x80 | (c & 0x3f)); - } - /* UTF-8 is defined for words of up to 31 bits, - but we need only 16 bits here */ -} +int spawnpid, spawnsig; /* * Translation of escaped scancodes to keycodes. * This is now user-settable (for machines were it makes sense). */ - -int setkeycode(unsigned int scancode, unsigned int keycode) -{ - return kbd_setkeycode(scancode, keycode); -} - int getkeycode(unsigned int scancode) { return kbd_getkeycode(scancode); } -void handle_scancode(unsigned char scancode, int down) +int setkeycode(unsigned int scancode, unsigned int keycode) { - unsigned char keycode; - char up_flag = down ? 0 : 0200; - char raw_mode; - - pm_access(pm_kbd); - add_keyboard_randomness(scancode | up_flag); - - tty = ttytab? ttytab[fg_console]: NULL; - if (tty && (!tty->driver_data)) { - /* - * We touch the tty structure via the ttytab array - * without knowing whether or not tty is open, which - * is inherently dangerous. We currently rely on that - * fact that console_open sets tty->driver_data when - * it opens it, and clears it when it closes it. - */ - tty = NULL; - } - kbd = kbd_table + fg_console; - if ((raw_mode = (kbd->kbdmode == VC_RAW))) { - put_queue(scancode | up_flag); - /* we do not return yet, because we want to maintain - the key_down array, so that we have the correct - values when finishing RAW mode or when changing VT's */ - } - - /* - * Convert scancode to keycode - */ - if (!kbd_translate(scancode, &keycode, raw_mode)) - goto out; - - /* - * At this point the variable `keycode' contains the keycode. - * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid). - * We keep track of the up/down status of the key, and - * return the keycode if in MEDIUMRAW mode. - */ - - if (up_flag) { - rep = 0; - if(!test_and_clear_bit(keycode, key_down)) - up_flag = kbd_unexpected_up(keycode); - } else - rep = test_and_set_bit(keycode, key_down); - -#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ - if (keycode == SYSRQ_KEY) { - sysrq_pressed = !up_flag; - goto out; - } else if (sysrq_pressed) { - if (!up_flag) { - handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty); - goto out; - } - } -#endif + return kbd_setkeycode(scancode, keycode); +} - if (kbd->kbdmode == VC_MEDIUMRAW) { - /* soon keycodes will require more than one byte */ - put_queue(keycode + up_flag); - raw_mode = 1; /* Most key classes will be ignored */ - } +/* + * Variables/function exported for vt.c + */ +int shift_state = 0; - /* - * Small change in philosophy: earlier we defined repetition by - * rep = keycode == prev_keycode; - * prev_keycode = keycode; - * but now by the fact that the depressed key was down already. - * Does this ever make a difference? Yes. - */ +/* + * Internal Data. + */ - /* - * Repeat a key only if the input buffers are empty or the - * characters get echoed locally. This makes key repeat usable - * with slow applications and under heavy loads. - */ - if (!rep || - (vc_kbd_mode(kbd,VC_REPEAT) && tty && - (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { - u_short keysym; - u_char type; +static unsigned long key_down[256/BITS_PER_LONG]; /* keyboard key bitmap */ +static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ +static int dead_key_next; +static int npadch = -1; /* -1 or number assembled on pad */ +static unsigned char diacr; +static char rep; /* flag telling character repeat */ +pm_callback pm_kbd_request_override = NULL; +typedef void (pm_kbd_func) (void); +static struct pm_dev *pm_kbd; - /* the XOR below used to be an OR */ - int shift_final = (shift_state | kbd->slockstate) ^ - kbd->lockstate; - ushort *key_map = key_maps[shift_final]; +static unsigned char ledstate = 0xff; /* undefined */ +static unsigned char ledioctl; - if (key_map != NULL) { - keysym = key_map[keycode]; - type = KTYP(keysym); +static struct ledptr { + unsigned int *addr; + unsigned int mask; + unsigned char valid:1; +} ledptrs[3]; - if (type >= 0xf0) { - type -= 0xf0; - if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type))) - goto out; - if (type == KT_LETTER) { - type = KT_LATIN; - if (vc_kbd_led(kbd, VC_CAPSLOCK)) { - key_map = key_maps[shift_final ^ (1<slockstate = 0; - } else { - /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ - if (!up_flag && !raw_mode) - to_utf8(keysym); - } - } else { - /* maybe beep? */ - /* we have at least to update shift_state */ -#if 1 /* how? two almost equivalent choices follow */ - compute_shiftstate(); - kbd->slockstate = 0; /* play it safe */ -#else - keysym = U(plain_map[keycode]); - type = KTYP(keysym); - if (type == KT_SHIFT) - (*key_handler[type])(keysym & 0xff, up_flag); +#ifdef CONFIG_MAGIC_SYSRQ +static int sysrq_pressed; #endif - } - } -out: - do_poke_blanked_console = 1; - schedule_console_callback(); -} - -void put_queue(int ch) +/* + * Helper Functions. + */ +static void put_queue(struct vc_data *vc, int ch) { + struct tty_struct *tty = vc->vc_tty; + if (tty) { tty_insert_flip_char(tty, ch, 0); con_schedule_flip(tty); } } -static void puts_queue(char *cp) +static void puts_queue(struct vc_data *vc, char *cp) { + struct tty_struct *tty = vc->vc_tty; + if (!tty) return; @@ -345,48 +176,172 @@ con_schedule_flip(tty); } -static void applkey(int key, char mode) +static void applkey(struct vc_data *vc, int key, char mode) { static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; buf[1] = (mode ? 'O' : '['); buf[2] = key; - puts_queue(buf); + puts_queue(vc, buf); +} + +/* + * A note on character conversion: + * + * A keymap maps keycodes to keysyms, which, at present, are 16-bit + * values. If a keysym is < 0xf000 then it specifies a 16-bit Unicode + * character to be queued. If a keysym is >= 0xf000, then 0xf000 is + * subtracted to give a pair of octets, extracted by KTYP and KVAL. + * The KTYP is used as an index into key_handler[] to give a function + * which handles the KVAL. The "normal" key_handler is k_self, which + * treats the KVAL as an 8-bit character to be queued. + * + * When a 16-bit Unicode character is queued it is converted to UTF-8 + * if the keyboard is in Unicode mode; otherwise it is converted to an + * 8-bit character using the current ACM (see consolemap.c). An 8-bit + * character is assumed to be in the character set defined by the + * current ACM, so it is queued unchanged if the keyboard is in 8-bit + * mode; otherwise it is converted using the inverse ACM. + * + * The handling of diacritics uses 8-bit characters, which are + * converted using the inverse ACM, when in Unicode mode. The strings + * bound to function keys are not converted, so they may already + * contain UTF-8. Codes entered using do_ascii() treated as 16-bit and + * converted to UTF-8 in Unicode mode; otherwise they are treated as + * 8-bit and queued unchanged. + * + * Since KTYP is not used in the case of Unicode keysyms, it is not + * possible to use KT_LETTER to implement CapsLock. Either use 8-bit + * keysyms with an appropriate ACM or use the work-around proposed in + * k_lock(). + */ + +/* + * Many other routines do put_queue, but I think either + * they produce ASCII, or they produce some user-assigned + * string, and in both cases we might assume that it is + * in utf-8 already. UTF-8 is defined for words of up to 31 bits, + * but we need only 16 bits here + */ +void to_utf8(struct vc_data *vc, ushort c) +{ + if (c < 0x80) + /* 0******* */ + put_queue(vc, c); + else if (c < 0x800) { + /* 110***** 10****** */ + put_queue(vc, 0xc0 | (c >> 6)); + put_queue(vc, 0x80 | (c & 0x3f)); + } else { + /* 1110**** 10****** 10****** */ + put_queue(vc, 0xe0 | (c >> 12)); + put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); + put_queue(vc, 0x80 | (c & 0x3f)); + } +} + +/* + * called after returning from RAW mode or when changing consoles - + * recompute shift_down[] and shift_state from key_down[] + * maybe called when keymap is undefined, so that shiftkey release is seen + */ +void compute_shiftstate(void) +{ + int i, j, k, sym, val; + + shift_state = 0; + memset(shift_down, 0, sizeof(shift_down)); + + for (i = 0; i < SIZE(key_down); i++) { + + if (!key_down[i]) + continue; + + k = i*BITS_PER_LONG; + + for (j = 0; j < BITS_PER_LONG; j++, k++) { + + if (!test_bit(k, key_down)) + continue; + + sym = U(plain_map[k]); + if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) + continue; + + val = KVAL(sym); + if (val == KVAL(K_CAPSSHIFT)) + val = KVAL(K_SHIFT); + + shift_down[val]++; + shift_state |= (1 << val); + } + } +} + +/* + * We have a combining character DIACR here, followed by the character CH. + * If the combination occurs in the table, return the corresponding value. + * Otherwise, if CH is a space or equals DIACR, return DIACR. + * Otherwise, conclude that DIACR was not combining after all, + * queue it and return CH. + */ +unsigned char handle_diacr(struct vc_data *vc, unsigned char ch) +{ + int d = diacr; + int i; + + diacr = 0; + + for (i = 0; i < accent_table_size; i++) { + if (accent_table[i].diacr == d && accent_table[i].base == ch) + return accent_table[i].result; + } + + if (ch == ' ' || ch == d) + return d; + + put_queue(vc, d); + return ch; } -static void enter(void) +/* + * Special function handlers + */ +static void fn_enter(struct vc_data *vc) { if (diacr) { - put_queue(diacr); + put_queue(vc, diacr); diacr = 0; } - put_queue(13); - if (vc_kbd_mode(kbd,VC_CRLF)) - put_queue(10); + put_queue(vc, 13); + if (get_kbd_mode(&vc->kbd_table, VC_CRLF)) + put_queue(vc, 10); } -static void caps_toggle(void) +static void fn_caps_toggle(struct vc_data *vc) { if (rep) return; - chg_vc_kbd_led(kbd, VC_CAPSLOCK); + chg_kbd_led(&vc->kbd_table, VC_CAPSLOCK); } -static void caps_on(void) +static void fn_caps_on(struct vc_data *vc) { if (rep) return; - set_vc_kbd_led(kbd, VC_CAPSLOCK); + set_kbd_led(&vc->kbd_table, VC_CAPSLOCK); } -static void show_ptregs(void) +static void fn_show_ptregs(struct vc_data *vc) { if (kbd_pt_regs) show_regs(kbd_pt_regs); } -static void hold(void) +static void fn_hold(struct vc_data *vc) { + struct tty_struct *tty = vc->vc_tty; + if (rep || !tty) return; @@ -401,12 +356,12 @@ stop_tty(tty); } -static void num(void) +static void fn_num(struct vc_data *vc) { - if (vc_kbd_mode(kbd,VC_APPLIC)) - applkey('P', 1); + if (get_kbd_mode(&vc->kbd_table, VC_APPLIC)) + applkey(vc, 'P', 1); else - bare_num(); + fn_bare_num(vc); } /* @@ -415,19 +370,19 @@ * Bind this to NumLock if you prefer that the NumLock key always * changes the NumLock flag. */ -static void bare_num(void) +static void fn_bare_num(struct vc_data *vc) { if (!rep) - chg_vc_kbd_led(kbd,VC_NUMLOCK); + chg_kbd_led(&vc->kbd_table, VC_NUMLOCK); } -static void lastcons(void) +static void fn_lastcons(struct vc_data *vc) { /* switch to the last used console, ChN */ - set_console(last_console); + set_console(vc->display_fg->last_console->vc_num); } -static void decr_console(void) +static void fn_dec_console(struct vc_data *vc) { int i; @@ -440,7 +395,7 @@ set_console(i); } -static void incr_console(void) +static void fn_inc_console(struct vc_data *vc) { int i; @@ -453,114 +408,114 @@ set_console(i); } -static void send_intr(void) +static void fn_send_intr(struct vc_data *vc) { + struct tty_struct *tty = vc->vc_tty; + if (!tty) return; tty_insert_flip_char(tty, 0, TTY_BREAK); con_schedule_flip(tty); } -static void scroll_forw(void) +static void fn_scroll_forw(struct vc_data *vc) +{ + scrollfront(vc, 0); +} + +static void fn_scroll_back(struct vc_data *vc) +{ + scrollback(vc, 0); +} + +static void fn_show_mem(struct vc_data *vc) { - scrollfront(0); + show_mem(); } -static void scroll_back(void) +static void fn_show_state(struct vc_data *vc) { - scrollback(0); + show_state(); } -static void boot_it(void) +static void fn_boot_it(struct vc_data *vc) { ctrl_alt_del(); } -static void compose(void) +static void fn_compose(struct vc_data *vc) { + /* ???? */ dead_key_next = 1; } -int spawnpid, spawnsig; - -static void spawn_console(void) +static void fn_spawn_con(struct vc_data *vc) { - if (spawnpid) - if(kill_proc(spawnpid, spawnsig, 1)) - spawnpid = 0; + if (spawnpid) + if (kill_proc(spawnpid, spawnsig, 1)) + spawnpid = 0; } -static void SAK(void) +static void fn_SAK(struct vc_data *vc) { + struct tty_struct *tty = vc->vc_tty; + /* * SAK should also work in all raw modes and reset * them properly. */ - - do_SAK(tty); - reset_vc(fg_console); + if (tty) + do_SAK(tty); + reset_vc(vc); #if 0 do_unblank_screen(); /* not in interrupt routine? */ #endif } -static void do_ignore(unsigned char value, char up_flag) +static void fn_null(struct vc_data *vc) { + compute_shiftstate(); } -static void do_null() +/* + * Special key handlers + */ +static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag) { - compute_shiftstate(); } -static void do_spec(unsigned char value, char up_flag) +static void k_spec(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; - if (value >= SIZE(spec_fn_table)) + if (value >= SIZE(fn_handler)) return; - if ((kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) && - !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value))) + if ((vc->kbd_table.kbdmode == VC_RAW || + vc->kbd_table.kbdmode == VC_MEDIUMRAW) && + !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value))) return; - spec_fn_table[value](); + fn_handler[value](vc); } -static void do_lowercase(unsigned char value, char up_flag) +static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag) { - printk(KERN_ERR "keyboard.c: do_lowercase was called - impossible\n"); + printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n"); } -static void do_self(unsigned char value, char up_flag) +static void k_self(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; /* no action, if this is a key release */ if (diacr) - value = handle_diacr(value); + value = handle_diacr(vc, value); if (dead_key_next) { dead_key_next = 0; diacr = value; return; } - - put_queue(value); -} - -#define A_GRAVE '`' -#define A_ACUTE '\'' -#define A_CFLEX '^' -#define A_TILDE '~' -#define A_DIAER '"' -#define A_CEDIL ',' -static unsigned char ret_diacr[NR_DEAD] = - {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL }; - -/* Obsolete - for backwards compatibility only */ -static void do_dead(unsigned char value, char up_flag) -{ - value = ret_diacr[value]; - do_dead2(value,up_flag); + put_queue(vc, value); } /* @@ -568,60 +523,51 @@ * dead keys modifying the same character. Very useful * for Vietnamese. */ -static void do_dead2(unsigned char value, char up_flag) +static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; - - diacr = (diacr ? handle_diacr(value) : value); + diacr = (diacr ? handle_diacr(vc, value) : value); } - /* - * We have a combining character DIACR here, followed by the character CH. - * If the combination occurs in the table, return the corresponding value. - * Otherwise, if CH is a space or equals DIACR, return DIACR. - * Otherwise, conclude that DIACR was not combining after all, - * queue it and return CH. + * Obsolete - for backwards compatibility only */ -unsigned char handle_diacr(unsigned char ch) +static void k_dead(struct vc_data *vc, unsigned char value, char up_flag) { - int d = diacr; - int i; - - diacr = 0; - - for (i = 0; i < accent_table_size; i++) { - if (accent_table[i].diacr == d && accent_table[i].base == ch) - return accent_table[i].result; - } - - if (ch == ' ' || ch == d) - return d; - - put_queue(d); - return ch; + static unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; + value = ret_diacr[value]; + k_dead2(vc, value, up_flag); } -static void do_cons(unsigned char value, char up_flag) +static void k_cons(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; set_console(value); } -static void do_fn(unsigned char value, char up_flag) +static void k_fn(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag) return; if (value < SIZE(func_table)) { if (func_table[value]) - puts_queue(func_table[value]); + puts_queue(vc, func_table[value]); } else - printk(KERN_ERR "do_fn called with value=%d\n", value); + printk(KERN_ERR "k_fn called with value=%d\n", value); } -static void do_pad(unsigned char value, char up_flag) +static void k_cur(struct vc_data *vc, unsigned char value, char up_flag) +{ + static const char *cur_chars = "BDCA"; + + if (up_flag) + return; + applkey(vc, cur_chars[value], get_kbd_mode(&vc->kbd_table, VC_CKMODE)); +} + +static void k_pad(struct vc_data *vc, unsigned char value, char up_flag) { static const char *pad_chars = "0123456789+-*/\015,.?()"; static const char *app_map = "pqrstuvwxylSRQMnnmPQ"; @@ -630,178 +576,162 @@ return; /* no action, if this is a key release */ /* kludge... shift forces cursor/number keys */ - if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) { - applkey(app_map[value], 1); + if (get_kbd_mode(&vc->kbd_table, VC_APPLIC) && !shift_down[KG_SHIFT]) { + applkey(vc, app_map[value], 1); return; } - if (!vc_kbd_led(kbd,VC_NUMLOCK)) + if (!get_kbd_led(&vc->kbd_table, VC_NUMLOCK)) switch (value) { case KVAL(K_PCOMMA): case KVAL(K_PDOT): - do_fn(KVAL(K_REMOVE), 0); + k_fn(vc, KVAL(K_REMOVE), 0); return; case KVAL(K_P0): - do_fn(KVAL(K_INSERT), 0); + k_fn(vc, KVAL(K_INSERT), 0); return; case KVAL(K_P1): - do_fn(KVAL(K_SELECT), 0); + k_fn(vc, KVAL(K_SELECT), 0); return; case KVAL(K_P2): - do_cur(KVAL(K_DOWN), 0); + k_cur(vc, KVAL(K_DOWN), 0); return; case KVAL(K_P3): - do_fn(KVAL(K_PGDN), 0); + k_fn(vc, KVAL(K_PGDN), 0); return; case KVAL(K_P4): - do_cur(KVAL(K_LEFT), 0); + k_cur(vc, KVAL(K_LEFT), 0); return; case KVAL(K_P6): - do_cur(KVAL(K_RIGHT), 0); + k_cur(vc, KVAL(K_RIGHT), 0); return; case KVAL(K_P7): - do_fn(KVAL(K_FIND), 0); + k_fn(vc, KVAL(K_FIND), 0); return; case KVAL(K_P8): - do_cur(KVAL(K_UP), 0); + k_cur(vc, KVAL(K_UP), 0); return; case KVAL(K_P9): - do_fn(KVAL(K_PGUP), 0); + k_fn(vc, KVAL(K_PGUP), 0); return; case KVAL(K_P5): - applkey('G', vc_kbd_mode(kbd, VC_APPLIC)); + applkey(vc, 'G', get_kbd_mode(&vc->kbd_table, + VC_APPLIC)); return; } - put_queue(pad_chars[value]); - if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) - put_queue(10); + put_queue(vc, pad_chars[value]); + if (value == KVAL(K_PENTER) && get_kbd_mode(&vc->kbd_table, VC_CRLF)) + put_queue(vc, 10); } -static void do_cur(unsigned char value, char up_flag) -{ - static const char *cur_chars = "BDCA"; - if (up_flag) - return; - - applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE)); -} - -static void do_shift(unsigned char value, char up_flag) +static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) { int old_state = shift_state; if (rep) return; - - /* Mimic typewriter: - a CapsShift key acts like Shift but undoes CapsLock */ + /* + * Mimic typewriter: + * a CapsShift key acts like Shift but undoes CapsLock + */ if (value == KVAL(K_CAPSSHIFT)) { value = KVAL(K_SHIFT); if (!up_flag) - clr_vc_kbd_led(kbd, VC_CAPSLOCK); + clr_kbd_led(&vc->kbd_table, VC_CAPSLOCK); } if (up_flag) { - /* handle the case that two shift or control - keys are depressed simultaneously */ - if (k_down[value]) - k_down[value]--; + /* + * handle the case that two shift or control + * keys are depressed simultaneously + */ + if (shift_down[value]) + shift_down[value]--; } else - k_down[value]++; + shift_down[value]++; - if (k_down[value]) + if (shift_down[value]) shift_state |= (1 << value); else - shift_state &= ~ (1 << value); + shift_state &= ~(1 << value); /* kludge */ if (up_flag && shift_state != old_state && npadch != -1) { - if (kbd->kbdmode == VC_UNICODE) - to_utf8(npadch & 0xffff); + if (vc->kbd_table.kbdmode == VC_UNICODE) + to_utf8(vc, npadch & 0xffff); else - put_queue(npadch & 0xff); + put_queue(vc, npadch & 0xff); npadch = -1; } } -/* called after returning from RAW mode or when changing consoles - - recompute k_down[] and shift_state from key_down[] */ -/* maybe called when keymap is undefined, so that shiftkey release is seen */ -void compute_shiftstate(void) -{ - int i, j, k, sym, val; - - shift_state = 0; - for(i=0; i < SIZE(k_down); i++) - k_down[i] = 0; - - for(i=0; i < SIZE(key_down); i++) - if(key_down[i]) { /* skip this word if not a single bit on */ - k = i*BITS_PER_LONG; - for(j=0; jkbd_table, VC_META)) { + put_queue(vc, '\033'); + put_queue(vc, value); } else - put_queue(value | 0x80); + put_queue(vc, value | 0x80); } -static void do_ascii(unsigned char value, char up_flag) +static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) { int base; if (up_flag) return; - if (value < 10) /* decimal input of code, while Alt depressed */ - base = 10; - else { /* hexadecimal input of code, while AltGr depressed */ - value -= 10; - base = 16; + if (value < 10) { + /* decimal input of code, while Alt depressed */ + base = 10; + } else { + /* hexadecimal input of code, while AltGr depressed */ + value -= 10; + base = 16; } if (npadch == -1) - npadch = value; + npadch = value; else - npadch = npadch * base + value; + npadch = npadch * base + value; } -static void do_lock(unsigned char value, char up_flag) +static void k_lock(struct vc_data *vc, unsigned char value, char up_flag) { if (up_flag || rep) return; - chg_vc_kbd_lock(kbd, value); + if (value >= NR_LOCK) { + /* + * Change the lock state and + * set the CapsLock LED to the new state + */ + unsigned char mask; + + mask = 1 << (value -= NR_LOCK); + if ((vc->kbd_table.lockstate ^= mask) & mask) + set_kbd_led(&vc->kbd_table, VC_CAPSLOCK); + else + clr_kbd_led(&vc->kbd_table, VC_CAPSLOCK); + } else { + /* Just change the lock state */ + chg_kbd_lock(&vc->kbd_table, value); + } } -static void do_slock(unsigned char value, char up_flag) +static void k_slock(struct vc_data *vc, unsigned char value, char up_flag) { - do_shift(value,up_flag); + k_shift(vc, value, up_flag); if (up_flag || rep) return; - chg_vc_kbd_slock(kbd, value); + chg_kbd_slock(&vc->kbd_table, value); /* try to make Alt, oops, AltGr and such work */ - if (!key_maps[kbd->lockstate ^ kbd->slockstate]) { - kbd->slockstate = 0; - chg_vc_kbd_slock(kbd, value); + if (!key_maps[vc->kbd_table.lockstate ^ vc->kbd_table.slockstate]) { + vc->kbd_table.slockstate = 0; + chg_kbd_slock(&vc->kbd_table, value); } } @@ -810,69 +740,58 @@ * or (ii) whatever pattern of lights people want to show using KDSETLED, * or (iii) specified bits of specified words in kernel memory. */ +unsigned char getledstate(void) +{ + return ledstate; +} -static unsigned char ledstate = 0xff; /* undefined */ -static unsigned char ledioctl; - -unsigned char getledstate(void) { - return ledstate; +void setledstate(struct kbd_struct *kbd, unsigned int led) +{ + if (!(led & ~7)) { + ledioctl = led; + kbd->ledmode = LED_SHOW_IOCTL; + } else + kbd->ledmode = LED_SHOW_FLAGS; + set_leds(); } -void setledstate(struct kbd_struct *kbd, unsigned int led) { - if (!(led & ~7)) { - ledioctl = led; - kbd->ledmode = LED_SHOW_IOCTL; - } else - kbd->ledmode = LED_SHOW_FLAGS; - set_leds(); +void register_leds(struct kbd_struct *kbd, unsigned int led, + unsigned int *addr, unsigned int mask) +{ + if (led < 3) { + ledptrs[led].addr = addr; + ledptrs[led].mask = mask; + ledptrs[led].valid = 1; + kbd->ledmode = LED_SHOW_MEM; + } else + kbd->ledmode = LED_SHOW_FLAGS; } -static struct ledptr { - unsigned int *addr; - unsigned int mask; - unsigned char valid:1; -} ledptrs[3]; +static inline unsigned char getleds(struct vt_struct *vt) +{ + struct vc_data *vc = vt->vc_cons[fg_console]; + struct kbd_struct *kbd = NULL; + unsigned char leds; + int i; + + if (vc) + kbd = &vc->kbd_table; -void register_leds(int console, unsigned int led, - unsigned int *addr, unsigned int mask) { - struct kbd_struct *kbd = kbd_table + console; - if (led < 3) { - ledptrs[led].addr = addr; - ledptrs[led].mask = mask; - ledptrs[led].valid = 1; - kbd->ledmode = LED_SHOW_MEM; - } else - kbd->ledmode = LED_SHOW_FLAGS; -} - -static inline unsigned char getleds(void){ - struct kbd_struct *kbd = kbd_table + fg_console; - unsigned char leds; - - if (kbd->ledmode == LED_SHOW_IOCTL) - return ledioctl; - leds = kbd->ledflagstate; - if (kbd->ledmode == LED_SHOW_MEM) { - if (ledptrs[0].valid) { - if (*ledptrs[0].addr & ledptrs[0].mask) - leds |= 1; - else - leds &= ~1; - } - if (ledptrs[1].valid) { - if (*ledptrs[1].addr & ledptrs[1].mask) - leds |= 2; - else - leds &= ~2; - } - if (ledptrs[2].valid) { - if (*ledptrs[2].addr & ledptrs[2].mask) - leds |= 4; - else - leds &= ~4; + if (kbd->ledmode == LED_SHOW_IOCTL) + return ledioctl; + + leds = kbd->ledflagstate; + + if (kbd->ledmode == LED_SHOW_MEM) { + for (i = 0; i < 3; i++) + if (ledptrs[i].valid) { + if (*ledptrs[i].addr & ledptrs[i].mask) + leds |= (1 << i); + else + leds &= ~(1 << i); + } } - } - return leds; + return leds; } /* @@ -888,9 +807,10 @@ * used, but this allows for easy and efficient race-condition * prevention later on. */ + static void kbd_bh(unsigned long dummy) { - unsigned char leds = getleds(); + unsigned char leds = getleds(vt_cons); if (leds != ledstate) { ledstate = leds; @@ -902,28 +822,144 @@ EXPORT_SYMBOL(keyboard_tasklet); DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); -typedef void (pm_kbd_func) (void); +void handle_scancode(unsigned char scancode, int down) +{ + struct vc_data *vc = vt_cons->vc_cons[fg_console]; + char up_flag = down ? 0 : 0200; + struct tty_struct *tty; + unsigned char keycode; + char raw_mode; -pm_callback pm_kbd_request_override = NULL; + pm_access(pm_kbd); + add_keyboard_randomness(scancode | up_flag); -int __init kbd_init(void) -{ - int i; - struct kbd_struct kbd0; - extern struct tty_driver console_driver; + tty = vc->vc_tty; - kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; - kbd0.ledmode = LED_SHOW_FLAGS; - kbd0.lockstate = KBD_DEFLOCK; - kbd0.slockstate = 0; - kbd0.modeflags = KBD_DEFMODE; - kbd0.kbdmode = VC_XLATE; - - for (i = 0 ; i < MAX_NR_CONSOLES ; i++) - kbd_table[i] = kbd0; + if (tty && (!tty->driver_data)) { + /* + * We touch the tty structure via the ttytab array + * without knowing whether or not tty is open, which + * is inherently dangerous. We currently rely on that + * fact that console_open sets tty->driver_data when + * it opens it, and clears it when it closes it. + */ + tty = NULL; + } + + if ((raw_mode = (vc->kbd_table.kbdmode == VC_RAW))) { + put_queue(vc, scancode | up_flag); + /* we do not return yet, because we want to maintain + the key_down array, so that we have the correct + values when finishing RAW mode or when changing VT's */ + } + + /* + * Convert scancode to keycode + */ + if (!kbd_translate(scancode, &keycode, raw_mode)) + goto out; + + /* + * At this point the variable `keycode' contains the keycode. + * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid). + * We keep track of the up/down status of the key, and + * return the keycode if in MEDIUMRAW mode. + */ + + if (up_flag) { + rep = 0; + if(!test_and_clear_bit(keycode, key_down)) + up_flag = kbd_unexpected_up(keycode); + } else + rep = test_and_set_bit(keycode, key_down); + +#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ + if (keycode == SYSRQ_KEY) { + sysrq_pressed = !up_flag; + goto out; + } else if (sysrq_pressed) { + if (!up_flag) { + handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, tty); + goto out; + } + } +#endif + + if (vc->kbd_table.kbdmode == VC_MEDIUMRAW) { + /* soon keycodes will require more than one byte */ + put_queue(vc, keycode + up_flag); + raw_mode = 1; /* Most key classes will be ignored */ + } + + /* + * Small change in philosophy: earlier we defined repetition by + * rep = keycode == prev_keycode; + * prev_keycode = keycode; + * but now by the fact that the depressed key was down already. + * Does this ever make a difference? Yes. + */ - ttytab = console_driver.table; + /* + * Repeat a key only if the input buffers are empty or the + * characters get echoed locally. This makes key repeat usable + * with slow applications and under heavy loads. + */ + if (!rep || + (get_kbd_mode(&vc->kbd_table, VC_REPEAT) && tty && + (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { + u_short keysym; + u_char type; + + /* the XOR below used to be an OR */ + int shift_final = (shift_state | vc->kbd_table.slockstate) ^ + vc->kbd_table.lockstate; + ushort *key_map = key_maps[shift_final]; + + if (key_map != NULL) { + keysym = key_map[keycode]; + type = KTYP(keysym); + if (type >= 0xf0) { + type -= 0xf0; + if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type))) + goto out; + if (type == KT_LETTER) { + type = KT_LATIN; + if (get_kbd_led(&vc->kbd_table, VC_CAPSLOCK)) { + key_map = key_maps[shift_final ^ (1<kbd_table.slockstate = 0; + } else { + /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ + if (!up_flag && !raw_mode) + to_utf8(vc, keysym); + } + } else { + /* maybe beep? */ + /* we have at least to update shift_state */ +#if 1 /* how? two almost equivalent choices follow */ + compute_shiftstate(); + vc->kbd_table.slockstate = 0; /* play it safe */ +#else + keysym = U(plain_map[keycode]); + type = KTYP(keysym); + if (type == KT_SHIFT) + (*key_handler[type])(keysym & 0xff, up_flag); +#endif + } + } +out: + do_poke_blanked_console = 1; + schedule_task(&vc->display_fg->vt_tq); +} + +int __init kbd_init(void) +{ kbd_init_hw(); tasklet_enable(&keyboard_tasklet); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/lcd.c linux-2.5/drivers/char/lcd.c --- linux-2.5.5/drivers/char/lcd.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/lcd.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,632 @@ +/* + * LCD, LED and Button interface for Cobalt + * + * 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. + * + * Copyright (C) 1996, 1997 by Andrew Bose + * + * Linux kernel version history: + * March 2001: Ported from 2.0.34 by Liam Davies + * + */ + +#define RTC_IO_EXTENT 0x10 /*Only really two ports, but... */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "lcd.h" + +static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg); + +static int lcd_present = 1; + +int led_state = 0; + +#if defined(CONFIG_TULIP) && 0 + +#define MAX_INTERFACES 8 +static linkcheck_func_t linkcheck_callbacks[MAX_INTERFACES]; +static void *linkcheck_cookies[MAX_INTERFACES]; + +int lcd_register_linkcheck_func(int iface_num, void *func, void *cookie) +{ + if (iface_num < 0 || + iface_num >= MAX_INTERFACES || + linkcheck_callbacks[iface_num] != NULL) + return -1; + linkcheck_callbacks[iface_num] = (linkcheck_func_t) func; + linkcheck_cookies[iface_num] = cookie; + return 0; +} +#endif + +static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct lcd_display button_display; + unsigned long address, a; + int index; + + switch (cmd) { + case LCD_On: + udelay(150); + BusyCheck(); + LCDWriteInst(0x0F); + break; + + case LCD_Off: + udelay(150); + BusyCheck(); + LCDWriteInst(0x08); + break; + + case LCD_Reset: + udelay(150); + LCDWriteInst(0x3F); + udelay(150); + LCDWriteInst(0x3F); + udelay(150); + LCDWriteInst(0x3F); + udelay(150); + LCDWriteInst(0x3F); + udelay(150); + LCDWriteInst(0x01); + udelay(150); + LCDWriteInst(0x06); + break; + + case LCD_Clear: + udelay(150); + BusyCheck(); + LCDWriteInst(0x01); + break; + + case LCD_Cursor_Left: + udelay(150); + BusyCheck(); + LCDWriteInst(0x10); + break; + + case LCD_Cursor_Right: + udelay(150); + BusyCheck(); + LCDWriteInst(0x14); + break; + + case LCD_Cursor_Off: + udelay(150); + BusyCheck(); + LCDWriteInst(0x0C); + break; + + case LCD_Cursor_On: + udelay(150); + BusyCheck(); + LCDWriteInst(0x0F); + break; + + case LCD_Blink_Off: + udelay(150); + BusyCheck(); + LCDWriteInst(0x0E); + break; + + case LCD_Get_Cursor_Pos:{ + struct lcd_display display; + + udelay(150); + BusyCheck(); + display.cursor_address = ( LCDReadInst ); + display.cursor_address = ( display.cursor_address & 0x07F ); + if(copy_to_user((struct lcd_display*)arg, &display, sizeof(struct lcd_display))) + return -EFAULT; + + break; + } + + + case LCD_Set_Cursor_Pos: { + struct lcd_display display; + + if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display))) + return -EFAULT; + + a = (display.cursor_address | kLCD_Addr ); + + udelay(150); + BusyCheck(); + LCDWriteInst( a ); + + break; + } + + case LCD_Get_Cursor: { + struct lcd_display display; + + udelay(150); + BusyCheck(); + display.character = LCDReadData; + + if(copy_to_user((struct lcd_display*)arg, &display, sizeof(struct lcd_display))) + return -EFAULT; + udelay(150); + BusyCheck(); + LCDWriteInst(0x10); + + break; + } + + case LCD_Set_Cursor:{ + struct lcd_display display; + + if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display))) + return -EFAULT; + + udelay(150); + BusyCheck(); + LCDWriteData( display.character ); + udelay(150); + BusyCheck(); + LCDWriteInst(0x10); + + break; + } + + + case LCD_Disp_Left: + udelay(150); + BusyCheck(); + LCDWriteInst(0x18); + break; + + case LCD_Disp_Right: + udelay(150); + BusyCheck(); + LCDWriteInst(0x1C); + break; + + case LCD_Home: + udelay(150); + BusyCheck(); + LCDWriteInst(0x02); + break; + + case LCD_Write: { + struct lcd_display display; + + + if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display))) + return -EFAULT; + + udelay(150); + BusyCheck(); + LCDWriteInst(0x80); + udelay(150); + BusyCheck(); + + for (index = 0; index < (display.size1); index++) { + udelay(150); + BusyCheck(); + LCDWriteData( display.line1[index]); + BusyCheck(); + } + + udelay(150); + BusyCheck(); + LCDWriteInst(0xC0); + udelay(150); + BusyCheck(); + for (index = 0; index < (display.size2); index++) { + udelay(150); + BusyCheck(); + LCDWriteData( display.line2[index]); + } + + break; + } + + case LCD_Read: { + struct lcd_display display; + + BusyCheck(); + for (address = kDD_R00; address <= kDD_R01; address++) { + a = (address | kLCD_Addr ); + + udelay(150); + BusyCheck(); + LCDWriteInst( a ); + udelay(150); + BusyCheck(); + display.line1[address] = LCDReadData; + } + + display.line1[ 0x27 ] = '\0'; + + for (address = kDD_R10; address <= kDD_R11; address++) { + a = (address | kLCD_Addr ); + + udelay(150); + BusyCheck(); + LCDWriteInst( a ); + + udelay(150); + BusyCheck(); + display.line2[address - 0x40 ] = LCDReadData; + } + + display.line2[ 0x27 ] = '\0'; + + if(copy_to_user((struct lcd_display*)arg, &display, + sizeof(struct lcd_display))) + return -EFAULT; + break; + } + +// set all GPIO leds to led_display.leds + + case LED_Set: { + struct lcd_display led_display; + + + if(copy_from_user(&led_display, (struct lcd_display*)arg, + sizeof(struct lcd_display))) + return -EFAULT; + + led_state = led_display.leds; + LEDSet(led_state); + + break; + } + + +// set only bit led_display.leds + + case LED_Bit_Set: { + int i; + int bit=1; + struct lcd_display led_display; + + + if(copy_from_user(&led_display, (struct lcd_display*)arg, + sizeof(struct lcd_display))) + return -EFAULT; + + for (i=0;i<(int)led_display.leds;i++) + { + bit = 2*bit; + } + + led_state = led_state | bit; + LEDSet(led_state); + break; + } + +// clear only bit led_display.leds + + case LED_Bit_Clear: { + int i; + int bit=1; + struct lcd_display led_display; + + + if(copy_from_user(&led_display, (struct lcd_display*)arg, + sizeof(struct lcd_display))) + return -EFAULT; + + for (i=0;i<(int)led_display.leds;i++) + { + bit = 2*bit; + } + + led_state = led_state & ~bit; + LEDSet(led_state); + break; + } + + + case BUTTON_Read: { + button_display.buttons = GPIRead; + if(copy_to_user((struct lcd_display*)arg, &button_display, sizeof(struct lcd_display))) + return -EFAULT; + break; + } + + case LINK_Check: { + button_display.buttons = *((volatile unsigned long *) (0xB0100060) ); + if(copy_to_user((struct lcd_display*)arg, &button_display, sizeof(struct lcd_display))) + return -EFAULT; + break; + } + + case LINK_Check_2: { + int iface_num; + + /* panel-utils should pass in the desired interface status is wanted for + * in "buttons" of the structure. We will set this to non-zero if the + * link is in fact up for the requested interface. --DaveM + */ + if(copy_from_user(&button_display, (struct lcd_display *)arg, sizeof(button_display))) + return -EFAULT; + iface_num = button_display.buttons; +#if defined(CONFIG_TULIP) && 0 + if (iface_num >= 0 && + iface_num < MAX_INTERFACES && + linkcheck_callbacks[iface_num] != NULL) { + button_display.buttons = + linkcheck_callbacks[iface_num](linkcheck_cookies[iface_num]); + } else +#endif + button_display.buttons = 0; + + if(__copy_to_user((struct lcd_display*)arg, &button_display, sizeof(struct lcd_display))) + return -EFAULT; + break; + } + +// Erase the flash + + case FLASH_Erase: { + + int ctr=0; + + // Chip Erase Sequence + WRITE_FLASH( kFlash_Addr1, kFlash_Data1 ); + WRITE_FLASH( kFlash_Addr2, kFlash_Data2 ); + WRITE_FLASH( kFlash_Addr1, kFlash_Erase3 ); + WRITE_FLASH( kFlash_Addr1, kFlash_Data1 ); + WRITE_FLASH( kFlash_Addr2, kFlash_Data2 ); + WRITE_FLASH( kFlash_Addr1, kFlash_Erase6 ); + + printk( "Erasing Flash.\n"); + + while ( (!dqpoll(0x00000000,0xFF)) && (!timeout(0x00000000)) ) { + ctr++; + } + + printk("\n"); + printk("\n"); + printk("\n"); + + if (READ_FLASH(0x07FFF0)==0xFF) { printk("Erase Successful\r\n"); } + else if (timeout) { printk("Erase Timed Out\r\n"); } + + break; + } + +// burn the flash + + case FLASH_Burn: { + + volatile unsigned long burn_addr; + unsigned long flags; + int i; + unsigned char *rom; + + + struct lcd_display display; + + if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display))) + return -EFAULT; + rom = (unsigned char *) kmalloc((128),GFP_ATOMIC); + if ( rom == NULL ) { + printk ("broken\n"); + return 1; + } + + printk("Churning and Burning -"); + save_flags(flags); + for (i=0; iRomImage[0]); + + if(!access_ok(VERIFY_WRITE, user_bytes, FLASH_SIZE)) + return -EFAULT; + + printk("Reading Flash"); + for (i=0; i 0) + return -EINVAL; + + lcd_waiters++; + while(((buttons_now = (long)button_pressed()) == 0) && + !(signal_pending(current))) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(2 * HZ); + } + lcd_waiters--; + + if(signal_pending(current)) + return -ERESTARTSYS; + return buttons_now; +} + +/* + * The various file operations we support. + */ + +static struct file_operations lcd_fops = { + read: lcd_read, + ioctl: lcd_ioctl, + open: lcd_open, +}; + +static struct miscdevice lcd_dev= +{ + LCD_MINOR, + "lcd", + &lcd_fops +}; + +int lcd_init(void) +{ +unsigned long data; + + printk("%s\n", LCD_DRIVER); + misc_register(&lcd_dev); + + /* Check region? Naaah! Just snarf it up. */ +/* request_region(RTC_PORT(0), RTC_IO_EXTENT, "lcd");*/ + + udelay(150); + data = LCDReadData; + if ( (data & 0x000000FF) == (0x00) ) { + lcd_present = 0; + printk("LCD Not Present\n"); + } + else { + lcd_present = 1; + WRITE_GAL( kGal_DevBank2PReg, kGal_DevBank2Cfg ); + WRITE_GAL( kGal_DevBank3PReg, kGal_DevBank3Cfg ); + } + + return 0; +} + + +// +// Function: dqpoll +// +// Description: Polls the data lines to see if the flash is busy +// +// In: address, byte data +// +// Out: 0 = busy, 1 = write or erase complete +// +// + +int dqpoll( volatile unsigned long address, volatile unsigned char data ) { + +volatile unsigned char dq7; + +dq7 = data & 0x80; + +return ( (READ_FLASH(address) & 0x80) == dq7 ); + +} + + +// +// Function: timeout +// +// Description: Checks to see if erase or write has timed out +// By polling dq5 +// +// In: address +// +// +// Out: 0 = not timed out, 1 = timed out + +int timeout( volatile unsigned long address ) { + + +return ( (READ_FLASH(address) & 0x20) == 0x20 ); + +} + + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/lcd.h linux-2.5/drivers/char/lcd.h --- linux-2.5.5/drivers/char/lcd.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/lcd.h Sun Mar 3 17:54:35 2002 @@ -0,0 +1,184 @@ +/* + * LED, LCD and Button panel driver for Cobalt + * + * 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. + * + * Copyright (C) 1996, 1997 by Andrew Bose + * + * Linux kernel version history: + * March 2001: Ported from 2.0.34 by Liam Davies + * + */ + +// function headers + +int dqpoll( volatile unsigned long, volatile unsigned char ); +int timeout( volatile unsigned long ); + +#define LCD_CHARS_PER_LINE 40 +#define FLASH_SIZE 524288 +#define MAX_IDLE_TIME 120 + +struct lcd_display { + unsigned long buttons; + int size1; + int size2; + unsigned char line1[LCD_CHARS_PER_LINE]; + unsigned char line2[LCD_CHARS_PER_LINE]; + unsigned char cursor_address; + unsigned char character; + unsigned char leds; + unsigned char *RomImage; +}; + + + +#define LCD_DRIVER "Cobalt LCD Driver v2.10" + +#define kLCD_IR 0xBF000000 +#define kLCD_DR 0xBF000010 +#define kGPI 0xBD000000 +#define kLED 0xBC000000 + +#define kDD_R00 0x00 +#define kDD_R01 0x27 +#define kDD_R10 0x40 +#define kDD_R11 0x67 + +#define kLCD_Addr 0x00000080 + +#define LCDTimeoutValue 0xfff + + +// Flash definitions AMD 29F040 +#define kFlashBase 0xBFC00000 + +#define kFlash_Addr1 0x5555 +#define kFlash_Addr2 0x2AAA +#define kFlash_Data1 0xAA +#define kFlash_Data2 0x55 +#define kFlash_Prog 0xA0 +#define kFlash_Erase3 0x80 +#define kFlash_Erase6 0x10 +#define kFlash_Read 0xF0 + +#define kFlash_ID 0x90 +#define kFlash_VenAddr 0x00 +#define kFlash_DevAddr 0x01 +#define kFlash_VenID 0x01 +#define kFlash_DevID 0xA4 // 29F040 +//#define kFlash_DevID 0xAD // 29F016 + + +// Macros + +#define LCDWriteData(x) (*(volatile unsigned long *) kLCD_DR) = (x << 24) +#define LCDWriteInst(x) (*(volatile unsigned long *) kLCD_IR) = (x << 24) + +#define LCDReadData (((*(volatile unsigned long *) kLCD_DR) >> 24)) +#define LCDReadInst (((*(volatile unsigned long *) kLCD_IR) >> 24)) + +#define GPIRead (( (*(volatile unsigned long *) kGPI) >> 24)) + +#define LEDSet(x) (*(volatile unsigned char *) kLED) = ((char)x) + +#define WRITE_GAL(x,y) (*((volatile unsigned long *) (0xB4000000 | (x)) ) =y) +#define BusyCheck() while ((LCDReadInst & 0x80) == 0x80) + +#define WRITE_FLASH(x,y) (*((volatile unsigned char *) (kFlashBase | (x)) ) = y) +#define READ_FLASH(x) *((volatile unsigned char *) (kFlashBase | (x)) ) + + + +/* + * Function command codes for io_ctl. + */ +#define LCD_On 1 +#define LCD_Off 2 +#define LCD_Clear 3 +#define LCD_Reset 4 +#define LCD_Cursor_Left 5 +#define LCD_Cursor_Right 6 +#define LCD_Disp_Left 7 +#define LCD_Disp_Right 8 +#define LCD_Get_Cursor 9 +#define LCD_Set_Cursor 10 +#define LCD_Home 11 +#define LCD_Read 12 +#define LCD_Write 13 +#define LCD_Cursor_Off 14 +#define LCD_Cursor_On 15 +#define LCD_Get_Cursor_Pos 16 +#define LCD_Set_Cursor_Pos 17 +#define LCD_Blink_Off 18 + +#define LED_Set 40 +#define LED_Bit_Set 41 +#define LED_Bit_Clear 42 + + +// Button defs +#define BUTTON_Read 50 + +// Flash command codes +#define FLASH_Erase 60 +#define FLASH_Burn 61 +#define FLASH_Read 62 + + +// Ethernet LINK check hackaroo +#define LINK_Check 90 +#define LINK_Check_2 91 + +// Button patterns _B - single layer lcd boards + +#define BUTTON_NONE 0x3F +#define BUTTON_NONE_B 0xFE + +#define BUTTON_Left 0x3B +#define BUTTON_Left_B 0xFA + +#define BUTTON_Right 0x37 +#define BUTTON_Right_B 0xDE + +#define BUTTON_Up 0x2F +#define BUTTON_Up_B 0xF6 + +#define BUTTON_Down 0x1F +#define BUTTON_Down_B 0xEE + +#define BUTTON_Next 0x3D +#define BUTTON_Next_B 0x7E + +#define BUTTON_Enter 0x3E +#define BUTTON_Enter_B 0xBE + +#define BUTTON_Reset_B 0xFC + + +// debounce constants + +#define BUTTON_SENSE 160000 +#define BUTTON_DEBOUNCE 5000 + + +// Galileo register stuff + +#define kGal_DevBank2Cfg 0x1466DB33 +#define kGal_DevBank2PReg 0x464 +#define kGal_DevBank3Cfg 0x146FDFFB +#define kGal_DevBank3PReg 0x468 + +// Network + +#define kIPADDR 1 +#define kNETMASK 2 +#define kGATEWAY 3 +#define kDNS 4 + +#define kClassA 5 +#define kClassB 6 +#define kClassC 7 + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/logibusmouse.c linux-2.5/drivers/char/logibusmouse.c --- linux-2.5.5/drivers/char/logibusmouse.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/char/logibusmouse.c Thu Jan 1 00:00:00 1970 @@ -1,163 +0,0 @@ -/* - * Logitech Bus Mouse Driver for Linux - * by James Banks - * - * Mods by Matthew Dillon - * calls verify_area() - * tracks better when X is busy or paging - * - * Heavily modified by David Giller - * changed from queue- to counter- driven - * hacked out a (probably incorrect) mouse_select - * - * Modified again by Nathan Laredo to interface with - * 0.96c-pl1 IRQ handling changes (13JUL92) - * didn't bother touching select code. - * - * Modified the select() code blindly to conform to the VFS - * requirements. 92.07.14 - Linus. Somebody should test it out. - * - * Modified by Johan Myreen to make room for other mice (9AUG92) - * removed assignment chr_fops[10] = &mouse_fops; see mouse.c - * renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public. - * renamed this file mouse.c => busmouse.c - * - * Minor addition by Cliff Matthews - * added fasync support - * - * Modularised 6-Sep-95 Philip Blundell - * - * Replaced dumb busy loop with udelay() 16 Nov 95 - * Nathan Laredo - * - * Track I/O ports with request_region(). 12 Dec 95 Philip Blundell - * - * Converted to use new generic busmouse code. 5 Apr 1998 - * Russell King - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "busmouse.h" - -static int msedev; -static int mouse_irq = MOUSE_IRQ; - -MODULE_PARM(mouse_irq, "i"); - -#ifndef MODULE - -static int __init bmouse_setup(char *str) -{ - int ints[4]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) - mouse_irq=ints[1]; - - return 1; -} - -__setup("logi_busmouse=", bmouse_setup); - -#endif /* !MODULE */ - -static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - char dx, dy; - unsigned char buttons; - - outb(MSE_READ_X_LOW, MSE_CONTROL_PORT); - dx = (inb(MSE_DATA_PORT) & 0xf); - outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT); - dx |= (inb(MSE_DATA_PORT) & 0xf) << 4; - outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT ); - dy = (inb(MSE_DATA_PORT) & 0xf); - outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT); - buttons = inb(MSE_DATA_PORT); - dy |= (buttons & 0xf) << 4; - buttons = ((buttons >> 5) & 0x07); - busmouse_add_movementbuttons(msedev, dx, -dy, buttons); - MSE_INT_ON(); -} - -/* - * close access to the mouse - */ -static int close_mouse(struct inode * inode, struct file * file) -{ - MSE_INT_OFF(); - free_irq(mouse_irq, NULL); - return 0; -} - -/* - * open access to the mouse - */ - -static int open_mouse(struct inode * inode, struct file * file) -{ - if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL)) - return -EBUSY; - MSE_INT_ON(); - return 0; -} - -static struct busmouse busmouse = { - LOGITECH_BUSMOUSE, "busmouse", THIS_MODULE, open_mouse, close_mouse, 7 -}; - -static int __init logi_busmouse_init(void) -{ - if (check_region(LOGIBM_BASE, LOGIBM_EXTENT)) - return -EIO; - - outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT); - outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT); - udelay(100L); /* wait for reply from mouse */ - if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) - return -EIO; - - outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT); - MSE_INT_OFF(); - - request_region(LOGIBM_BASE, LOGIBM_EXTENT, "busmouse"); - - msedev = register_busmouse(&busmouse); - if (msedev < 0) - printk(KERN_WARNING "Unable to register busmouse driver.\n"); - else - printk(KERN_INFO "Logitech busmouse installed.\n"); - return msedev < 0 ? msedev : 0; -} - -static void __exit logi_busmouse_cleanup (void) -{ - unregister_busmouse(msedev); - release_region(LOGIBM_BASE, LOGIBM_EXTENT); -} - -module_init(logi_busmouse_init); -module_exit(logi_busmouse_cleanup); - -MODULE_LICENSE("GPL"); -EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/lp.c linux-2.5/drivers/char/lp.c --- linux-2.5.5/drivers/char/lp.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/char/lp.c Fri Mar 1 15:07:37 2002 @@ -270,7 +270,7 @@ return error; } -static int lp_wait_ready(int minor) +static int lp_wait_ready(int minor, int nonblock) { int error = 0; @@ -281,7 +281,7 @@ do { error = lp_check_status (minor); - if (error && (LP_F(minor) & LP_ABORT)) + if (error && (nonblock || (LP_F(minor) & LP_ABORT))) break; if (signal_pending (current)) { error = -EINTR; @@ -300,6 +300,8 @@ ssize_t retv = 0; ssize_t written; size_t copy_size = count; + int nonblock = ((file->f_flags & O_NONBLOCK) || + (LP_F(minor) & LP_ABORT)); #ifdef LP_STATS if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) @@ -326,9 +328,10 @@ lp_table[minor].best_mode); parport_set_timeout (lp_table[minor].dev, - lp_table[minor].timeout); + (nonblock ? PARPORT_INACTIVITY_O_NONBLOCK + : lp_table[minor].timeout)); - if ((retv = lp_wait_ready (minor)) == 0) + if ((retv = lp_wait_ready (minor, nonblock)) == 0) do { /* Write the data. */ written = parport_write (port, kbuf, copy_size); @@ -354,12 +357,16 @@ IEEE1284_MODE_COMPAT); lp_table[minor].current_mode = IEEE1284_MODE_COMPAT; - error = lp_wait_ready (minor); + error = lp_wait_ready (minor, nonblock); if (error) { if (retv == 0) retv = error; break; + } else if (nonblock) { + if (retv == 0) + retv = -EAGAIN; + break; } parport_yield_blocking (lp_table[minor].dev); @@ -407,6 +414,8 @@ struct parport *port = lp_table[minor].dev->port; ssize_t retval = 0; char *kbuf = lp_table[minor].lp_buffer; + int nonblock = ((file->f_flags & O_NONBLOCK) || + (LP_F(minor) & LP_ABORT)); if (count > LP_BUFFER_SIZE) count = LP_BUFFER_SIZE; @@ -415,7 +424,53 @@ return -EINTR; lp_claim_parport_or_block (&lp_table[minor]); - retval = parport_read (port, kbuf, count); + + parport_set_timeout (lp_table[minor].dev, + (nonblock ? PARPORT_INACTIVITY_O_NONBLOCK + : lp_table[minor].timeout)); + + parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT); + if (parport_negotiate (lp_table[minor].dev->port, + IEEE1284_MODE_NIBBLE)) { + retval = -EIO; + goto out; + } + + while (retval == 0) { + retval = parport_read (port, kbuf, count); + + if (retval > 0) + break; + + if (nonblock) { + retval = -EAGAIN; + break; + } + + /* Wait for data. */ + + if (lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE) { + parport_negotiate (lp_table[minor].dev->port, + IEEE1284_MODE_COMPAT); + lp_error (minor); + if (parport_negotiate (lp_table[minor].dev->port, + IEEE1284_MODE_NIBBLE)) { + retval = -EIO; + goto out; + } + } else + interruptible_sleep_on_timeout (&lp_table[minor].waitq, + LP_TIMEOUT_POLLED); + + if (signal_pending (current)) { + retval = -ERESTARTSYS; + break; + } + + cond_resched (); + } + parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT); + out: lp_release_parport (&lp_table[minor]); if (retval > 0 && copy_to_user (buf, kbuf, retval)) @@ -476,7 +531,6 @@ printk (KERN_INFO "lp%d: ECP mode\n", minor); lp_table[minor].best_mode = IEEE1284_MODE_ECP; } else { - printk (KERN_INFO "lp%d: compatibility mode\n", minor); lp_table[minor].best_mode = IEEE1284_MODE_COMPAT; } /* Leave peripheral in compatibility mode */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/machzwd.c linux-2.5/drivers/char/machzwd.c --- linux-2.5.5/drivers/char/machzwd.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/char/machzwd.c Sun Jan 13 22:15:01 2002 @@ -24,6 +24,8 @@ * a system RESET and it starts wd#2 that unconditionaly will RESET * the system when the counter reaches zero. * + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT */ #include @@ -103,6 +105,15 @@ MODULE_PARM(action, "i"); MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI"); +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + #define PFX "machzwd" static struct watchdog_info zf_info = { @@ -307,23 +318,23 @@ * no need to check for close confirmation * no way to disable watchdog ;) */ -#ifndef CONFIG_WATCHDOG_NOWAYOUT - size_t ofs; - - /* - * note: just in case someone wrote the magic character - * five months ago... - */ - zf_expect_close = 0; - - /* now scan */ - for(ofs = 0; ofs != count; ofs++){ - if(buf[ofs] == 'V'){ - zf_expect_close = 1; - dprintk("zf_expect_close 1\n"); + if (!nowayout) { + size_t ofs; + + /* + * note: just in case someone wrote the magic character + * five months ago... + */ + zf_expect_close = 0; + + /* now scan */ + for(ofs = 0; ofs != count; ofs++){ + if(buf[ofs] == 'V'){ + zf_expect_close = 1; + dprintk("zf_expect_close 1\n"); + } } } -#endif /* * Well, anyhow someone wrote to us, * we should return that favour @@ -386,9 +397,9 @@ return -EBUSY; } -#ifdef CONFIG_WATCHDOG_NOWAYOUT - MOD_INC_USE_COUNT; -#endif + if (nowayout) { + MOD_INC_USE_COUNT; + } zf_is_open = 1; spin_unlock(&zf_lock); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/mem.c linux-2.5/drivers/char/mem.c --- linux-2.5.5/drivers/char/mem.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/char/mem.c Fri Feb 8 09:10:48 2002 @@ -199,10 +199,10 @@ vma->vm_flags |= VM_RESERVED; /* - * Don't dump addresses that are not real memory to a core file. + * Dump addresses that are real memory to a core file. */ - if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) - vma->vm_flags |= VM_IO; + if (offset < __pa(high_memory) && !(file->f_flags & O_SYNC)) + vma->vm_flags &= ~VM_IO; if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start, vma->vm_page_prot)) @@ -273,6 +273,8 @@ return virtr + read; } +extern long vwrite(char *buf, char *addr, unsigned long count); + /* * This function writes to the *virtual* memory as seen by the kernel. */ @@ -280,12 +282,46 @@ size_t count, loff_t *ppos) { unsigned long p = *ppos; + ssize_t wrote = 0; + ssize_t virtr = 0; + char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ - if (p >= (unsigned long) high_memory) - return 0; - if (count > (unsigned long) high_memory - p) - count = (unsigned long) high_memory - p; - return do_write_mem(file, (void*)p, p, buf, count, ppos); + if (p < (unsigned long) high_memory) { + wrote = count; + if (count > (unsigned long) high_memory - p) + wrote = (unsigned long) high_memory - p; + + wrote = do_write_mem(file, (void*)p, p, buf, wrote, ppos); + + p += wrote; + buf += wrote; + count -= wrote; + } + + if (count > 0) { + kbuf = (char *)__get_free_page(GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + while (count > 0) { + int len = count; + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + if (len && copy_from_user(kbuf, buf, len)) { + free_page((unsigned long)kbuf); + return -EFAULT; + } + len = vwrite(kbuf, (char *)p, len); + count -= len; + buf += len; + virtr += len; + p += len; + } + free_page((unsigned long)kbuf); + } + + *ppos = p; + return virtr + wrote; } #if !defined(__mc68000__) @@ -437,6 +473,7 @@ return shmem_zero_setup(vma); if (zeromap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; + vma->vm_flags &= ~VM_IO; return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/misc.c linux-2.5/drivers/char/misc.c --- linux-2.5.5/drivers/char/misc.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/char/misc.c Sun Mar 3 17:54:35 2002 @@ -48,7 +48,6 @@ #include #include -#include #include #include "busmouse.h" @@ -76,6 +75,7 @@ extern int pmu_device_init(void); extern int tosh_init(void); extern int i8k_init(void); +extern int lcd_init(void); static int misc_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *private) @@ -276,6 +276,9 @@ #endif #ifdef CONFIG_TOSHIBA tosh_init(); +#endif +#ifdef CONFIG_COBALT_LCD + lcd_init(); #endif #ifdef CONFIG_I8K i8k_init(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/mixcomwd.c linux-2.5/drivers/char/mixcomwd.c --- linux-2.5.5/drivers/char/mixcomwd.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/char/mixcomwd.c Sun Jan 13 22:15:01 2002 @@ -27,10 +27,13 @@ * * Version 0.4 (99/11/15): * - support for one more type board + * + * Version 0.5 (2001/12/14) Matt Domsch + * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT * */ -#define VERSION "0.4" +#define VERSION "0.5" #include #include @@ -57,26 +60,30 @@ static long mixcomwd_opened; /* long req'd for setbit --RR */ static int watchdog_port; - -#ifndef CONFIG_WATCHDOG_NOWAYOUT static int mixcomwd_timer_alive; static struct timer_list mixcomwd_timer; + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; #endif +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + static void mixcomwd_ping(void) { outb_p(55,watchdog_port); return; } -#ifndef CONFIG_WATCHDOG_NOWAYOUT static void mixcomwd_timerfun(unsigned long d) { mixcomwd_ping(); mod_timer(&mixcomwd_timer,jiffies+ 5*HZ); } -#endif /* * Allow only one person to hold it open @@ -89,31 +96,32 @@ } mixcomwd_ping(); -#ifndef CONFIG_WATCHDOG_NOWAYOUT - if(mixcomwd_timer_alive) { - del_timer(&mixcomwd_timer); - mixcomwd_timer_alive=0; - } -#endif + if (nowayout) { + MOD_INC_USE_COUNT; + } else { + if(mixcomwd_timer_alive) { + del_timer(&mixcomwd_timer); + mixcomwd_timer_alive=0; + } + } return 0; } static int mixcomwd_release(struct inode *inode, struct file *file) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - if(mixcomwd_timer_alive) { - printk(KERN_ERR "mixcomwd: release called while internal timer alive"); - return -EBUSY; + if (!nowayout) { + if(mixcomwd_timer_alive) { + printk(KERN_ERR "mixcomwd: release called while internal timer alive"); + return -EBUSY; + } + init_timer(&mixcomwd_timer); + mixcomwd_timer.expires=jiffies + 5 * HZ; + mixcomwd_timer.function=mixcomwd_timerfun; + mixcomwd_timer.data=0; + mixcomwd_timer_alive=1; + add_timer(&mixcomwd_timer); } - init_timer(&mixcomwd_timer); - mixcomwd_timer.expires=jiffies + 5 * HZ; - mixcomwd_timer.function=mixcomwd_timerfun; - mixcomwd_timer.data=0; - mixcomwd_timer_alive=1; - add_timer(&mixcomwd_timer); -#endif - clear_bit(0,&mixcomwd_opened); return 0; } @@ -145,9 +153,9 @@ { case WDIOC_GETSTATUS: status=mixcomwd_opened; -#ifndef CONFIG_WATCHDOG_NOWAYOUT - status|=mixcomwd_timer_alive; -#endif + if (!nowayout) { + status|=mixcomwd_timer_alive; + } if (copy_to_user((int *)arg, &status, sizeof(int))) { return -EFAULT; } @@ -252,14 +260,14 @@ static void __exit mixcomwd_exit(void) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - if(mixcomwd_timer_alive) { - printk(KERN_WARNING "mixcomwd: I quit now, hardware will" - " probably reboot!\n"); - del_timer(&mixcomwd_timer); - mixcomwd_timer_alive=0; + if (!nowayout) { + if(mixcomwd_timer_alive) { + printk(KERN_WARNING "mixcomwd: I quit now, hardware will" + " probably reboot!\n"); + del_timer(&mixcomwd_timer); + mixcomwd_timer_alive=0; + } } -#endif release_region(watchdog_port,1); misc_deregister(&mixcomwd_miscdev); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/msbusmouse.c linux-2.5/drivers/char/msbusmouse.c --- linux-2.5.5/drivers/char/msbusmouse.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/char/msbusmouse.c Thu Jan 1 00:00:00 1970 @@ -1,172 +0,0 @@ -/* - * Microsoft busmouse driver based on Logitech driver (see busmouse.c) - * - * Microsoft BusMouse support by Teemu Rantanen (tvr@cs.hut.fi) (02AUG92) - * - * Microsoft Bus Mouse support modified by Derrick Cole (cole@concert.net) - * 8/28/92 - * - * Microsoft Bus Mouse support folded into 0.97pl4 code - * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92) - * Changes: Logitech and Microsoft support in the same kernel. - * Defined new constants in busmouse.h for MS mice. - * Added int mse_busmouse_type to distinguish busmouse types - * Added a couple of new functions to handle differences in using - * MS vs. Logitech (where the int variable wasn't appropriate). - * - * Modified by Peter Cervasio (address above) (26SEP92) - * Changes: Included code to (properly?) detect when a Microsoft mouse is - * really attached to the machine. Don't know what this does to - * Logitech bus mice, but all it does is read ports. - * - * Modified by Christoph Niemann (niemann@rubdv15.etdv.ruhr-uni-bochum.de) - * Changes: Better interrupt-handler (like in busmouse.c). - * Some changes to reduce code-size. - * Changed detection code to use inb_p() instead of doing empty - * loops to delay i/o. - * - * Modularised 8-Sep-95 Philip Blundell - * - * Converted to use new generic busmouse code. 5 Apr 1998 - * Russell King - * - * version 0.3b - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "busmouse.h" - -static int msedev; -static int mouse_irq = MOUSE_IRQ; - -MODULE_PARM(mouse_irq, "i"); - -#ifndef MODULE - -static int __init msmouse_setup(char *str) -{ - int ints[4]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) - mouse_irq=ints[1]; - - return 1; -} - -__setup("msmouse=",msmouse_setup); - -#endif /* !MODULE */ - -static void ms_mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - char dx, dy; - unsigned char buttons; - - outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); - outb((inb(MS_MSE_DATA_PORT) | 0x20), MS_MSE_DATA_PORT); - - outb(MS_MSE_READ_X, MS_MSE_CONTROL_PORT); - dx = inb(MS_MSE_DATA_PORT); - - outb(MS_MSE_READ_Y, MS_MSE_CONTROL_PORT); - dy = inb(MS_MSE_DATA_PORT); - - outb(MS_MSE_READ_BUTTONS, MS_MSE_CONTROL_PORT); - buttons = ~(inb(MS_MSE_DATA_PORT)) & 0x07; - - outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); - outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT); - - /* why did the original have: - * if (dx != 0 || dy != 0 || buttons != mouse.buttons || - * ((~buttons) & 0x07)) - * ^^^^^^^^^^^^^^^^^^^ this? - */ - busmouse_add_movementbuttons(msedev, dx, -dy, buttons); -} - -static int release_mouse(struct inode * inode, struct file * file) -{ - MS_MSE_INT_OFF(); - free_irq(mouse_irq, NULL); - return 0; -} - -static int open_mouse(struct inode * inode, struct file * file) -{ - if (request_irq(mouse_irq, ms_mouse_interrupt, 0, "MS Busmouse", NULL)) - return -EBUSY; - - outb(MS_MSE_START, MS_MSE_CONTROL_PORT); - MS_MSE_INT_ON(); - return 0; -} - -static struct busmouse msbusmouse = { - MICROSOFT_BUSMOUSE, "msbusmouse", THIS_MODULE, open_mouse, release_mouse, 0 -}; - -static int __init ms_bus_mouse_init(void) -{ - int present = 0; - int mse_byte, i; - - if (check_region(MS_MSE_CONTROL_PORT, 0x04)) - return -ENODEV; - - if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) { - - mse_byte = inb_p(MS_MSE_SIGNATURE_PORT); - - for (i = 0; i < 4; i++) { - if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) { - if (inb_p(MS_MSE_SIGNATURE_PORT) == mse_byte) - present = 1; - else - present = 0; - } else - present = 0; - } - } - if (present == 0) - return -EIO; - MS_MSE_INT_OFF(); - request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse"); - msedev = register_busmouse(&msbusmouse); - if (msedev < 0) - printk(KERN_WARNING "Unable to register msbusmouse driver.\n"); - else - printk(KERN_INFO "Microsoft BusMouse detected and installed.\n"); - return msedev < 0 ? msedev : 0; -} - -static void __exit ms_bus_mouse_exit(void) -{ - unregister_busmouse(msedev); - release_region(MS_MSE_CONTROL_PORT, 0x04); -} - -module_init(ms_bus_mouse_init) -module_exit(ms_bus_mouse_exit) - -MODULE_LICENSE("GPL"); -EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/mwave/mwavedd.c linux-2.5/drivers/char/mwave/mwavedd.c --- linux-2.5.5/drivers/char/mwave/mwavedd.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/char/mwave/mwavedd.c Sun Feb 17 23:08:54 2002 @@ -461,7 +461,7 @@ * mwave_exit is called on module unload * mwave_exit is also used to clean up after an aborted mwave_init */ -static void __exit mwave_exit(void) +static void mwave_exit(void) { pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/mxser.c linux-2.5/drivers/char/mxser.c --- linux-2.5.5/drivers/char/mxser.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/char/mxser.c Fri Feb 8 02:38:26 2002 @@ -32,6 +32,9 @@ * version : 1.2 * * Fixes for C104H/PCI by Tim Hockin + * Added support for: C102, CI-132, CI-134, CP-132, CP-114, CT-114 cards + * by Damian Wrobel + * */ #include @@ -61,7 +64,7 @@ #include #include -#define MXSER_VERSION "1.2" +#define MXSER_VERSION "1.2.1" #define MXSERMAJOR 174 #define MXSERCUMAJOR 175 @@ -114,10 +117,22 @@ #ifndef PCI_DEVICE_ID_C104 #define PCI_DEVICE_ID_C104 0x1040 #endif +#ifndef PCI_DEVICE_ID_CP132 +#define PCI_DEVICE_ID_CP132 0x1320 +#endif +#ifndef PCI_DEVICE_ID_CP114 +#define PCI_DEVICE_ID_CP114 0x1141 +#endif +#ifndef PCI_DEVICE_ID_CT114 +#define PCI_DEVICE_ID_CT114 0x1140 +#endif #define C168_ASIC_ID 1 #define C104_ASIC_ID 2 +#define CI134_ASIC_ID 3 +#define CI132_ASIC_ID 4 #define CI104J_ASIC_ID 5 +#define C102_ASIC_ID 0xB enum { MXSER_BOARD_C168_ISA = 0, @@ -125,6 +140,12 @@ MXSER_BOARD_CI104J, MXSER_BOARD_C168_PCI, MXSER_BOARD_C104_PCI, + MXSER_BOARD_C102_ISA, + MXSER_BOARD_CI132, + MXSER_BOARD_CI134, + MXSER_BOARD_CP132_PCI, + MXSER_BOARD_CP114_PCI, + MXSER_BOARD_CT114_PCI }; static char *mxser_brdname[] = @@ -134,6 +155,12 @@ "CI-104J series", "C168H/PCI series", "C104H/PCI series", + "C102 series", + "CI-132 series", + "CI-134 series", + "CP-132 series", + "CP-114 series", + "CT-114 series" }; static int mxser_numports[] = @@ -143,6 +170,12 @@ 4, 8, 4, + 2, + 2, + 4, + 2, + 4, + 4 }; /* @@ -163,6 +196,12 @@ MXSER_BOARD_C168_PCI }, { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MXSER_BOARD_C104_PCI }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + MXSER_BOARD_CP132_PCI }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + MXSER_BOARD_CP114_PCI }, + { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CT114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + MXSER_BOARD_CT114_PCI }, { 0 } }; MODULE_DEVICE_TABLE(pci, mxser_pcibrds); @@ -613,38 +652,35 @@ n = (sizeof(mxser_pcibrds) / sizeof(mxser_pcibrds[0])) - 1; index = 0; for (b = 0; b < n; b++) { - pdev = pci_find_device(mxser_pcibrds[b].vendor, - mxser_pcibrds[b].device, pdev); - if (!pdev || pci_enable_device(pdev)) - continue; - hwconf.pdev = pdev; - printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", - mxser_brdname[mxser_pcibrds[b].driver_data], - pdev->bus->number, PCI_SLOT(pdev->devfn)); - if (m >= MXSER_BOARDS) { - printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS); - } else { - retval = mxser_get_PCI_conf(pdev, - mxser_pcibrds[b].driver_data, &hwconf); - if (retval < 0) { - if (retval == MXSER_ERR_IRQ) - printk("Invalid interrupt number,board not configured\n"); - else if (retval == MXSER_ERR_IRQ_CONFLIT) - printk("Invalid interrupt number,board not configured\n"); - else if (retval == MXSER_ERR_VECTOR) - printk("Invalid interrupt vector,board not configured\n"); - else if (retval == MXSER_ERR_IOADDR) - printk("Invalid I/O address,board not configured\n"); + while (pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev)) + { + if (pci_enable_device(pdev)) continue; - + hwconf.pdev = pdev; + printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", + mxser_brdname[mxser_pcibrds[b].driver_data], + pdev->bus->number, PCI_SLOT(pdev->devfn)); + if (m >= MXSER_BOARDS) { + printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS); + } else { + retval = mxser_get_PCI_conf(pdev, mxser_pcibrds[b].driver_data, &hwconf); + if (retval < 0) { + if (retval == MXSER_ERR_IRQ) + printk("Invalid interrupt number,board not configured\n"); + else if (retval == MXSER_ERR_IRQ_CONFLIT) + printk("Invalid interrupt number,board not configured\n"); + else if (retval == MXSER_ERR_VECTOR) + printk("Invalid interrupt vector,board not configured\n"); + else if (retval == MXSER_ERR_IOADDR) + printk("Invalid I/O address,board not configured\n"); + continue; + } + if (mxser_initbrd(m, &hwconf) < 0) + continue; + mxser_getcfg(m, &hwconf); + m++; } - if (mxser_initbrd(m, &hwconf) < 0) - continue; - mxser_getcfg(m, &hwconf); - m++; - } - } } #endif @@ -2306,6 +2342,12 @@ hwconf->board_type = MXSER_BOARD_C168_ISA; else if (id == C104_ASIC_ID) hwconf->board_type = MXSER_BOARD_C104_ISA; + else if (id == C102_ASIC_ID) + hwconf->board_type = MXSER_BOARD_C102_ISA; + else if (id == CI132_ASIC_ID) + hwconf->board_type = MXSER_BOARD_CI132; + else if (id == CI134_ASIC_ID) + hwconf->board_type = MXSER_BOARD_CI134; else if (id == CI104J_ASIC_ID) hwconf->board_type = MXSER_BOARD_CI104J; else @@ -2417,7 +2459,8 @@ (void) inb(port); restore_flags(flags); id = inb(port + 1) & 0x1F; - if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID)) + if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID) && + (id != C102_ASIC_ID) && (id != CI132_ASIC_ID) && (id != CI134_ASIC_ID)) return (-1); for (i = 0, j = 0; i < 4; i++) { n = inb(port + 2); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/n_hdlc.c linux-2.5/drivers/char/n_hdlc.c --- linux-2.5.5/drivers/char/n_hdlc.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/char/n_hdlc.c Sun Jan 6 01:38:26 2002 @@ -9,7 +9,7 @@ * Al Longyear , Paul Mackerras * * Original release 01/11/99 - * $Id: n_hdlc.c,v 3.2 2000/11/06 22:34:38 paul Exp $ + * $Id: n_hdlc.c,v 3.3 2001/11/08 16:16:03 paulkf Exp $ * * This code is released under the GNU General Public License (GPL) * @@ -78,7 +78,7 @@ */ #define HDLC_MAGIC 0x239e -#define HDLC_VERSION "3.2" +#define HDLC_VERSION "$Revision: 3.3 $" #include #include @@ -159,11 +159,6 @@ struct tty_struct *tty; /* ptr to TTY structure */ struct tty_struct *backup_tty; /* TTY to use if tty gets closed */ - /* Queues for select() functionality */ - wait_queue_head_t read_wait; - wait_queue_head_t write_wait; - wait_queue_head_t poll_wait; - int tbusy; /* reentrancy flag for tx wakeup code */ int woke_up; N_HDLC_BUF *tbuf; /* currently transmitting tx buffer */ @@ -234,9 +229,8 @@ printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__); /* Ensure that the n_hdlcd process is not hanging on select()/poll() */ - wake_up_interruptible (&n_hdlc->read_wait); - wake_up_interruptible (&n_hdlc->poll_wait); - wake_up_interruptible (&n_hdlc->write_wait); + wake_up_interruptible (&tty->read_wait); + wake_up_interruptible (&tty->write_wait); if (tty != NULL && tty->disc_data == n_hdlc) tty->disc_data = NULL; /* Break the tty->n_hdlc link */ @@ -431,8 +425,7 @@ n_hdlc->tbuf = NULL; /* wait up sleeping writers */ - wake_up_interruptible(&n_hdlc->write_wait); - wake_up_interruptible(&n_hdlc->poll_wait); + wake_up_interruptible(&tty->write_wait); /* get next pending transmit buffer */ tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); @@ -574,8 +567,7 @@ n_hdlc_buf_put(&n_hdlc->rx_buf_list,buf); /* wake up any blocked reads and perform async signalling */ - wake_up_interruptible (&n_hdlc->read_wait); - wake_up_interruptible (&n_hdlc->poll_wait); + wake_up_interruptible (&tty->read_wait); if (n_hdlc->tty->fasync != NULL) kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN); @@ -620,6 +612,9 @@ } for (;;) { + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) + return -EIO; + n_hdlc = tty2n_hdlc (tty); if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) @@ -633,7 +628,7 @@ if (file->f_flags & O_NONBLOCK) return -EAGAIN; - interruptible_sleep_on (&n_hdlc->read_wait); + interruptible_sleep_on (&tty->read_wait); if (signal_pending(current)) return -EINTR; } @@ -702,7 +697,7 @@ count = maxframe; } - add_wait_queue(&n_hdlc->write_wait, &wait); + add_wait_queue(&tty->write_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); /* Allocate transmit buffer */ @@ -725,7 +720,7 @@ } set_current_state(TASK_RUNNING); - remove_wait_queue(&n_hdlc->write_wait, &wait); + remove_wait_queue(&tty->write_wait, &wait); if (!error) { /* Retrieve the user's buffer */ @@ -835,12 +830,14 @@ if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) { /* queue current process into any wait queue that */ /* may awaken in the future (read and write) */ - poll_wait(filp, &n_hdlc->poll_wait, wait); + + poll_wait(filp, &tty->read_wait, wait); + poll_wait(filp, &tty->write_wait, wait); /* set bits for operations that wont block */ if(n_hdlc->rx_buf_list.head) mask |= POLLIN | POLLRDNORM; /* readable */ - if(tty->flags & (1 << TTY_OTHER_CLOSED)) + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) mask |= POLLHUP; if(tty_hung_up_p(filp)) mask |= POLLHUP; @@ -894,11 +891,7 @@ /* Initialize the control block */ n_hdlc->magic = HDLC_MAGIC; - n_hdlc->flags = 0; - init_waitqueue_head(&n_hdlc->read_wait); - init_waitqueue_head(&n_hdlc->poll_wait); - init_waitqueue_head(&n_hdlc->write_wait); return n_hdlc; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/pc110pad.c linux-2.5/drivers/char/pc110pad.c --- linux-2.5.5/drivers/char/pc110pad.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/char/pc110pad.c Thu Jan 1 00:00:00 1970 @@ -1,852 +0,0 @@ -/* - * Linux driver for the PC110 pad - */ - -/** - * DOC: PC110 Digitizer Hardware - * - * The pad provides triples of data. The first byte has - * 0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down - * The second byte is bits 0-6 X - * The third is bits 0-6 Y - * - * This is read internally and used to synthesize a stream of - * triples in the form expected from a PS/2 device. Specialist - * applications can choose to obtain the pad data in other formats - * including a debugging mode. - * - * It would be good to add a joystick driver mode to this pad so - * that doom and other game playing are better. One possible approach - * would be to deactive the mouse mode while the joystick port is opened. - */ - -/* - * History - * - * 0.0 1997-05-16 Alan Cox - Pad reader - * 0.1 1997-05-19 Robin O'Leary - PS/2 emulation - * 0.2 1997-06-03 Robin O'Leary - tap gesture - * 0.3 1997-06-27 Alan Cox - 2.1 commit - * 0.4 1997-11-09 Alan Cox - Single Unix VFS API changes - * 0.5 2000-02-10 Alan Cox - 2.3.x cleanup, documentation - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "pc110pad.h" - - -static struct pc110pad_params default_params = { - mode: PC110PAD_PS2, - bounce_interval: 50 MS, - tap_interval: 200 MS, - irq: 10, - io: 0x15E0, -}; - -static struct pc110pad_params current_params; - - -/* driver/filesystem interface management */ -static wait_queue_head_t queue; -static struct fasync_struct *asyncptr; -static int active_count = 0; /* number of concurrent open()s */ -static spinlock_t pc110_lock = SPIN_LOCK_UNLOCKED; -/* this lock should be held when referencing active_count */ -static struct semaphore reader_lock; - -/** - * wake_readers: - * - * Take care of letting any waiting processes know that - * now would be a good time to do a read(). Called - * whenever a state transition occurs, real or synthetic. Also - * issue any SIGIO's to programs that use SIGIO on mice (eg - * Executor) - */ - -static void wake_readers(void) -{ - wake_up_interruptible(&queue); - kill_fasync(&asyncptr, SIGIO, POLL_IN); -} - - -/*****************************************************************************/ -/* - * Deal with the messy business of synthesizing button tap and drag - * events. - * - * Exports: - * notify_pad_up_down() - * Must be called whenever debounced pad up/down state changes. - * button_pending - * Flag is set whenever read_button() has new values - * to return. - * read_button() - * Obtains the current synthetic mouse button state. - */ - -/* - * These keep track of up/down transitions needed to generate the - * synthetic mouse button events. While recent_transition is set, - * up/down events cause transition_count to increment. tap_timer - * turns off the recent_transition flag and may cause some synthetic - * up/down mouse events to be created by incrementing synthesize_tap. - */ - -static int button_pending; -static int recent_transition; -static int transition_count; -static int synthesize_tap; -static void tap_timeout(unsigned long data); -static struct timer_list tap_timer = { function: tap_timeout }; - - -/** - * tap_timeout: - * @data: Unused - * - * This callback goes off a short time after an up/down transition; - * before it goes off, transitions will be considered part of a - * single PS/2 event and counted in transition_count. Once the - * timeout occurs the recent_transition flag is cleared and - * any synthetic mouse up/down events are generated. - */ - -static void tap_timeout(unsigned long data) -{ - if(!recent_transition) - { - printk(KERN_ERR "pc110pad: tap_timeout but no recent transition!\n"); - } - if( transition_count==2 || transition_count==4 || transition_count==6 ) - { - synthesize_tap+=transition_count; - button_pending = 1; - wake_readers(); - } - recent_transition=0; -} - - -/** - * notify_pad_up_down: - * - * Called by the raw pad read routines when a (debounced) up/down - * transition is detected. - */ - -void notify_pad_up_down(void) -{ - if(recent_transition) - { - transition_count++; - } - else - { - transition_count=1; - recent_transition=1; - } - mod_timer(&tap_timer, jiffies + current_params.tap_interval); - - /* changes to transition_count can cause reported button to change */ - button_pending = 1; - wake_readers(); -} - -/** - * read_button: - * @b: pointer to the button status. - * - * The actual button state depends on what we are seeing. We have to check - * for the tap gesture and also for dragging. - */ - -static void read_button(int *b) -{ - if(synthesize_tap) - { - *b=--synthesize_tap & 1; - } - else - { - *b=(!recent_transition && transition_count==3); /* drag */ - } - button_pending=(synthesize_tap>0); -} - - -/*****************************************************************************/ -/* - * Read pad absolute co-ordinates and debounced up/down state. - * - * Exports: - * pad_irq() - * Function to be called whenever the pad signals - * that it has new data available. - * read_raw_pad() - * Returns the most current pad state. - * xy_pending - * Flag is set whenever read_raw_pad() has new values - * to return. - * Imports: - * wake_readers() - * Called when movement occurs. - * notify_pad_up_down() - * Called when debounced up/down status changes. - */ - -/* - * These are up/down state and absolute co-ords read directly from pad - */ - -static int raw_data[3]; -static int raw_data_count; -static int raw_x, raw_y; /* most recent absolute co-ords read */ -static int raw_down; /* raw up/down state */ -static int debounced_down; /* up/down state after debounce processing */ -static enum { NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN } bounce=NO_BOUNCE; - /* set just after an up/down transition */ -static int xy_pending; /* set if new data have not yet been read */ - -/* - * Timer goes off a short while after an up/down transition and copies - * the value of raw_down to debounced_down. - */ - -static void bounce_timeout(unsigned long data); -static struct timer_list bounce_timer = { function: bounce_timeout }; - - - -/** - * bounce_timeout: - * @data: Unused - * - * No further up/down transitions happened within the - * bounce period, so treat this as a genuine transition. - */ - -static void bounce_timeout(unsigned long data) -{ - switch(bounce) - { - case NO_BOUNCE: - { - /* - * Strange; the timer callback should only go off if - * we were expecting to do bounce processing! - */ - printk(KERN_WARNING "pc110pad, bounce_timeout: bounce flag not set!\n"); - break; - } - case JUST_GONE_UP: - { - /* - * The last up we spotted really was an up, so set - * debounced state the same as raw state. - */ - bounce=NO_BOUNCE; - if(debounced_down==raw_down) - { - printk(KERN_WARNING "pc110pad, bounce_timeout: raw already debounced!\n"); - } - debounced_down=raw_down; - - notify_pad_up_down(); - break; - } - case JUST_GONE_DOWN: - { - /* - * We don't debounce down events, but we still time - * out soon after one occurs so we can avoid the (x,y) - * skittering that sometimes happens. - */ - bounce=NO_BOUNCE; - break; - } - } -} - - -/** - * pad_irq: - * @irq: Interrupt number - * @ptr: Unused - * @regs: Unused - * - * Callback when pad's irq goes off; copies values in to raw_* globals; - * initiates debounce processing. This isn't SMP safe however there are - * no SMP machines with a PC110 touchpad on them. - */ - -static void pad_irq(int irq, void *ptr, struct pt_regs *regs) -{ - - /* Obtain byte from pad and prime for next byte */ - { - int value=inb_p(current_params.io); - int handshake=inb_p(current_params.io+2); - outb_p(handshake | 1, current_params.io+2); - outb_p(handshake &~1, current_params.io+2); - inb_p(0x64); - - raw_data[raw_data_count++]=value; - } - - if(raw_data_count==3) - { - int new_down=raw_data[0]&0x01; - int new_x=raw_data[1]; - int new_y=raw_data[2]; - if(raw_data[0]&0x10) new_x+=128; - if(raw_data[0]&0x80) new_x+=256; - if(raw_data[0]&0x08) new_y+=128; - - if( (raw_x!=new_x) || (raw_y!=new_y) ) - { - raw_x=new_x; - raw_y=new_y; - xy_pending=1; - } - - if(new_down != raw_down) - { - /* Down state has changed. raw_down always holds - * the most recently observed state. - */ - raw_down=new_down; - - /* Forget any earlier bounce processing */ - if(bounce) - { - del_timer(&bounce_timer); - bounce=NO_BOUNCE; - } - - if(new_down) - { - if(debounced_down) - { - /* pad gone down, but we were reporting - * it down anyway because we suspected - * (correctly) that the last up was just - * a bounce - */ - } - else - { - bounce=JUST_GONE_DOWN; - mod_timer(&bounce_timer, - jiffies+current_params.bounce_interval); - /* start new stroke/tap */ - debounced_down=new_down; - notify_pad_up_down(); - } - } - else /* just gone up */ - { - if(recent_transition) - { - /* early bounces are probably part of - * a multi-tap gesture, so process - * immediately - */ - debounced_down=new_down; - notify_pad_up_down(); - } - else - { - /* don't trust it yet */ - bounce=JUST_GONE_UP; - mod_timer(&bounce_timer, - jiffies+current_params.bounce_interval); - } - } - } - wake_readers(); - raw_data_count=0; - } -} - -/** - * read_raw_pad: - * @down: set if the pen is down - * @debounced: set if the debounced pen position is down - * @x: X position - * @y: Y position - * - * Retrieve the data saved by the interrupt handler and indicate we - * have no more pending XY to do. - * - * FIXME: We should switch to a spinlock for this. - */ - -static void read_raw_pad(int *down, int *debounced, int *x, int *y) -{ - disable_irq(current_params.irq); - { - *down=raw_down; - *debounced=debounced_down; - *x=raw_x; - *y=raw_y; - xy_pending = 0; - } - enable_irq(current_params.irq); -} - -/*****************************************************************************/ -/* - * Filesystem interface - */ - -/* - * Read returns byte triples, so we need to keep track of - * how much of a triple has been read. This is shared across - * all processes which have this device open---not that anything - * will make much sense in that case. - */ -static int read_bytes[3]; -static int read_byte_count; - -/** - * sample_raw: - * @d: sample buffer - * - * Retrieve a triple of sample data. - */ - - -static void sample_raw(int d[3]) -{ - d[0]=raw_data[0]; - d[1]=raw_data[1]; - d[2]=raw_data[2]; -} - -/** - * sample_rare: - * @d: sample buffer - * - * Retrieve a triple of sample data and sanitize it. We do the needed - * scaling and masking to get the current status. - */ - - -static void sample_rare(int d[3]) -{ - int thisd, thisdd, thisx, thisy; - - read_raw_pad(&thisd, &thisdd, &thisx, &thisy); - - d[0]=(thisd?0x80:0) - | (thisx/256)<<4 - | (thisdd?0x08:0) - | (thisy/256) - ; - d[1]=thisx%256; - d[2]=thisy%256; -} - -/** - * sample_debug: - * @d: sample buffer - * - * Retrieve a triple of sample data and mix it up with the state - * information in the gesture parser. Not useful for normal users but - * handy when debugging - */ - -static void sample_debug(int d[3]) -{ - int thisd, thisdd, thisx, thisy; - int b; - unsigned long flags; - - spin_lock_irqsave(&pc110_lock, flags); - read_raw_pad(&thisd, &thisdd, &thisx, &thisy); - d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce; - d[1]=(recent_transition?0x80:0)+transition_count; - read_button(&b); - d[2]=(synthesize_tap<<4) | (b?0x01:0); - spin_unlock_irqrestore(&pc110_lock, flags); -} - -/** - * sample_ps2: - * @d: sample buffer - * - * Retrieve a triple of sample data and turn the debounced tap and - * stroke information into what appears to be a PS/2 mouse. This means - * the PC110 pad needs no funny application side support. - */ - - -static void sample_ps2(int d[3]) -{ - static int lastx, lasty, lastd; - - int thisd, thisdd, thisx, thisy; - int dx, dy, b; - - /* - * Obtain the current mouse parameters and limit as appropriate for - * the return data format. Interrupts are only disabled while - * obtaining the parameters, NOT during the puts_fs_byte() calls, - * so paging in put_user() does not affect mouse tracking. - */ - read_raw_pad(&thisd, &thisdd, &thisx, &thisy); - read_button(&b); - - /* Now compare with previous readings. Note that we use the - * raw down flag rather than the debounced one. - */ - if( (thisd && !lastd) /* new stroke */ - || (bounce!=NO_BOUNCE) ) - { - dx=0; - dy=0; - } - else - { - dx = (thisx-lastx); - dy = -(thisy-lasty); - } - lastx=thisx; - lasty=thisy; - lastd=thisd; - -/* - d[0]= ((dy<0)?0x20:0) - | ((dx<0)?0x10:0) - | 0x08 - | (b? 0x01:0x00) - ; -*/ - d[0]= ((dy<0)?0x20:0) - | ((dx<0)?0x10:0) - | (b? 0x00:0x08) - ; - d[1]=dx; - d[2]=dy; -} - - -/** - * fasync_pad: - * @fd: file number for the file - * @filp: file handle - * @on: 1 to add, 0 to remove a notifier - * - * Update the queue of asynchronous event notifiers. We can use the - * same helper the mice do and that does almost everything we need. - */ - -static int fasync_pad(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &asyncptr); - if (retval < 0) - return retval; - return 0; -} - - -/** - * close_pad: - * @inode: inode of pad - * @file: file handle to pad - * - * Close access to the pad. We turn the pad power off if this is the - * last user of the pad. I've not actually measured the power draw but - * the DOS driver is careful to do this so we follow suit. - */ - -static int close_pad(struct inode * inode, struct file * file) -{ - unsigned long flags; - fasync_pad(-1, file, 0); - spin_lock_irqsave(&pc110_lock, flags); - if (!--active_count) - outb(0x30, current_params.io+2); /* switch off digitiser */ - spin_unlock_irqrestore(&pc110_lock, flags); - return 0; -} - - -/** - * open_pad: - * @inode: inode of pad - * @file: file handle to pad - * - * Open access to the pad. We turn the pad off first (we turned it off - * on close but if this is the first open after a crash the state is - * indeterminate). The device has a small fifo so we empty that before - * we kick it back into action. - */ - -static int open_pad(struct inode * inode, struct file * file) -{ - unsigned long flags; - - spin_lock_irqsave(&pc110_lock, flags); - if (active_count++) - { - spin_unlock_irqrestore(&pc110_lock, flags); - return 0; - } - - outb(0x30, current_params.io+2); /* switch off digitiser */ - pad_irq(0,0,0); /* read to flush any pending bytes */ - pad_irq(0,0,0); /* read to flush any pending bytes */ - pad_irq(0,0,0); /* read to flush any pending bytes */ - outb(0x38, current_params.io+2); /* switch on digitiser */ - current_params = default_params; - raw_data_count=0; /* re-sync input byte counter */ - read_byte_count=0; /* re-sync output byte counter */ - button_pending=0; - recent_transition=0; - transition_count=0; - synthesize_tap=0; - del_timer(&bounce_timer); - del_timer(&tap_timer); - spin_unlock_irqrestore(&pc110_lock, flags); - - return 0; -} - - -/** - * write_pad: - * @file: File handle to the pad - * @buffer: Unused - * @count: Unused - * @ppos: Unused - * - * Writes are disallowed. A true PS/2 mouse lets you write stuff. Everyone - * seems happy with this and not faking the write modes. - */ - -static ssize_t write_pad(struct file * file, const char * buffer, size_t count, loff_t *ppos) -{ - return -EINVAL; -} - - -/* - * new_sample: - * @d: sample buffer - * - * Fetch a new sample according the current mouse mode the pad is - * using. - */ - -void new_sample(int d[3]) -{ - switch(current_params.mode) - { - case PC110PAD_RAW: sample_raw(d); break; - case PC110PAD_RARE: sample_rare(d); break; - case PC110PAD_DEBUG: sample_debug(d); break; - case PC110PAD_PS2: sample_ps2(d); break; - } -} - - -/** - * read_pad: - * @file: File handle to pad - * @buffer: Target for the mouse data - * @count: Buffer length - * @ppos: Offset (unused) - * - * Read data from the pad. We use the reader_lock to avoid mess when there are - * two readers. This shouldnt be happening anyway but we play safe. - */ - -static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t *ppos) -{ - int r; - - down(&reader_lock); - for(r=0; rPC110PAD_PS2) - || (new.bounce_interval<0) - || (new.tap_interval<0) - ) - return -EINVAL; - - current_params.mode = new.mode; - current_params.bounce_interval = new.bounce_interval; - current_params.tap_interval = new.tap_interval; - return 0; - } - return -ENOTTY; -} - - -static struct file_operations pad_fops = { - owner: THIS_MODULE, - read: read_pad, - write: write_pad, - poll: pad_poll, - ioctl: pad_ioctl, - open: open_pad, - release: close_pad, - fasync: fasync_pad, -}; - - -static struct miscdevice pc110_pad = { - minor: PC110PAD_MINOR, - name: "pc110 pad", - fops: &pad_fops, -}; - - -/** - * pc110pad_init_driver: - * - * We configure the pad with the default parameters (that is PS/2 - * emulation mode. We then claim the needed I/O and interrupt resources. - * Finally as a matter of paranoia we turn the pad off until we are - * asked to open it by an application. - */ - -static char banner[] __initdata = KERN_INFO "PC110 digitizer pad at 0x%X, irq %d.\n"; - -static int __init pc110pad_init_driver(void) -{ - init_MUTEX(&reader_lock); - current_params = default_params; - - if (request_irq(current_params.irq, pad_irq, 0, "pc110pad", 0)) { - printk(KERN_ERR "pc110pad: Unable to get IRQ.\n"); - return -EBUSY; - } - if (!request_region(current_params.io, 4, "pc110pad")) { - printk(KERN_ERR "pc110pad: I/O area in use.\n"); - free_irq(current_params.irq,0); - return -EBUSY; - } - init_waitqueue_head(&queue); - printk(banner, current_params.io, current_params.irq); - misc_register(&pc110_pad); - outb(0x30, current_params.io+2); /* switch off digitiser */ - return 0; -} - -/* - * pc110pad_exit_driver: - * - * Free the resources we acquired when the module was loaded. We also - * turn the pad off to be sure we don't leave it using power. - */ - -static void __exit pc110pad_exit_driver(void) -{ - outb(0x30, current_params.io+2); /* switch off digitiser */ - if (current_params.irq) - free_irq(current_params.irq, 0); - current_params.irq = 0; - release_region(current_params.io, 4); - misc_deregister(&pc110_pad); -} - -module_init(pc110pad_init_driver); -module_exit(pc110pad_exit_driver); - -MODULE_AUTHOR("Alan Cox, Robin O'Leary"); -MODULE_DESCRIPTION("Driver for the touchpad on the IBM PC110 palmtop"); -MODULE_LICENSE("GPL"); - -EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/pc110pad.h linux-2.5/drivers/char/pc110pad.h --- linux-2.5.5/drivers/char/pc110pad.h Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/char/pc110pad.h Thu Jan 1 00:00:00 1970 @@ -1,31 +0,0 @@ -#ifndef _PC110PAD_H -#define _PC110PAD_H - -#include - -enum pc110pad_mode { - PC110PAD_RAW, /* bytes as they come out of the hardware */ - PC110PAD_RARE, /* debounced up/down and absolute x,y */ - PC110PAD_DEBUG, /* up/down, debounced, transitions, button */ - PC110PAD_PS2, /* ps2 relative (default) */ -}; - - -struct pc110pad_params { - enum pc110pad_mode mode; - int bounce_interval; - int tap_interval; - int irq; - int io; -}; - -#define MS *HZ/1000 - -/* Appears as device major=10 (MISC), minor=PC110_PAD */ - -#define PC110PAD_IOCTL_TYPE 0x9a - -#define PC110PADIOCGETP _IOR(PC110PAD_IOCTL_TYPE, 0, struct pc110pad_params) -#define PC110PADIOCSETP _IOW(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params) - -#endif /* _PC110PAD_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/pc_keyb.c linux-2.5/drivers/char/pc_keyb.c --- linux-2.5.5/drivers/char/pc_keyb.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/char/pc_keyb.c Sun Jan 20 17:11:45 2002 @@ -61,79 +61,6 @@ "\r\000/"; /* 0x60 - 0x6f */ #endif -static void kbd_write_command_w(int data); -static void kbd_write_output_w(int data); -#ifdef CONFIG_PSMOUSE -static void aux_write_ack(int val); -static void __aux_write_ack(int val); -static int aux_reconnect = 0; -#endif - -static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; -static unsigned char handle_kbd_event(void); - -/* used only by send_data - set by keyboard_interrupt */ -static volatile unsigned char reply_expected; -static volatile unsigned char acknowledge; -static volatile unsigned char resend; - - -#if defined CONFIG_PSMOUSE -/* - * PS/2 Auxiliary Device - */ - -static int __init psaux_init(void); - -#define AUX_RECONNECT1 0xaa /* scancode1 when ps2 device is plugged (back) in */ -#define AUX_RECONNECT2 0x00 /* scancode2 when ps2 device is plugged (back) in */ - -static struct aux_queue *queue; /* Mouse data buffer. */ -static int aux_count; -static spinlock_t aux_count_lock = SPIN_LOCK_UNLOCKED; -/* used when we send commands to the mouse that expect an ACK. */ -static unsigned char mouse_reply_expected; - -#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT) -#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) - -#define MAX_RETRIES 60 /* some aux operations take long time*/ -#endif /* CONFIG_PSMOUSE */ - -/* - * Wait for keyboard controller input buffer to drain. - * - * Don't use 'jiffies' so that we don't depend on - * interrupts.. - * - * Quote from PS/2 System Reference Manual: - * - * "Address hex 0060 and address hex 0064 should be written only when - * the input-buffer-full bit and output-buffer-full bit in the - * Controller Status register are set 0." - */ - -static void kb_wait(void) -{ - unsigned long timeout = KBC_TIMEOUT; - - do { - /* - * "handle_kbd_event()" will handle any incoming events - * while we wait - keypresses or mouse movement. - */ - unsigned char status = handle_kbd_event(); - - if (! (status & KBD_STAT_IBF)) - return; - mdelay(1); - timeout--; - } while (timeout); -#ifdef KBD_REPORT_TIMEOUTS - printk(KERN_WARNING "Keyboard timed out[1]\n"); -#endif -} - /* * Translation of escaped scancodes to keycodes. * This is now user-settable. @@ -268,32 +195,6 @@ e0_keys[scancode - 128]; } -static int do_acknowledge(unsigned char scancode) -{ - if (reply_expected) { - /* Unfortunately, we must recognise these codes only if we know they - * are known to be valid (i.e., after sending a command), because there - * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have - * keys with such codes :( - */ - if (scancode == KBD_REPLY_ACK) { - acknowledge = 1; - reply_expected = 0; - return 0; - } else if (scancode == KBD_REPLY_RESEND) { - resend = 1; - reply_expected = 0; - return 0; - } - /* Should not happen... */ -#if 0 - printk(KERN_DEBUG "keyboard reply expected - got %02x\n", - scancode); -#endif - } - return 1; -} - int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode) { @@ -401,833 +302,8 @@ int pckbd_pm_resume(struct pm_dev *dev, pm_request_t rqst, void *data) { -#if defined CONFIG_PSMOUSE - unsigned long flags; - - if (rqst == PM_RESUME) { - if (queue) { /* Aux port detected */ - spin_lock_irqsave(&aux_count_lock, flags); - if ( aux_count == 0) { /* Mouse not in use */ - spin_lock(&kbd_controller_lock); - /* - * Dell Lat. C600 A06 enables mouse after resume. - * When user touches the pad, it posts IRQ 12 - * (which we do not process), thus holding keyboard. - */ - kbd_write_command(KBD_CCMD_MOUSE_DISABLE); - /* kbd_write_cmd(AUX_INTS_OFF); */ /* Config & lock */ - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MODE); - kb_wait(); - kbd_write_output(AUX_INTS_OFF); - spin_unlock(&kbd_controller_lock); - } - spin_unlock_irqrestore(&aux_count_lock, flags); - } - } -#endif return 0; } - -static inline void handle_mouse_event(unsigned char scancode) -{ -#ifdef CONFIG_PSMOUSE - unsigned long flags; - static unsigned char prev_code; - if (mouse_reply_expected) { - if (scancode == AUX_ACK) { - mouse_reply_expected--; - return; - } - mouse_reply_expected = 0; - } - else if(scancode == AUX_RECONNECT2 && prev_code == AUX_RECONNECT1 - && aux_reconnect) { - printk (KERN_INFO "PS/2 mouse reconnect detected\n"); - queue->head = queue->tail = 0; /* Flush input queue */ - __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */ - return; - } - - prev_code = scancode; - add_mouse_randomness(scancode); - spin_lock_irqsave(&aux_count_lock, flags); - if ( aux_count ) { - int head = queue->head; - - queue->buf[head] = scancode; - head = (head + 1) & (AUX_BUF_SIZE-1); - if (head != queue->tail) { - queue->head = head; - kill_fasync(&queue->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&queue->proc_list); - } - } - spin_unlock_irqrestore(&aux_count_lock, flags); -#endif -} - -static unsigned char kbd_exists = 1; - -static inline void handle_keyboard_event(unsigned char scancode) -{ -#ifdef CONFIG_VT - kbd_exists = 1; - if (do_acknowledge(scancode)) - handle_scancode(scancode, !(scancode & 0x80)); -#endif - tasklet_schedule(&keyboard_tasklet); -} - -/* - * This reads the keyboard status port, and does the - * appropriate action. - * - * It requires that we hold the keyboard controller - * spinlock. - */ -static unsigned char handle_kbd_event(void) -{ - unsigned char status = kbd_read_status(); - unsigned int work = 10000; - - while ((--work > 0) && (status & KBD_STAT_OBF)) { - unsigned char scancode; - - scancode = kbd_read_input(); - - /* Error bytes must be ignored to make the - Synaptics touchpads compaq use work */ -#if 1 - /* Ignore error bytes */ - if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) -#endif - { - if (status & KBD_STAT_MOUSE_OBF) - handle_mouse_event(scancode); - else - handle_keyboard_event(scancode); - } - - status = kbd_read_status(); - } - - if (!work) - printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", status); - - return status; -} - - -static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ -#ifdef CONFIG_VT - kbd_pt_regs = regs; -#endif - - spin_lock_irq(&kbd_controller_lock); - handle_kbd_event(); - spin_unlock_irq(&kbd_controller_lock); -} - -/* - * send_data sends a character to the keyboard and waits - * for an acknowledge, possibly retrying if asked to. Returns - * the success status. - * - * Don't use 'jiffies', so that we don't depend on interrupts - */ -static int send_data(unsigned char data) -{ - int retries = 3; - - do { - unsigned long timeout = KBD_TIMEOUT; - - acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */ - resend = 0; - reply_expected = 1; - kbd_write_output_w(data); - for (;;) { - if (acknowledge) - return 1; - if (resend) - break; - mdelay(1); - if (!--timeout) { -#ifdef KBD_REPORT_TIMEOUTS - printk(KERN_WARNING "keyboard: Timeout - AT keyboard not present?(%02x)\n", data); -#endif - return 0; - } - } - } while (retries-- > 0); -#ifdef KBD_REPORT_TIMEOUTS - printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n"); -#endif - return 0; -} - -void pckbd_leds(unsigned char leds) -{ - if (kbd_exists && (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))) { - send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ - kbd_exists = 0; - } -} - -#define DEFAULT_KEYB_REP_DELAY 250 -#define DEFAULT_KEYB_REP_RATE 30 /* cps */ - -static struct kbd_repeat kbdrate={ - DEFAULT_KEYB_REP_DELAY, - DEFAULT_KEYB_REP_RATE -}; - -static unsigned char parse_kbd_rate(struct kbd_repeat *r) -{ - static struct r2v{ - int rate; - unsigned char val; - } kbd_rates[]={ {5,0x14}, - {7,0x10}, - {10,0x0c}, - {15,0x08}, - {20,0x04}, - {25,0x02}, - {30,0x00} - }; - static struct d2v{ - int delay; - unsigned char val; - } kbd_delays[]={{250,0}, - {500,1}, - {750,2}, - {1000,3} - }; - int rate=0,delay=0; - if (r != NULL){ - int i,new_rate=30,new_delay=250; - if (r->rate <= 0) - r->rate=kbdrate.rate; - if (r->delay <= 0) - r->delay=kbdrate.delay; - for (i=0; i < sizeof(kbd_rates)/sizeof(struct r2v); i++) - if (kbd_rates[i].rate == r->rate){ - new_rate=kbd_rates[i].rate; - rate=kbd_rates[i].val; - break; - } - for (i=0; i < sizeof(kbd_delays)/sizeof(struct d2v); i++) - if (kbd_delays[i].delay == r->delay){ - new_delay=kbd_delays[i].delay; - delay=kbd_delays[i].val; - break; - } - r->rate=new_rate; - r->delay=new_delay; - } - return (delay << 5) | rate; -} - -static int write_kbd_rate(unsigned char r) -{ - if (!send_data(KBD_CMD_SET_RATE) || !send_data(r)){ - send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ - return 0; - }else - return 1; -} - -static int pckbd_rate(struct kbd_repeat *rep) -{ - if (rep == NULL) - return -EINVAL; - else{ - unsigned char r=parse_kbd_rate(rep); - struct kbd_repeat old_rep; - memcpy(&old_rep,&kbdrate,sizeof(struct kbd_repeat)); - if (write_kbd_rate(r)){ - memcpy(&kbdrate,rep,sizeof(struct kbd_repeat)); - memcpy(rep,&old_rep,sizeof(struct kbd_repeat)); - return 0; - } - } - return -EIO; -} - -/* - * In case we run on a non-x86 hardware we need to initialize both the - * keyboard controller and the keyboard. On a x86, the BIOS will - * already have initialized them. - * - * Some x86 BIOSes do not correctly initialize the keyboard, so the - * "kbd-reset" command line options can be given to force a reset. - * [Ranger] - */ -#ifdef __i386__ - int kbd_startup_reset __initdata = 0; -#else - int kbd_startup_reset __initdata = 1; -#endif - -/* for "kbd-reset" cmdline param */ -static int __init kbd_reset_setup(char *str) -{ - kbd_startup_reset = 1; - return 1; -} - -__setup("kbd-reset", kbd_reset_setup); - -#define KBD_NO_DATA (-1) /* No data */ -#define KBD_BAD_DATA (-2) /* Parity or other error */ - -static int __init kbd_read_data(void) -{ - int retval = KBD_NO_DATA; - unsigned char status; - - status = kbd_read_status(); - if (status & KBD_STAT_OBF) { - unsigned char data = kbd_read_input(); - - retval = data; - if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) - retval = KBD_BAD_DATA; - } - return retval; -} - -static void __init kbd_clear_input(void) -{ - int maxread = 100; /* Random number */ - - do { - if (kbd_read_data() == KBD_NO_DATA) - break; - } while (--maxread); -} - -static int __init kbd_wait_for_input(void) -{ - long timeout = KBD_INIT_TIMEOUT; - - do { - int retval = kbd_read_data(); - if (retval >= 0) - return retval; - mdelay(1); - } while (--timeout); - return -1; -} - -static void kbd_write_command_w(int data) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_command(data); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} - -static void kbd_write_output_w(int data) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_output(data); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} - -#if defined(__alpha__) -/* - * Some Alphas cannot mask some/all interrupts, so we have to - * make sure not to allow interrupts AT ALL when polling for - * specific return values from the keyboard. - * - * I think this should work on any architecture, but for now, only Alpha. - */ -static int kbd_write_command_w_and_wait(int data) -{ - unsigned long flags; - int input; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_command(data); - input = kbd_wait_for_input(); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - return input; -} - -static int kbd_write_output_w_and_wait(int data) -{ - unsigned long flags; - int input; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_output(data); - input = kbd_wait_for_input(); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - return input; -} -#else -static int kbd_write_command_w_and_wait(int data) -{ - kbd_write_command_w(data); - return kbd_wait_for_input(); -} - -static int kbd_write_output_w_and_wait(int data) -{ - kbd_write_output_w(data); - return kbd_wait_for_input(); -} -#endif /* __alpha__ */ - -#if defined CONFIG_PSMOUSE -static void kbd_write_cmd(int cmd) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MODE); - kb_wait(); - kbd_write_output(cmd); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} -#endif /* CONFIG_PSMOUSE */ - -static char * __init initialize_kbd(void) -{ - int status; - - /* - * Test the keyboard interface. - * This seems to be the only way to get it going. - * If the test is successful a x55 is placed in the input buffer. - */ - kbd_write_command_w(KBD_CCMD_SELF_TEST); - if (kbd_wait_for_input() != 0x55) - return "Keyboard failed self test"; - - /* - * Perform a keyboard interface test. This causes the controller - * to test the keyboard clock and data lines. The results of the - * test are placed in the input buffer. - */ - kbd_write_command_w(KBD_CCMD_KBD_TEST); - if (kbd_wait_for_input() != 0x00) - return "Keyboard interface failed self test"; - - /* - * Enable the keyboard by allowing the keyboard clock to run. - */ - kbd_write_command_w(KBD_CCMD_KBD_ENABLE); - - /* - * Reset keyboard. If the read times out - * then the assumption is that no keyboard is - * plugged into the machine. - * This defaults the keyboard to scan-code set 2. - * - * Set up to try again if the keyboard asks for RESEND. - */ - do { - kbd_write_output_w(KBD_CMD_RESET); - status = kbd_wait_for_input(); - if (status == KBD_REPLY_ACK) - break; - if (status != KBD_REPLY_RESEND) - return "Keyboard reset failed, no ACK"; - } while (1); - - if (kbd_wait_for_input() != KBD_REPLY_POR) - return "Keyboard reset failed, no POR"; - - /* - * Set keyboard controller mode. During this, the keyboard should be - * in the disabled state. - * - * Set up to try again if the keyboard asks for RESEND. - */ - do { - kbd_write_output_w(KBD_CMD_DISABLE); - status = kbd_wait_for_input(); - if (status == KBD_REPLY_ACK) - break; - if (status != KBD_REPLY_RESEND) - return "Disable keyboard: no ACK"; - } while (1); - - kbd_write_command_w(KBD_CCMD_WRITE_MODE); - kbd_write_output_w(KBD_MODE_KBD_INT - | KBD_MODE_SYS - | KBD_MODE_DISABLE_MOUSE - | KBD_MODE_KCC); - - /* ibm powerpc portables need this to use scan-code set 1 -- Cort */ - if (!(kbd_write_command_w_and_wait(KBD_CCMD_READ_MODE) & KBD_MODE_KCC)) - { - /* - * If the controller does not support conversion, - * Set the keyboard to scan-code set 1. - */ - kbd_write_output_w(0xF0); - kbd_wait_for_input(); - kbd_write_output_w(0x01); - kbd_wait_for_input(); - } - - if (kbd_write_output_w_and_wait(KBD_CMD_ENABLE) != KBD_REPLY_ACK) - return "Enable keyboard: no ACK"; - - /* - * Finally, set the typematic rate to maximum. - */ - if (kbd_write_output_w_and_wait(KBD_CMD_SET_RATE) != KBD_REPLY_ACK) - return "Set rate: no ACK"; - if (kbd_write_output_w_and_wait(0x00) != KBD_REPLY_ACK) - return "Set rate: no 2nd ACK"; - - return NULL; -} - -void __init pckbd_init_hw(void) -{ - kbd_request_region(); - - /* Flush any pending input. */ - kbd_clear_input(); - - if (kbd_startup_reset) { - char *msg = initialize_kbd(); - if (msg) - printk(KERN_WARNING "initialize_kbd: %s\n", msg); - } - -#if defined CONFIG_PSMOUSE - psaux_init(); -#endif - - kbd_rate = pckbd_rate; - - /* Ok, finally allocate the IRQ, and off we go.. */ - kbd_request_irq(keyboard_interrupt); -} - -#if defined CONFIG_PSMOUSE - -static int __init aux_reconnect_setup (char *str) -{ - aux_reconnect = 1; - return 1; -} - -__setup("psaux-reconnect", aux_reconnect_setup); - -/* - * Check if this is a dual port controller. - */ -static int __init detect_auxiliary_port(void) -{ - unsigned long flags; - int loops = 10; - int retval = 0; - - /* Check if the BIOS detected a device on the auxiliary port. */ - if (aux_device_present == 0xaa) - return 1; - - spin_lock_irqsave(&kbd_controller_lock, flags); - - /* Put the value 0x5A in the output buffer using the "Write - * Auxiliary Device Output Buffer" command (0xD3). Poll the - * Status Register for a while to see if the value really - * turns up in the Data Register. If the KBD_STAT_MOUSE_OBF - * bit is also set to 1 in the Status Register, we assume this - * controller has an Auxiliary Port (a.k.a. Mouse Port). - */ - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF); - - kb_wait(); - kbd_write_output(0x5a); /* 0x5a is a random dummy value. */ - - do { - unsigned char status = kbd_read_status(); - - if (status & KBD_STAT_OBF) { - (void) kbd_read_input(); - if (status & KBD_STAT_MOUSE_OBF) { - printk(KERN_INFO "Detected PS/2 Mouse Port.\n"); - retval = 1; - } - break; - } - mdelay(1); - } while (--loops); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - - return retval; -} - -/* - * Send a byte to the mouse. - */ -static void aux_write_dev(int val) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MOUSE); - kb_wait(); - kbd_write_output(val); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} - -/* - * Send a byte to the mouse & handle returned ack - */ -static void __aux_write_ack(int val) -{ - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MOUSE); - kb_wait(); - kbd_write_output(val); - /* we expect an ACK in response. */ - mouse_reply_expected++; - kb_wait(); -} - -static void aux_write_ack(int val) -{ - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - __aux_write_ack(val); - spin_unlock_irqrestore(&kbd_controller_lock, flags); -} - -static unsigned char get_from_queue(void) -{ - unsigned char result; - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - result = queue->buf[queue->tail]; - queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - return result; -} - - -static inline int queue_empty(void) -{ - return queue->head == queue->tail; -} - -static int fasync_aux(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &queue->fasync); - if (retval < 0) - return retval; - return 0; -} - - -/* - * Random magic cookie for the aux device - */ -#define AUX_DEV ((void *)queue) - -static int release_aux(struct inode * inode, struct file * file) -{ - unsigned long flags; - fasync_aux(-1, file, 0); - spin_lock_irqsave(&aux_count_lock, flags); - if ( --aux_count ) { - spin_unlock_irqrestore(&aux_count_lock, flags); - return 0; - } - spin_unlock_irqrestore(&aux_count_lock, flags); - kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ - kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); - aux_free_irq(AUX_DEV); - return 0; -} - -/* - * Install interrupt handler. - * Enable auxiliary device. - */ - -static int open_aux(struct inode * inode, struct file * file) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&aux_count_lock, flags); - if ( aux_count++ ) { - spin_unlock_irqrestore(&aux_count_lock, flags); - return 0; - } - queue->head = queue->tail = 0; /* Flush input queue */ - spin_unlock_irqrestore(&aux_count_lock, flags); - ret = aux_request_irq(keyboard_interrupt, AUX_DEV); - spin_lock_irqsave(&aux_count_lock, flags); - if (ret) { - aux_count--; - spin_unlock_irqrestore(&aux_count_lock, flags); - return -EBUSY; - } - spin_unlock_irqrestore(&aux_count_lock, flags); - kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the - auxiliary port on - controller. */ - aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ - kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */ - - mdelay(2); /* Ensure we follow the kbc access delay rules.. */ - - send_data(KBD_CMD_ENABLE); /* try to workaround toshiba4030cdt problem */ - return 0; -} - -/* - * Put bytes from input queue to buffer. - */ - -static ssize_t read_aux(struct file * file, char * buffer, - size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - ssize_t i = count; - unsigned char c; - - if (queue_empty()) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - add_wait_queue(&queue->proc_list, &wait); -repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (queue_empty() && !signal_pending(current)) { - schedule(); - goto repeat; - } - current->state = TASK_RUNNING; - remove_wait_queue(&queue->proc_list, &wait); - } - while (i > 0 && !queue_empty()) { - c = get_from_queue(); - put_user(c, buffer++); - i--; - } - if (count-i) { - file->f_dentry->d_inode->i_atime = CURRENT_TIME; - return count-i; - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* - * Write to the aux device. - */ - -static ssize_t write_aux(struct file * file, const char * buffer, - size_t count, loff_t *ppos) -{ - ssize_t retval = 0; - - if (count) { - ssize_t written = 0; - - if (count > 32) - count = 32; /* Limit to 32 bytes. */ - do { - char c; - get_user(c, buffer++); - aux_write_dev(c); - written++; - } while (--count); - retval = -EIO; - if (written) { - retval = written; - file->f_dentry->d_inode->i_mtime = CURRENT_TIME; - } - } - - return retval; -} - -/* No kernel lock held - fine */ -static unsigned int aux_poll(struct file *file, poll_table * wait) -{ - poll_wait(file, &queue->proc_list, wait); - if (!queue_empty()) - return POLLIN | POLLRDNORM; - return 0; -} - -struct file_operations psaux_fops = { - read: read_aux, - write: write_aux, - poll: aux_poll, - open: open_aux, - release: release_aux, - fasync: fasync_aux, -}; - -/* - * Initialize driver. - */ -static struct miscdevice psaux_mouse = { - PSMOUSE_MINOR, "psaux", &psaux_fops -}; - -static int __init psaux_init(void) -{ - int retval; - - if (!detect_auxiliary_port()) - return -EIO; - - if ((retval = misc_register(&psaux_mouse))) - return retval; - - queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); - if (queue == NULL) { - printk(KERN_ERR "psaux_init(): out of memory\n"); - misc_deregister(&psaux_mouse); - return -ENOMEM; - } - memset(queue, 0, sizeof(*queue)); - queue->head = queue->tail = 0; - init_waitqueue_head(&queue->proc_list); - -#ifdef INITIALIZE_MOUSE - kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ - aux_write_ack(AUX_SET_SAMPLE); - aux_write_ack(100); /* 100 samples/sec */ - aux_write_ack(AUX_SET_RES); - aux_write_ack(3); /* 8 counts per mm */ - aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ -#endif /* INITIALIZE_MOUSE */ - kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ - kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */ - - return 0; -} - -#endif /* CONFIG_PSMOUSE */ +void pckbd_leds(unsigned char leds) { } +void __init pckbd_init_hw(void) { } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/pcmcia/serial_cs.c linux-2.5/drivers/char/pcmcia/serial_cs.c --- linux-2.5.5/drivers/char/pcmcia/serial_cs.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/char/pcmcia/serial_cs.c Thu Dec 13 16:32:35 2001 @@ -2,7 +2,7 @@ A driver for PCMCIA serial devices - serial_cs.c 1.123 2000/08/24 18:46:38 + serial_cs.c 1.128 2001/10/18 12:18:35 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -19,8 +19,8 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the + terms of the GNU General Public License version 2 (the "GPL"), in + which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -53,30 +54,32 @@ #include #include -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"serial_cs.c 1.123 2000/08/24 18:46:38 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds "); +MODULE_DESCRIPTION("PCMCIA serial card driver"); +MODULE_LICENSE("Dual MPL/GPL"); + +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +INT_MODULE_PARM(irq_mask, 0xdeb8); static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); /* Enable the speaker? */ -static int do_sound = 1; +INT_MODULE_PARM(do_sound, 1); -MODULE_PARM(irq_mask, "i"); -MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM(do_sound, "i"); +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ @@ -93,6 +96,8 @@ { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 }, { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 }, { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 }, + { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 }, + { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 }, { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 }, { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 }, { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 } @@ -357,7 +362,6 @@ found_port: if (i != CS_SUCCESS) { - printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); cs_error(link->handle, RequestIO, i); return -1; } @@ -437,7 +441,6 @@ i = CardServices(RequestIRQ, link->handle, &link->irq); if (i != CS_SUCCESS) { - printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); cs_error(link->handle, RequestIRQ, i); link->irq.AssignedIRQ = 0; } @@ -663,5 +666,3 @@ module_init(init_serial_cs); module_exit(exit_serial_cs); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/pcwd.c linux-2.5/drivers/char/pcwd.c --- linux-2.5.5/drivers/char/pcwd.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/char/pcwd.c Thu Feb 14 02:57:58 2002 @@ -40,6 +40,8 @@ * fairly useless proc entry. * 990610 removed said useless proc code for the merge * 000403 Removed last traces of proc code. + * 011214 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default */ #include @@ -76,7 +78,7 @@ */ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; -#define WD_VER "1.10 (06/05/99)" +#define WD_VER "1.12 (12/14/2001)" /* * It should be noted that PCWD_REVISION_B was removed because A and B @@ -88,7 +90,22 @@ #define PCWD_REVISION_A 1 #define PCWD_REVISION_C 2 -#define WD_TIMEOUT 3 /* 1 1/2 seconds for a timeout */ +#define WD_TIMEOUT 4 /* 2 seconds for a timeout */ +static int timeout_val = WD_TIMEOUT; +static int timeout = 2; + +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=2)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + /* * These are the defines for the PC Watchdog card, revision A. @@ -127,7 +144,7 @@ if (prev_card_dat == 0xFF) return 0; - while(count < WD_TIMEOUT) { + while(count < timeout_val) { /* Read the raw card data from the port, and strip off the first 4 bits */ @@ -456,16 +473,16 @@ { if (minor(ino->i_rdev)==WATCHDOG_MINOR) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - /* Disable the board */ - if (revision == PCWD_REVISION_C) { - spin_lock(&io_lock); - outb_p(0xA5, current_readport + 3); - outb_p(0xA5, current_readport + 3); - spin_unlock(&io_lock); + if (!nowayout) { + /* Disable the board */ + if (revision == PCWD_REVISION_C) { + spin_lock(&io_lock); + outb_p(0xA5, current_readport + 3); + outb_p(0xA5, current_readport + 3); + spin_unlock(&io_lock); + } + atomic_inc( &open_allowed ); } - atomic_inc( &open_allowed ); -#endif } return 0; } @@ -565,10 +582,16 @@ "temperature", &pcwd_fops }; + +static void __init pcwd_validate_timeout(void) +{ + timeout_val = timeout * 2; +} static int __init pcwatchdog_init(void) { int i, found = 0; + pcwd_validate_timeout(); spin_lock_init(&io_lock); revision = PCWD_REVISION_A; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/ppdev.c linux-2.5/drivers/char/ppdev.c --- linux-2.5.5/drivers/char/ppdev.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/char/ppdev.c Fri Mar 1 15:07:37 2002 @@ -4,7 +4,7 @@ * This is the code behind /dev/parport* -- it allows a user-space * application to use the parport subsystem. * - * Copyright (C) 1998-2000 Tim Waugh + * Copyright (C) 1998-2000, 2002 Tim Waugh * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -80,6 +80,7 @@ unsigned char irqctl; struct ieee1284_info state; struct ieee1284_info saved_state; + long default_inactivity; }; /* pp_struct.flags bitfields */ @@ -107,7 +108,6 @@ struct pp_struct *pp = file->private_data; char * kbuffer; ssize_t bytes_read = 0; - ssize_t got = 0; struct parport *pport; int mode; @@ -125,8 +125,13 @@ pport = pp->pdev->port; mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); - while (bytes_read < count) { - ssize_t need = min_t(unsigned long, count - bytes_read, PP_BUFFER_SIZE); + parport_set_timeout (pp->pdev, + (file->f_flags & O_NONBLOCK) ? + PARPORT_INACTIVITY_O_NONBLOCK : + pp->default_inactivity); + + while (bytes_read == 0) { + ssize_t need = min_t(unsigned long, count, PP_BUFFER_SIZE); if (mode == IEEE1284_MODE_EPP) { /* various specials for EPP mode */ @@ -144,35 +149,32 @@ } else { fn = pport->ops->epp_read_data; } - got = (*fn)(pport, kbuffer, need, flags); + bytes_read = (*fn)(pport, kbuffer, need, flags); } else { - got = parport_read (pport, kbuffer, need); + bytes_read = parport_read (pport, kbuffer, need); } - if (got <= 0) { - if (!bytes_read) { - bytes_read = got; - } + if (bytes_read != 0) break; - } - if (copy_to_user (buf + bytes_read, kbuffer, got)) { - bytes_read = -EFAULT; + if (file->f_flags & O_NONBLOCK) { + bytes_read = -EAGAIN; break; } - bytes_read += got; - if (signal_pending (current)) { - if (!bytes_read) { - bytes_read = -EINTR; - } + bytes_read = -ERESTARTSYS; break; } cond_resched(); } + parport_set_timeout (pp->pdev, pp->default_inactivity); + + if (bytes_read > 0 && copy_to_user (buf, kbuffer, bytes_read)) + bytes_read = -EFAULT; + kfree (kbuffer); pp_enable_irq (pp); return bytes_read; @@ -203,6 +205,11 @@ pport = pp->pdev->port; mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); + parport_set_timeout (pp->pdev, + (file->f_flags & O_NONBLOCK) ? + PARPORT_INACTIVITY_O_NONBLOCK : + pp->default_inactivity); + while (bytes_written < count) { ssize_t n = min_t(unsigned long, count - bytes_written, PP_BUFFER_SIZE); @@ -233,6 +240,12 @@ bytes_written += wrote; + if (file->f_flags & O_NONBLOCK) { + if (!bytes_written) + bytes_written = -EAGAIN; + break; + } + if (signal_pending (current)) { if (!bytes_written) { bytes_written = -EINTR; @@ -243,6 +256,8 @@ cond_resched(); } + parport_set_timeout (pp->pdev, pp->default_inactivity); + kfree (kbuffer); pp_enable_irq (pp); return bytes_written; @@ -352,6 +367,8 @@ pp->saved_state.phase = info->phase; info->mode = pp->state.mode; info->phase = pp->state.phase; + pp->default_inactivity = parport_set_timeout (pp->pdev, 0); + parport_set_timeout (pp->pdev, pp->default_inactivity); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/qpmouse.c linux-2.5/drivers/char/qpmouse.c --- linux-2.5.5/drivers/char/qpmouse.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/char/qpmouse.c Thu Jan 1 00:00:00 1970 @@ -1,382 +0,0 @@ -/* - * linux/drivers/char/qpmouse.c - * - * Driver for a 82C710 C&T mouse interface chip. - * - * Based on the PS/2 driver by Johan Myreen. - * - * Corrections in device setup for some laptop mice & trackballs. - * 02Feb93 (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca) - * - * Modified by Johan Myreen (jem@iki.fi) 04Aug93 - * to include support for QuickPort mouse. - * - * Changed references to "QuickPort" with "82C710" since "QuickPort" - * is not what this driver is all about -- QuickPort is just a - * connector type, and this driver is for the mouse port on the Chips - * & Technologies 82C710 interface chip. 15Nov93 jem@iki.fi - * - * Added support for SIGIO. 28Jul95 jem@iki.fi - * - * Rearranged SIGIO support to use code from tty_io. 9Sept95 ctm@ardi.com - * - * Modularised 8-Sep-95 Philip Blundell - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include /* mouse enable command.. */ - - -/* - * We use the same minor number as the PS/2 mouse for (bad) historical - * reasons.. - */ -#define PSMOUSE_MINOR 1 /* Minor device # for this mouse */ -#define QP_BUF_SIZE 2048 - -struct qp_queue { - unsigned long head; - unsigned long tail; - wait_queue_head_t proc_list; - struct fasync_struct *fasync; - unsigned char buf[QP_BUF_SIZE]; -}; - -static struct qp_queue *queue; - -static unsigned int get_from_queue(void) -{ - unsigned int result; - unsigned long flags; - - save_flags(flags); - cli(); - result = queue->buf[queue->tail]; - queue->tail = (queue->tail + 1) & (QP_BUF_SIZE-1); - restore_flags(flags); - return result; -} - - -static inline int queue_empty(void) -{ - return queue->head == queue->tail; -} - -static int fasync_qp(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &queue->fasync); - if (retval < 0) - return retval; - return 0; -} - -/* - * 82C710 Interface - */ - -#define QP_DATA 0x310 /* Data Port I/O Address */ -#define QP_STATUS 0x311 /* Status Port I/O Address */ - -#define QP_DEV_IDLE 0x01 /* Device Idle */ -#define QP_RX_FULL 0x02 /* Device Char received */ -#define QP_TX_IDLE 0x04 /* Device XMIT Idle */ -#define QP_RESET 0x08 /* Device Reset */ -#define QP_INTS_ON 0x10 /* Device Interrupt On */ -#define QP_ERROR_FLAG 0x20 /* Device Error */ -#define QP_CLEAR 0x40 /* Device Clear */ -#define QP_ENABLE 0x80 /* Device Enable */ - -#define QP_IRQ 12 - -static int qp_present; -static int qp_count; -static spinlock_t qp_count_lock = SPIN_LOCK_UNLOCKED; -static int qp_data = QP_DATA; -static int qp_status = QP_STATUS; - -static int poll_qp_status(void); -static int probe_qp(void); - -/* - * Interrupt handler for the 82C710 mouse port. A character - * is waiting in the 82C710. - */ - -static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs) -{ - int head = queue->head; - int maxhead = (queue->tail-1) & (QP_BUF_SIZE-1); - - add_mouse_randomness(queue->buf[head] = inb(qp_data)); - if (head != maxhead) { - head++; - head &= QP_BUF_SIZE-1; - } - queue->head = head; - kill_fasync(&queue->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&queue->proc_list); -} - -static int release_qp(struct inode * inode, struct file * file) -{ - unsigned char status; - - fasync_qp(-1, file, 0); - spin_lock( &qp_count_lock ); - if (!--qp_count) { - if (!poll_qp_status()) - printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n"); - status = inb_p(qp_status); - outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status); - if (!poll_qp_status()) - printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n"); - free_irq(QP_IRQ, NULL); - } - spin_unlock( &qp_count_lock ); - return 0; -} - -/* - * Install interrupt handler. - * Enable the device, enable interrupts. - */ - -static int open_qp(struct inode * inode, struct file * file) -{ - unsigned char status; - - if (!qp_present) - return -EINVAL; - - spin_lock( &qp_count_lock ); - if (qp_count++) - { - spin_unlock( &qp_count_lock ); - return 0; - } - spin_unlock( &qp_count_lock ); - - if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse", NULL)) { - qp_count--; - return -EBUSY; - } - - status = inb_p(qp_status); - status |= (QP_ENABLE|QP_RESET); - outb_p(status, qp_status); - status &= ~(QP_RESET); - outb_p(status, qp_status); - - queue->head = queue->tail = 0; /* Flush input queue */ - status |= QP_INTS_ON; - outb_p(status, qp_status); /* Enable interrupts */ - - while (!poll_qp_status()) { - printk(KERN_ERR "Error: Mouse device busy in open_qp()\n"); - qp_count--; - status &= ~(QP_ENABLE|QP_INTS_ON); - outb_p(status, qp_status); - free_irq(QP_IRQ, NULL); - return -EBUSY; - } - - outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */ - return 0; -} - -/* - * Write to the 82C710 mouse device. - */ - -static ssize_t write_qp(struct file * file, const char * buffer, - size_t count, loff_t *ppos) -{ - ssize_t i = count; - - while (i--) { - char c; - if (!poll_qp_status()) - return -EIO; - get_user(c, buffer++); - outb_p(c, qp_data); - } - file->f_dentry->d_inode->i_mtime = CURRENT_TIME; - return count; -} - -static unsigned int poll_qp(struct file *file, poll_table * wait) -{ - poll_wait(file, &queue->proc_list, wait); - if (!queue_empty()) - return POLLIN | POLLRDNORM; - return 0; -} - -/* - * Wait for device to send output char and flush any input char. - */ - -#define MAX_RETRIES (60) - -static int poll_qp_status(void) -{ - int retries=0; - - while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE)) - != (QP_DEV_IDLE|QP_TX_IDLE) - && retries < MAX_RETRIES) { - - if (inb_p(qp_status)&(QP_RX_FULL)) - inb_p(qp_data); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((5*HZ + 99) / 100); - retries++; - } - return !(retries==MAX_RETRIES); -} - -/* - * Put bytes from input queue to buffer. - */ - -static ssize_t read_qp(struct file * file, char * buffer, - size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - ssize_t i = count; - unsigned char c; - - if (queue_empty()) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - add_wait_queue(&queue->proc_list, &wait); -repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (queue_empty() && !signal_pending(current)) { - schedule(); - goto repeat; - } - current->state = TASK_RUNNING; - remove_wait_queue(&queue->proc_list, &wait); - } - while (i > 0 && !queue_empty()) { - c = get_from_queue(); - put_user(c, buffer++); - i--; - } - if (count-i) { - file->f_dentry->d_inode->i_atime = CURRENT_TIME; - return count-i; - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -struct file_operations qp_fops = { - owner: THIS_MODULE, - read: read_qp, - write: write_qp, - poll: poll_qp, - open: open_qp, - release: release_qp, - fasync: fasync_qp, -}; - -/* - * Initialize driver. - */ -static struct miscdevice qp_mouse = { - minor: PSMOUSE_MINOR, - name: "QPmouse", - fops: &qp_fops, -}; - -/* - * Function to read register in 82C710. - */ - -static inline unsigned char read_710(unsigned char index) -{ - outb_p(index, 0x390); /* Write index */ - return inb_p(0x391); /* Read the data */ -} - - -/* - * See if we can find a 82C710 device. Read mouse address. - */ - -static int __init probe_qp(void) -{ - outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */ - outb_p(0xaa, 0x3fa); /* Inverse of 55 */ - outb_p(0x36, 0x3fa); /* Address the chip */ - outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */ - outb_p(0x1b, 0x2fa); /* Inverse of e4 */ - if (read_710(0x0f) != 0xe4) /* Config address found? */ - return 0; /* No: no 82C710 here */ - qp_data = read_710(0x0d)*4; /* Get mouse I/O address */ - qp_status = qp_data+1; - outb_p(0x0f, 0x390); - outb_p(0x0f, 0x391); /* Close config mode */ - return 1; -} - -static char msg_banner[] __initdata = KERN_INFO "82C710 type pointing device detected -- driver installed.\n"; -static char msg_nomem[] __initdata = KERN_ERR "qpmouse: no queue memory.\n"; - -static int __init qpmouse_init_driver(void) -{ - if (!probe_qp()) - return -EIO; - - printk(msg_banner); - -/* printk("82C710 address = %x (should be 0x310)\n", qp_data); */ - queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); - if (queue == NULL) { - printk(msg_nomem); - return -ENOMEM; - } - qp_present = 1; - misc_register(&qp_mouse); - memset(queue, 0, sizeof(*queue)); - queue->head = queue->tail = 0; - init_waitqueue_head(&queue->proc_list); - return 0; -} - -static void __exit qpmouse_exit_driver(void) -{ - misc_deregister(&qp_mouse); - kfree(queue); -} - -module_init(qpmouse_init_driver); -module_exit(qpmouse_exit_driver); - - -MODULE_LICENSE("GPL"); -EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/qtronix.c linux-2.5/drivers/char/qtronix.c --- linux-2.5.5/drivers/char/qtronix.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/char/qtronix.c Sun Mar 3 17:54:35 2002 @@ -51,6 +51,7 @@ #ifdef CONFIG_QTRONIX_KEYBOARD +#include #include #include #include @@ -121,7 +122,7 @@ }; -void init_qtronix_990P_kbd(void) +void __init init_qtronix_990P_kbd(void) { int retval; @@ -592,4 +593,5 @@ return 0; } +module_init(init_qtronix_990P_kbd); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/qtronixmap.c linux-2.5/drivers/char/qtronixmap.c --- linux-2.5.5/drivers/char/qtronixmap.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/qtronixmap.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,265 @@ + +/* Do not edit this file! It was automatically generated by */ +/* loadkeys --mktable defkeymap.map > defkeymap.c */ + +#include +#include +#include + +u_short plain_map[NR_KEYS] = { + 0xf200, 0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, + 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf200, 0xf07f, + 0xf009, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, + 0xfb69, 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf05c, 0xf207, 0xfb61, + 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, + 0xf03b, 0xf027, 0xf060, 0xf201, 0xf700, 0xf200, 0xfb7a, 0xfb78, + 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf020, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, + 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf01b, 0xf200, + 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107, + 0xf108, 0xf109, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +u_short shift_map[NR_KEYS] = { + 0xf200, 0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, + 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf200, 0xf07f, + 0xf009, 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, + 0xfb49, 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf07c, 0xf207, 0xfb41, + 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, + 0xf03a, 0xf022, 0xf07e, 0xf201, 0xf700, 0xf200, 0xfb5a, 0xfb58, + 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf020, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf20b, 0xf20a, 0xf200, + 0xf200, 0xf602, 0xf213, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf01b, 0xf200, + 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111, + 0xf112, 0xf113, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +u_short altgr_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, + 0xf200, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, + 0xfb69, 0xfb6f, 0xfb70, 0xf200, 0xf200, 0xf200, 0xf207, 0xfb61, + 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, + 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xfb7a, 0xfb78, + 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, + 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, + 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513, + 0xf514, 0xf515, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +u_short ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, + 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf008, + 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, + 0xf009, 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf01c, 0xf207, 0xf001, + 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, + 0xf007, 0xf000, 0xf200, 0xf201, 0xf700, 0xf200, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf002, 0xf00e, 0xf20e, 0xf07f, 0xf200, 0xf200, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf000, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, + 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, + 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107, + 0xf108, 0xf109, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +u_short shift_ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, + 0xf009, 0xf00f, 0xf010, 0xf200, 0xf200, 0xf200, 0xf207, 0xf001, + 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, + 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, + 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +u_short alt_map[NR_KEYS] = { + 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, + 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf200, 0xf87f, + 0xf809, 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, + 0xf869, 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf85c, 0xf207, 0xf861, + 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf83b, + 0xf827, 0xf860, 0xf200, 0xf80d, 0xf700, 0xf200, 0xf87a, 0xf878, + 0xf863, 0xf876, 0xf862, 0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf200, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf820, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf210, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, + 0xf200, 0xf211, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, + 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507, + 0xf508, 0xf509, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +u_short ctrl_alt_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, + 0xf809, 0xf80f, 0xf810, 0xf200, 0xf200, 0xf200, 0xf207, 0xf801, + 0xf813, 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, + 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xf81a, 0xf818, + 0xf803, 0xf816, 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601, + 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200, + 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200, + 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507, + 0xf508, 0xf509, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200, +}; + +ushort *key_maps[MAX_NR_KEYMAPS] = { + plain_map, shift_map, altgr_map, 0, + ctrl_map, shift_ctrl_map, 0, 0, + alt_map, 0, 0, 0, + ctrl_alt_map, 0 +}; + +unsigned int keymap_count = 7; + + +/* + * Philosophy: most people do not define more strings, but they who do + * often want quite a lot of string space. So, we statically allocate + * the default and allocate dynamically in chunks of 512 bytes. + */ + +char func_buf[] = { + '\033', '[', '[', 'A', 0, + '\033', '[', '[', 'B', 0, + '\033', '[', '[', 'C', 0, + '\033', '[', '[', 'D', 0, + '\033', '[', '[', 'E', 0, + '\033', '[', '1', '7', '~', 0, + '\033', '[', '1', '8', '~', 0, + '\033', '[', '1', '9', '~', 0, + '\033', '[', '2', '0', '~', 0, + '\033', '[', '2', '1', '~', 0, + '\033', '[', '2', '3', '~', 0, + '\033', '[', '2', '4', '~', 0, + '\033', '[', '2', '5', '~', 0, + '\033', '[', '2', '6', '~', 0, + '\033', '[', '2', '8', '~', 0, + '\033', '[', '2', '9', '~', 0, + '\033', '[', '3', '1', '~', 0, + '\033', '[', '3', '2', '~', 0, + '\033', '[', '3', '3', '~', 0, + '\033', '[', '3', '4', '~', 0, + '\033', '[', '1', '~', 0, + '\033', '[', '2', '~', 0, + '\033', '[', '3', '~', 0, + '\033', '[', '4', '~', 0, + '\033', '[', '5', '~', 0, + '\033', '[', '6', '~', 0, + '\033', '[', 'M', 0, + '\033', '[', 'P', 0, +}; + + +char *funcbufptr = func_buf; +int funcbufsize = sizeof(func_buf); +int funcbufleft = 0; /* space left */ + +char *func_table[MAX_NR_FUNC] = { + func_buf + 0, + func_buf + 5, + func_buf + 10, + func_buf + 15, + func_buf + 20, + func_buf + 25, + func_buf + 31, + func_buf + 37, + func_buf + 43, + func_buf + 49, + func_buf + 55, + func_buf + 61, + func_buf + 67, + func_buf + 73, + func_buf + 79, + func_buf + 85, + func_buf + 91, + func_buf + 97, + func_buf + 103, + func_buf + 109, + func_buf + 115, + func_buf + 120, + func_buf + 125, + func_buf + 130, + func_buf + 135, + func_buf + 140, + func_buf + 145, + 0, + 0, + func_buf + 149, + 0, +}; + +struct kbdiacr accent_table[MAX_DIACR] = { + {'`', 'A', 'À'}, {'`', 'a', 'à'}, + {'\'', 'A', 'Á'}, {'\'', 'a', 'á'}, + {'^', 'A', 'Â'}, {'^', 'a', 'â'}, + {'~', 'A', 'Ã'}, {'~', 'a', 'ã'}, + {'"', 'A', 'Ä'}, {'"', 'a', 'ä'}, + {'O', 'A', 'Å'}, {'o', 'a', 'å'}, + {'0', 'A', 'Å'}, {'0', 'a', 'å'}, + {'A', 'A', 'Å'}, {'a', 'a', 'å'}, + {'A', 'E', 'Æ'}, {'a', 'e', 'æ'}, + {',', 'C', 'Ç'}, {',', 'c', 'ç'}, + {'`', 'E', 'È'}, {'`', 'e', 'è'}, + {'\'', 'E', 'É'}, {'\'', 'e', 'é'}, + {'^', 'E', 'Ê'}, {'^', 'e', 'ê'}, + {'"', 'E', 'Ë'}, {'"', 'e', 'ë'}, + {'`', 'I', 'Ì'}, {'`', 'i', 'ì'}, + {'\'', 'I', 'Í'}, {'\'', 'i', 'í'}, + {'^', 'I', 'Î'}, {'^', 'i', 'î'}, + {'"', 'I', 'Ï'}, {'"', 'i', 'ï'}, + {'-', 'D', 'Ð'}, {'-', 'd', 'ð'}, + {'~', 'N', 'Ñ'}, {'~', 'n', 'ñ'}, + {'`', 'O', 'Ò'}, {'`', 'o', 'ò'}, + {'\'', 'O', 'Ó'}, {'\'', 'o', 'ó'}, + {'^', 'O', 'Ô'}, {'^', 'o', 'ô'}, + {'~', 'O', 'Õ'}, {'~', 'o', 'õ'}, + {'"', 'O', 'Ö'}, {'"', 'o', 'ö'}, + {'/', 'O', 'Ø'}, {'/', 'o', 'ø'}, + {'`', 'U', 'Ù'}, {'`', 'u', 'ù'}, + {'\'', 'U', 'Ú'}, {'\'', 'u', 'ú'}, + {'^', 'U', 'Û'}, {'^', 'u', 'û'}, + {'"', 'U', 'Ü'}, {'"', 'u', 'ü'}, + {'\'', 'Y', 'Ý'}, {'\'', 'y', 'ý'}, + {'T', 'H', 'Þ'}, {'t', 'h', 'þ'}, + {'s', 's', 'ß'}, {'"', 'y', 'ÿ'}, + {'s', 'z', 'ß'}, {'i', 'j', 'ÿ'}, +}; + +unsigned int accent_table_size = 68; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/rocket.c linux-2.5/drivers/char/rocket.c --- linux-2.5.5/drivers/char/rocket.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/char/rocket.c Thu Jan 31 00:08:53 2002 @@ -227,7 +227,7 @@ if (!info) return 1; if (info->magic != RPORT_MAGIC) { - printk(badmagic, MAJOR(device), MINOR(device), routine); + printk(badmagic, major(device), minor(device), routine); return 1; } #endif @@ -896,7 +896,7 @@ CHANNEL_t *cp; unsigned long page; - line = MINOR(tty->device) - tty->driver.minor_start; + line = minor(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= MAX_RP_PORTS)) return -ENODEV; if (!tmp_buf) { @@ -1964,6 +1964,10 @@ str = "8-port Modem"; max_num_aiops = 1; break; + case 0x8: + str = "mysterious 8 port"; + max_num_aiops = 1; + break; default: str = "(unknown/unsupported)"; max_num_aiops = 0; @@ -2040,6 +2044,10 @@ count++; if(!pcibios_find_device(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8M, i, &bus, &device_fn)) + if(register_PCI(count+boards_found, bus, device_fn)) + count++; + if(!pcibios_find_device(PCI_VENDOR_ID_RP, + 0x8, i, &bus, &device_fn)) if(register_PCI(count+boards_found, bus, device_fn)) count++; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/rocket_int.h linux-2.5/drivers/char/rocket_int.h --- linux-2.5.5/drivers/char/rocket_int.h Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/char/rocket_int.h Tue Feb 26 20:14:01 2002 @@ -185,7 +185,7 @@ /* Old clock prescale definition and baud rates associated with it */ -#define CLOCK_PRESC 0x19 */ /* mod 9 (divide by 10) prescale */ +#define CLOCK_PRESC 0x19 /* mod 9 (divide by 10) prescale */ #define BRD50 4607 #define BRD75 3071 #define BRD110 2094 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/rtc.c linux-2.5/drivers/char/rtc.c --- linux-2.5.5/drivers/char/rtc.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/char/rtc.c Tue Feb 26 21:24:48 2002 @@ -41,9 +41,11 @@ * 1.10c Cesar Barros: SMP locking fixes and cleanup * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness. + * 1.11 Takashi Iwai: Kernel access functions + * rtc_register/rtc_unregister/rtc_control */ -#define RTC_VERSION "1.10e" +#define RTC_VERSION "1.11" #define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */ @@ -139,6 +141,11 @@ static unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ static unsigned long rtc_irq_data = 0; /* our output to the world */ +#if RTC_IRQ +static spinlock_t rtc_task_lock = SPIN_LOCK_UNLOCKED; +static rtc_task_t *rtc_callback = NULL; +#endif + /* * If this driver ever becomes modularised, it will be really nice * to make the epoch retain its value across module reload... @@ -180,6 +187,10 @@ spin_unlock (&rtc_lock); /* Now do the rest of the actions */ + spin_lock(&rtc_task_lock); + if (rtc_callback) + rtc_callback->func(rtc_callback->private_data); + spin_unlock(&rtc_task_lock); wake_up_interruptible(&rtc_wait); kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); @@ -244,8 +255,7 @@ #endif } -static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) { struct rtc_time wtime; @@ -295,7 +305,7 @@ * We don't really want Joe User enabling more * than 64Hz of interrupts on a multi-user machine. */ - if ((rtc_freq > 64) && (!capable(CAP_SYS_RESOURCE))) + if (!kernel && (rtc_freq > 64) && (!capable(CAP_SYS_RESOURCE))) return -EACCES; if (!(rtc_status & RTC_TIMER_ON)) { @@ -493,7 +503,7 @@ * We don't really want Joe User generating more * than 64Hz of interrupts on a multi-user machine. */ - if ((arg > 64) && (!capable(CAP_SYS_RESOURCE))) + if (!kernel && (arg > 64) && (!capable(CAP_SYS_RESOURCE))) return -EACCES; while (arg > (1<func == NULL) + return -EINVAL; + spin_lock_irq(&rtc_lock); + if (rtc_status & RTC_IS_OPEN) { + spin_unlock_irq(&rtc_lock); + return -EBUSY; + } + spin_lock(&rtc_task_lock); + if (rtc_callback) { + spin_unlock(&rtc_task_lock); + spin_unlock_irq(&rtc_lock); + return -EBUSY; + } + rtc_status |= RTC_IS_OPEN; + rtc_callback = task; + spin_unlock(&rtc_task_lock); + spin_unlock_irq(&rtc_lock); + return 0; +#endif +} + +int rtc_unregister(rtc_task_t *task) +{ +#if !RTC_IRQ + return -EIO; +#else + unsigned char tmp; + + spin_lock_irq(&rtc_task_lock); + if (rtc_callback != task) { + spin_unlock_irq(&rtc_task_lock); + return -ENXIO; + } + rtc_callback = NULL; + spin_lock(&rtc_lock); + /* disable controls */ + tmp = CMOS_READ(RTC_CONTROL); + tmp &= ~RTC_PIE; + tmp &= ~RTC_AIE; + tmp &= ~RTC_UIE; + CMOS_WRITE(tmp, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + if (rtc_status & RTC_TIMER_ON) { + rtc_status &= ~RTC_TIMER_ON; + del_timer(&rtc_irq_timer); + } + rtc_status &= ~RTC_IS_OPEN; + spin_unlock(&rtc_lock); + spin_unlock_irq(&rtc_task_lock); + return 0; +#endif +} + +int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) +{ +#if !RTC_IRQ + return -EIO; +#else + spin_lock_irq(&rtc_task_lock); + if (rtc_callback != task) { + spin_unlock_irq(&rtc_task_lock); + return -ENXIO; + } + spin_unlock_irq(&rtc_task_lock); + return rtc_do_ioctl(cmd, arg, 1); +#endif +} + + +/* * The various file operations we support. */ @@ -822,7 +917,6 @@ module_init(rtc_init); module_exit(rtc_exit); -EXPORT_NO_SYMBOLS; #if RTC_IRQ /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/sb1250_duart.c linux-2.5/drivers/char/sb1250_duart.c --- linux-2.5.5/drivers/char/sb1250_duart.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/sb1250_duart.c Mon Mar 4 01:50:47 2002 @@ -0,0 +1,805 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/* + * Driver support for the on-chip sb1250 dual-channel serial port, + * running in asynchronous mode. Also, support for doing a serial console + * on one of those ports + * + * The non-console part of this code is based heavily on the serial_21285.c + * driver also in this directory. See tty_driver.h for a description of some + * of the driver functions, though it (like most of the inline code documentation :) + * is a bit out of date. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Toggle spewing of debugging output */ +#undef DUART_SPEW + +#define DEFAULT_CFLAGS (CS8 | B115200) + + +/* + Still not sure what the termios structures set up here are for, + but we have to supply pointers to them to register the tty driver +*/ + +static struct tty_driver sb1250_duart_driver, sb1250_duart_callout_driver; +static int ref_count; +static struct tty_struct *duart_table[2]; +static struct termios *duart_termios[2]; +static struct termios *duart_termios_locked[2]; + +/* This lock protects both the open flags for all the uart states as + well as the reference count for the module */ +static spinlock_t open_lock = SPIN_LOCK_UNLOCKED; + +/* Protect the writing stuff from contention */ +//static spinlock_t console_lock = SPIN_LOCK_UNLOCKED; + +/* Bit fields of flags in the flags field below */ + +#define SD_WRITE_WAKE 0x000000001 + + +typedef struct { + struct tty_struct *tty; + unsigned char outp_buf[CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE]; + unsigned int outp_head; + unsigned int outp_tail; + unsigned int outp_count; + spinlock_t outp_lock; + unsigned int outp_stopped; + unsigned int open; + unsigned long flags; + unsigned int last_cflags; +} uart_state_t; + +static uart_state_t uart_states[2] = { [0 ... 1] = { + tty: 0, + outp_head: 0, + outp_tail: 0, + outp_lock: SPIN_LOCK_UNLOCKED, + outp_count: 0, + open: 0, + flags: 0, + last_cflags: 0, +}}; + +/* + * Inline functions local to this module + */ + + +/* + * Mask out the passed interrupt lines at the duart level. This should be + * called while holding the associated outp_lock. + */ +static inline void duart_mask_ints(unsigned int line, unsigned int mask) +{ + u64 tmp; + tmp = in64(IO_SPACE_BASE | A_DUART_IMRREG(line)); + tmp &= ~mask; + out64(tmp, IO_SPACE_BASE | A_DUART_IMRREG(line)); +} + + +/* Unmask the passed interrupt lines at the duart level */ +static inline void duart_unmask_ints(unsigned int line, unsigned int mask) +{ + u64 tmp; + tmp = in64(IO_SPACE_BASE | A_DUART_IMRREG(line)); + tmp |= mask; + out64(tmp, IO_SPACE_BASE | A_DUART_IMRREG(line)); +} + +static inline unsigned long get_status_reg(unsigned int line) +{ + return in64(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_STATUS)); +} + +/* Derive which uart a call is for from the passed tty line. */ +static inline unsigned int get_line(struct tty_struct *tty) +{ + unsigned int line = minor(tty->device) - 64; + if (line > 1) + printk(KERN_CRIT "Invalid line\n"); + + return line; +} + + + +#define MIN(a, b) (((a)<(b))?(a):(b)) + +/* + * Generic interrupt handler for both channels. dev_id is a pointer + * to the proper uart_states structure, so from that we can derive + * which port interrupted + */ + +static void duart_int(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int line; + uart_state_t *us = (uart_state_t *)dev_id; + line = us-uart_states; +#ifdef DUART_SPEW +// setleds("INT!"); + printk("DUART INT\n"); +#endif + /* We could query the ISR to figure out why we are here, but since + we are here, we may as well just take care of both rx and tx */ + spin_lock(&us->outp_lock); + if (get_status_reg(line) & M_DUART_RX_RDY) { + do { + unsigned int status = get_status_reg(line); + unsigned int ch = in64(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_RX_HOLD)); + unsigned int flag = 0; + if (status & 0x10) { + tty_insert_flip_char(us->tty, 0, TTY_OVERRUN); } + if (status & 0x20) { + printk("Parity error!\n"); + flag = TTY_PARITY; + } else if (status & 0x40) { + printk("Frame error!\n"); + flag = TTY_FRAME; + } + tty_insert_flip_char(us->tty, ch, flag); + } while (get_status_reg(line) & M_DUART_RX_RDY); + tty_flip_buffer_push(us->tty); + } + if ((get_status_reg(line) & M_DUART_TX_RDY) && us->outp_count) { + do { + out64(us->outp_buf[us->outp_head], IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_TX_HOLD)); + us->outp_head = (us->outp_head + 1) & (CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE-1); + us->outp_count--; + } while ((get_status_reg(line) & M_DUART_TX_RDY) && us->outp_count); + + if (us->open && (us->flags & SD_WRITE_WAKE) && + (us->outp_count < (CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE/2))) { + /* We told the discipline at one point that we had no space, so it went + to sleep. Wake it up when we hit half empty */ + wake_up_interruptible(&us->tty->write_wait); + } + if (!us->outp_count) { + duart_mask_ints(line, M_DUART_IMR_TX); + } + } + spin_unlock(&us->outp_lock); +} + +/* + * Actual driver functions + */ + +/* Return the number of characters we can accomodate in a write at this instant */ +static int duart_write_room(struct tty_struct *tty) +{ + unsigned long flags; + int retval; + uart_state_t *us = &uart_states[get_line(tty)]; + + spin_lock_irqsave(&us->outp_lock, flags); + retval = CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE - uart_states[get_line(tty)].outp_count; + if (!retval) { + us->flags |= SD_WRITE_WAKE; + } + spin_unlock_irqrestore(&us->outp_lock, flags); +#ifdef DUART_SPEW + printk("duart_write_room called, returning %i\n", retval); +#endif + return retval; +} + +/* memcpy the data from src to destination, but take extra care if the + data is coming from user space */ +static inline int copy_buf(char *dest, const char *src, int size, int from_user) +{ + if (from_user) { + (void) copy_from_user(dest, src, size); + } else { + memcpy(dest, src, size); + } + return size; +} + +/* Buffer up to count characters from buf to be written. If we don't have other + characters buffered, enable the tx interrupt to start sending */ +static int duart_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + uart_state_t *us; + unsigned long flags; + unsigned int line; + int chars_written = 0; + if (from_user && verify_area(VERIFY_READ, buf, count)) { + return -EINVAL; + } +#ifdef DUART_SPEW + printk("duart_write called for %i chars by %i (%s)\n", count, current->pid, current->comm); +#endif + line = get_line(tty); + us = &uart_states[line]; + spin_lock_irqsave(&us->outp_lock, flags); + if (!count || (us->outp_count == CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE)) { + spin_unlock_irqrestore(&us->outp_lock, flags); + return 0; + } + if (us->outp_tail < us->outp_head) { + /* Straightforward case; copy from tail to head */ + chars_written += copy_buf(us->outp_buf + us->outp_tail, buf, + MIN(count, us->outp_head - us->outp_tail), from_user); + } else { + /* Copy from tail to end of buffer, wrap around and then + copy to head */ + chars_written += copy_buf(us->outp_buf + us->outp_tail, buf, + MIN(CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE - us->outp_tail, count), + from_user); + if (chars_written < count) { + chars_written += copy_buf(us->outp_buf, buf + chars_written, + MIN(us->outp_head, count - chars_written), from_user); + } + } + us->outp_tail = (us->outp_tail + chars_written) &(CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE-1); + if (!(us->outp_count || us->outp_stopped)) { + duart_unmask_ints(line, M_DUART_IMR_TX); + } + us->outp_count += chars_written; + spin_unlock_irqrestore(&us->outp_lock, flags); + return chars_written; +} + + +/* Buffer one character to be written. If there's not room for it, just drop + it on the floor. This is used for echo, among other things */ +static void duart_put_char(struct tty_struct *tty, u_char ch) +{ + unsigned long flags; + unsigned int line = get_line(tty); + uart_state_t *us = &uart_states[line]; +#ifdef DUART_SPEW + printk("duart_put_char called. Char is %x (%c)\n", (int)ch, ch); +#endif + spin_lock_irqsave(&us->outp_lock, flags); + if (us->outp_count != CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE) { + us->outp_buf[us->outp_tail] = ch; + us->outp_tail = (us->outp_tail + 1) &(CONFIG_SB1250_DUART_OUTPUT_BUF_SIZE-1); + if (!(us->outp_count || us->outp_stopped)) { + duart_unmask_ints(line, M_DUART_IMR_TX); + } + us->outp_count++; + } + spin_unlock_irqrestore(&us->outp_lock, flags); +} + +/* Return the number of characters in the output buffer that have yet to be + written */ +static int duart_chars_in_buffer(struct tty_struct *tty) +{ + int retval; + unsigned long flags; + uart_state_t *us = &uart_states[get_line(tty)]; + spin_lock_irqsave(&us->outp_lock, flags); + retval = us->outp_count; + if (retval) { + us->flags |= SD_WRITE_WAKE; + } + spin_unlock_irqrestore(&us->outp_lock, flags); +#ifdef DUART_SPEW + printk("duart_chars_in_buffer returning %i\n", retval); +#endif + return retval; +} + +/* Kill everything we haven't yet shoved into the FIFO. Turn off the + transmit interrupt since we've nothing more to transmit */ +static void duart_flush_buffer(struct tty_struct *tty) +{ + unsigned long flags; + unsigned int line = get_line(tty); + uart_state_t *us = &uart_states[get_line(tty)]; +#ifdef DUART_SPEW + printk("duart_flush_buffer called\n"); +#endif + duart_mask_ints(line, M_DUART_IMR_TX); + spin_lock_irqsave(&us->outp_lock, flags); + us->outp_head = us->outp_tail = us->outp_count = 0; + if (us->flags & SD_WRITE_WAKE) { + wake_up_interruptible(&us->tty->write_wait); + } + spin_unlock_irqrestore(&us->outp_lock, flags); +} + + +/* See sb1250 user manual for details on these registers */ +static inline void duart_set_cflag(unsigned int line, unsigned int cflag) +{ + unsigned int mode_reg1 = 0, mode_reg2 = 0; + unsigned int clk_divisor; + switch (cflag & CSIZE) { + case CS7: + mode_reg1 |= V_DUART_BITS_PER_CHAR_7; + + default: + /* We don't handle CS5 or CS6...is there a way we're supposed to flag this? + right now we just force them to CS8 */ + mode_reg1 |= 0x0; + break; + } + if (cflag & CSTOPB) { + mode_reg2 |= M_DUART_STOP_BIT_LEN_2; /* XXX was: 0x4; */ + } + if (!(cflag & PARENB)) { + mode_reg1 |= V_DUART_PARITY_MODE_NONE; /* XXX was: 0x8; */ + } + if (cflag & PARODD) { + mode_reg1 |= M_DUART_PARITY_TYPE_ODD; + } + + /* Formula for this is (5000000/baud)-1, but we saturate + at 12 bits, which means we can't actually do anything less + that 1200 baud */ + switch (cflag & CBAUD) { + case B200: + case B300: + case B1200: clk_divisor = 4095; break; + case B1800: clk_divisor = 2776; break; + case B2400: clk_divisor = 2082; break; + case B4800: clk_divisor = 1040; break; + default: + case B9600: clk_divisor = 519; break; + case B19200: clk_divisor = 259; break; + case B38400: clk_divisor = 129; break; + case B57600: clk_divisor = 85; break; + case B115200: clk_divisor = 42; break; + } + out64(mode_reg1, IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_MODE_REG_1)); + out64(mode_reg2, IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_MODE_REG_2)); + out64(clk_divisor, IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_CLK_SEL)); + uart_states[line].last_cflags = cflag; +} + + +/* Handle notification of a termios change. */ +static void duart_set_termios(struct tty_struct *tty, struct termios *old) +{ +#ifdef DUART_SPEW + printk("duart_set_termios called by %i (%s)\n", current->pid, current->comm); +#endif + if (old && tty->termios->c_cflag == old->c_cflag) + return; + duart_set_cflag(get_line(tty), tty->termios->c_cflag); +} + +/* Stop pushing stuff into the fifo, now. Do the mask under the + outp_lock to avoid races involving turning the interrupt line on/off */ +static void duart_stop(struct tty_struct *tty) +{ + unsigned long flags; + unsigned int line = get_line(tty); + uart_state_t *us = &uart_states[line]; +#ifdef DUART_SPEW + printk("duart_stop called\n"); +#endif + spin_lock_irqsave(&us->outp_lock, flags); + duart_mask_ints(get_line(tty), M_DUART_IMR_TX); + us->outp_stopped = 1; + spin_unlock_irqrestore(&us->outp_lock, flags); +} + +static int duart_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ +/* if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV;*/ + switch (cmd) { + case TIOCMGET: + printk("Ignoring TIOCMGET\n"); + break; + case TIOCMBIS: + printk("Ignoring TIOCMBIS\n"); + break; + case TIOCMBIC: + printk("Ignoring TIOCMBIC\n"); + break; + case TIOCMSET: + printk("Ignoring TIOCMSET\n"); + break; + case TIOCGSERIAL: + printk("Ignoring TIOCGSERIAL\n"); + break; + case TIOCSSERIAL: + printk("Ignoring TIOCSSERIAL\n"); + break; + case TIOCSERCONFIG: + printk("Ignoring TIOCSERCONFIG\n"); + break; + case TIOCSERGETLSR: /* Get line status register */ + printk("Ignoring TIOCSERGETLSR\n"); + break; + case TIOCSERGSTRUCT: + printk("Ignoring TIOCSERGSTRUCT\n"); + break; + case TIOCMIWAIT: + printk("Ignoring TIOCMIWAIT\n"); + break; + case TIOCGICOUNT: + printk("Ignoring TIOCGICOUNT\n"); + break; + case TIOCSERGWILD: + printk("Ignoring TIOCSERGWILD\n"); + break; + case TIOCSERSWILD: + printk("Ignoring TIOCSERSWILD\n"); + break; + default: + break; + } +// printk("Ignoring IOCTL %x from pid %i (%s)\n", cmd, current->pid, current->comm); + return -ENOIOCTLCMD; +#if 0 + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + case TIOCGSERIAL: + case TIOCSSERIAL: + case TIOCSERCONFIG: + case TIOCSERGETLSR: /* Get line status register */ + case TIOCSERGSTRUCT: + case TIOCMIWAIT: + case TIOCGICOUNT: + case TIOCSERGWILD: + case TIOCSERSWILD: + /* XXX Implement me! */ + printk("IOCTL needs implementing: %x\n", cmd); + + default: + printk("Unknown ioctl: %x\n", cmd); + } +#endif + return 0; +} + +/* Stop pushing stuff into the fifo, now. Do the mask under the + outp_lock to avoid races involving turning the interrupt line on/off */ +static void duart_start(struct tty_struct *tty) +{ + unsigned long flags; + unsigned int line = get_line(tty); + uart_state_t *us = &uart_states[line]; +#ifdef DUART_SPEW + printk("duart_start called\n"); +#endif + spin_lock_irqsave(&us->outp_lock, flags); + if (us->outp_count) { + duart_unmask_ints(get_line(tty), M_DUART_IMR_TX); + } + us->outp_stopped = 0; + spin_unlock_irqrestore(&us->outp_lock, flags); +} + +/* Not sure on the semantics of this; are we supposed to wait until the stuff + already in the hardware FIFO drains, or are we supposed to wait until + we've drained the output buffer, too? I'm assuming the former, 'cause thats + what the other drivers seem to assume +*/ + +static void duart_wait_until_sent(struct tty_struct *tty, int timeout) +{ + unsigned long target_time; + unsigned int line; + uart_state_t *us; +#ifdef DUART_SPEW + printk("duart_wait_until_sent(%d)+\n", timeout); +#endif + target_time = jiffies + timeout; + line = get_line(tty); + us = &uart_states[line]; + while (!(get_status_reg(line) & M_DUART_TX_EMT) && (jiffies < target_time)) { + schedule_timeout(1); + } +#ifdef DUART_SPEW + printk("duart_wait_until_sent()-\n"); +#endif +} + +/* + * Open a tty line. Note that this can be called multiple times, so ->open can + * be >1. Only set up the tty struct if this is a "new" open, e.g. ->open was + * zero + */ +static int duart_open(struct tty_struct *tty, struct file *filp) +{ + unsigned long flags; + unsigned int line; + uart_state_t *us; + + MOD_INC_USE_COUNT; +#ifndef CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1 + if (get_line(tty) > 1) +#else + if (get_line(tty) > 0) +#endif + { + MOD_DEC_USE_COUNT; + return -ENODEV; + } +#ifdef DUART_SPEW + printk("duart_open called by %i (%s), tty is %p, rw is %p, ww is %p\n", current->pid, current->comm, tty, + tty->read_wait, tty->write_wait); +#endif + line = get_line(tty); + tty->driver_data = NULL; + us = &uart_states[line]; + + spin_lock_irqsave(&open_lock, flags); + if (!us->open) { + us->tty = tty; + us->tty->termios->c_cflag = us->last_cflags; + } + us->open++; +#ifdef FORCED_INPUT + if (!line && (us->open == 1)) { + next_inp = inp_cmds; + init_timer(&inp_timer); + inp_timer.expires = jiffies + 20; + inp_timer.data = 0; + inp_timer.function = stuff_char; + stuff_char_tty = tty; + add_timer(&inp_timer); + } +#endif + duart_unmask_ints(line, M_DUART_IMR_RX); + spin_unlock_irqrestore(&open_lock, flags); + return 0; +} + + +/* + * Close a reference count out. If reference count hits zero, null the + * tty, kill the interrupts. The tty_io driver is responsible for making + * sure we've cleared out our internal buffers before calling close() + */ +static void duart_close(struct tty_struct *tty, struct file *filp) +{ + unsigned long flags; + unsigned int line = get_line(tty); + uart_state_t *us = &uart_states[line]; +#ifdef DUART_SPEW + printk("duart_close called by %i (%s)\n", current->pid, current->comm); +#endif + spin_lock_irqsave(&open_lock, flags); + us->open--; +#if 0 + if (!us->open) { + /* Flushing TX stuff here is conservative */ + duart_mask_ints(line, M_DUART_IMR_IN | M_DUART_IMR_BRK | M_DUART_IMR_RX | M_DUART_IMR_TX); + spin_lock(&us->outp_lock); + us->outp_head = us->outp_tail = us->outp_count = us->outp_stopped = 0; + us->tty = NULL; + spin_unlock(&us->outp_lock); + } +#endif + ref_count--; + spin_unlock_irqrestore(&open_lock, flags); + MOD_DEC_USE_COUNT; +} + + +/* Set up the driver and register it, register the 2 1250 UART interrupts. This + is called from tty_init, or as a part of the module init */ +static int __init sb1250_duart_init(void) +{ + sb1250_duart_driver.magic = TTY_DRIVER_MAGIC; + sb1250_duart_driver.driver_name = "serial"; +#ifdef CONFIG_DEVFS_FS + sb1250_duart_driver.name = "tts/%d"; +#else + sb1250_duart_driver.name = "ttyS"; +#endif + sb1250_duart_driver.major = TTY_MAJOR; + sb1250_duart_driver.minor_start = 64; + sb1250_duart_driver.num = 2; + sb1250_duart_driver.type = TTY_DRIVER_TYPE_SERIAL; + sb1250_duart_driver.subtype = SERIAL_TYPE_NORMAL; + sb1250_duart_driver.init_termios = tty_std_termios; + sb1250_duart_driver.flags = TTY_DRIVER_REAL_RAW; + sb1250_duart_driver.refcount = &ref_count; + sb1250_duart_driver.table = duart_table; + sb1250_duart_driver.termios = duart_termios; + sb1250_duart_driver.termios_locked = duart_termios_locked; + + sb1250_duart_driver.open = duart_open; + sb1250_duart_driver.close = duart_close; + sb1250_duart_driver.write = duart_write; + sb1250_duart_driver.put_char = duart_put_char; + sb1250_duart_driver.write_room = duart_write_room; + sb1250_duart_driver.chars_in_buffer = duart_chars_in_buffer; + sb1250_duart_driver.flush_buffer = duart_flush_buffer; + sb1250_duart_driver.ioctl = duart_ioctl; + sb1250_duart_driver.set_termios = duart_set_termios; + sb1250_duart_driver.stop = duart_stop; + sb1250_duart_driver.start = duart_start; + sb1250_duart_driver.wait_until_sent = duart_wait_until_sent; + + sb1250_duart_callout_driver = sb1250_duart_driver; +#ifdef CONFIG_DEVFS_FS + sb1250_duart_callout_driver.name = "cua/%d"; +#else + sb1250_duart_callout_driver.name = "cua"; +#endif + sb1250_duart_callout_driver.major = TTYAUX_MAJOR; + sb1250_duart_callout_driver.subtype = SERIAL_TYPE_CALLOUT; + + duart_mask_ints(0, 0xf); + if (request_irq(K_INT_UART_0, duart_int, 0, "uart0", &uart_states[0])) { + panic("Couldn't get uart0 interrupt line"); + } +#ifndef CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1 + duart_mask_ints(1, 0xf); + if (request_irq(K_INT_UART_1, duart_int, 0, "uart1", &uart_states[1])) { + panic("Couldn't get uart1 interrupt line"); + } +#endif + + /* Interrupts are now active, our ISR can be called. */ + + if (tty_register_driver(&sb1250_duart_driver)) { + printk(KERN_ERR "Couldn't register sb1250 duart serial driver\n"); + } + if (tty_register_driver(&sb1250_duart_callout_driver)) { + printk(KERN_ERR "Couldn't register sb1250 duart callout driver\n"); + } + duart_set_cflag(0, DEFAULT_CFLAGS); +#ifndef CONFIG_SIBYTE_SB1250_DUART_NO_PORT_1 + duart_set_cflag(1, DEFAULT_CFLAGS); +#endif + return 0; +} + +/* Unload the driver. Unregister stuff, get ready to go away */ +static void __exit sb1250_duart_fini(void) +{ + unsigned long flags; + int ret; + + save_flags(flags); + cli(); + ret = tty_unregister_driver(&sb1250_duart_callout_driver); + if (ret) { + printk(KERN_ERR "Unable to unregister sb1250 duart callout driver (%d)\n", ret); + } + ret = tty_unregister_driver(&sb1250_duart_driver); + if (ret) { + printk(KERN_ERR "Unable to unregister sb1250 duart serial driver (%d)\n", ret); + } + free_irq(K_INT_UART_0, &uart_states[0]); + free_irq(K_INT_UART_1, &uart_states[1]); + + /* mask lines in the scd */ + disable_irq(K_INT_UART_0); + disable_irq(K_INT_UART_1); + + restore_flags(flags); +} + +module_init(sb1250_duart_init); +module_exit(sb1250_duart_fini); +MODULE_DESCRIPTION("SB1250 Duart serial driver"); +MODULE_AUTHOR("Justin Carlson "); + +#ifdef CONFIG_SERIAL_CONSOLE + +/* + * Serial console stuff. + * Very basic, polling driver for doing serial console output. + * FIXME; there is a race here; we can't be sure that + * the tx is still empty without holding outp_lock for this line. + * Worst that can happen for now, though, is dropped characters. + */ + +static void ser_console_write(struct console *cons, const char *str, + unsigned int count) +{ + unsigned int i; + unsigned long flags; + spin_lock_irqsave(&uart_states[0].outp_lock, flags); + + for (i = 0; i < count; i++) { + if (str[i] == '\n') { + /* Expand LF -> CRLF */ + while (!(get_status_reg(0) & M_DUART_TX_RDY)) { + /* Spin, doing nothing. */ + } + out64('\r', IO_SPACE_BASE | A_DUART_CHANREG(0, R_DUART_TX_HOLD)); + } + while (!(get_status_reg(0) & M_DUART_TX_RDY)) { + /* Spin, doing nothing. */ + } + out64(str[i], IO_SPACE_BASE | A_DUART_CHANREG(0, R_DUART_TX_HOLD)); + } + spin_unlock_irqrestore(&uart_states[0].outp_lock, flags); +} + +static kdev_t ser_console_device(struct console *c) +{ + return mk_kdev(TTY_MAJOR, 64 + c->index); +} + +static int ser_console_wait_key(struct console *cons) +{ + panic("ser_console_wait_key called"); +} + +static int ser_console_setup(struct console *cons, char *str) +{ + /* Initialize the transmitter */ + + duart_set_cflag(0, DEFAULT_CFLAGS); + return 0; +} + +static struct console sb1250_ser_cons = { + name: "ttyS", + write: ser_console_write, + device: ser_console_device, + wait_key: ser_console_wait_key, + setup: ser_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +void __init sb1250_serial_console_init(void) +{ + register_console(&sb1250_ser_cons); +} + +#endif /* CONFIG_SERIAL_CONSOLE */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/sbc60xxwdt.c linux-2.5/drivers/char/sbc60xxwdt.c --- linux-2.5.5/drivers/char/sbc60xxwdt.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/char/sbc60xxwdt.c Sun Jan 13 22:15:01 2002 @@ -109,6 +109,15 @@ static int wdt_is_open; static int wdt_expect_close; +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + /* * Whack the dog */ @@ -202,6 +211,9 @@ /* Just in case we're already talking to someone... */ if(wdt_is_open) return -EBUSY; + if (nowayout) { + MOD_INC_USE_COUNT; + } /* Good, fire up the show */ wdt_is_open = 1; wdt_startup(); @@ -216,7 +228,7 @@ { if(minor(inode->i_rdev) == WATCHDOG_MINOR) { - if(wdt_expect_close) + if(wdt_expect_close && !nowayout) wdt_turnoff(); else { del_timer(&timer); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/selection.c linux-2.5/drivers/char/selection.c --- linux-2.5.5/drivers/char/selection.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/char/selection.c Mon Feb 25 18:54:26 2002 @@ -22,7 +22,6 @@ #include #include -#include #include #ifndef MIN @@ -32,8 +31,6 @@ /* Don't take this from : 011-015 on the screen aren't spaces */ #define isspace(c) ((c) == ' ') -extern void poke_blanked_console(void); - /* Variables for selection control. */ /* Use a dynamic buffer, instead of static (Dec 1994) */ int sel_cons; /* must not be disallocated */ @@ -48,19 +45,31 @@ /* set reverse video on characters s-e of console with selection. */ inline static void highlight(const int s, const int e) { - invert_screen(sel_cons, s, e-s+2, 1); + invert_screen(vt_cons->vc_cons[sel_cons], s, e-s+2, 1); } /* use complementary color to show the pointer */ inline static void highlight_pointer(const int where) { - complement_pos(sel_cons, where); + complement_pos(vt_cons->vc_cons[sel_cons], where); +} + +u16 screen_glyph(struct vc_data *vc, int offset) +{ + u16 w = scr_readw(screenpos(vc, offset, 1)); + u16 c = w & 0xff; + + if (w & vc->vc_hi_font_mask) + c |= 0x100; + return c; } static unsigned char sel_pos(int n) { - return inverse_translate(vc_cons[sel_cons].d, screen_glyph(sel_cons, n)); + struct vc_data *vc = vt_cons->vc_cons[sel_cons]; + + return inverse_translate(vc, screen_glyph(vc, n)); } /* remove the current selection highlight, if any, @@ -114,13 +123,13 @@ /* set the current selection. Invoked by ioctl() or by kernel code. */ int set_selection(const unsigned long arg, struct tty_struct *tty, int user) { + struct vc_data *vc = vt_cons->vc_cons[fg_console]; int sel_mode, new_sel_start, new_sel_end, spc; char *bp, *obp; int i, ps, pe; - unsigned int currcons = fg_console; unblank_screen(); - poke_blanked_console(); + poke_blanked_console(vc->display_fg); { unsigned short *args, xs, ys, xe, ye; @@ -141,12 +150,12 @@ sel_mode = *args; } xs--; ys--; xe--; ye--; - xs = limit(xs, video_num_columns - 1); - ys = limit(ys, video_num_lines - 1); - xe = limit(xe, video_num_columns - 1); - ye = limit(ye, video_num_lines - 1); - ps = ys * video_size_row + (xs << 1); - pe = ye * video_size_row + (xe << 1); + xs = limit(xs, vc->vc_cols - 1); + ys = limit(ys, vc->vc_rows - 1); + xe = limit(xe, vc->vc_cols - 1); + ye = limit(ye, vc->vc_rows - 1); + ps = ys * vc->vc_size_row + (xs << 1); + pe = ye * vc->vc_size_row + (xe << 1); if (sel_mode == 4) { /* useful for screendump without selection highlights */ @@ -154,7 +163,7 @@ return 0; } - if (mouse_reporting() && (sel_mode & 16)) { + if (mouse_reporting(vc) && (sel_mode & 16)) { mouse_report(tty, sel_mode & 15, xs, ys); return 0; } @@ -186,7 +195,7 @@ (!spc && !inword(sel_pos(ps)))) break; new_sel_start = ps; - if (!(ps % video_size_row)) + if (!(ps % vc->vc_size_row)) break; } spc = isspace(sel_pos(pe)); @@ -196,14 +205,14 @@ (!spc && !inword(sel_pos(pe)))) break; new_sel_end = pe; - if (!((pe + 2) % video_size_row)) + if (!((pe + 2) % vc->vc_size_row)) break; } break; case 2: /* line-by-line selection */ - new_sel_start = ps - ps % video_size_row; - new_sel_end = pe + video_size_row - - pe % video_size_row - 2; + new_sel_start = ps - ps % vc->vc_size_row; + new_sel_end = pe + vc->vc_size_row + - pe % vc->vc_size_row - 2; break; case 3: highlight_pointer(pe); @@ -217,11 +226,11 @@ /* select to end of line if on trailing space */ if (new_sel_end > new_sel_start && - !atedge(new_sel_end, video_size_row) && + !atedge(new_sel_end, vc->vc_size_row) && isspace(sel_pos(new_sel_end))) { for (pe = new_sel_end + 2; ; pe += 2) if (!isspace(sel_pos(pe)) || - atedge(pe, video_size_row)) + atedge(pe, vc->vc_size_row)) break; if (isspace(sel_pos(pe))) new_sel_end = pe; @@ -268,7 +277,7 @@ *bp = sel_pos(i); if (!isspace(*bp++)) obp = bp; - if (! ((i + 2) % video_size_row)) { + if (! ((i + 2) % vc->vc_size_row)) { /* strip trailing blanks from line and add newline, unless non-space at end of line. */ if (obp != bp) { @@ -288,12 +297,12 @@ */ int paste_selection(struct tty_struct *tty) { - struct vt_struct *vt = (struct vt_struct *) tty->driver_data; + struct vc_data *vc = (struct vc_data *) tty->driver_data; int pasted = 0, count; DECLARE_WAITQUEUE(wait, current); - poke_blanked_console(); - add_wait_queue(&vt->paste_wait, &wait); + poke_blanked_console(vc->display_fg); + add_wait_queue(&vc->paste_wait, &wait); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); if (test_bit(TTY_THROTTLED, &tty->flags)) { @@ -305,7 +314,7 @@ tty->ldisc.receive_buf(tty, sel_buffer + pasted, 0, count); pasted += count; } - remove_wait_queue(&vt->paste_wait, &wait); + remove_wait_queue(&vc->paste_wait, &wait); current->state = TASK_RUNNING; return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/serial.c linux-2.5/drivers/char/serial.c --- linux-2.5.5/drivers/char/serial.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/char/serial.c Sun Mar 3 23:50:41 2002 @@ -57,6 +57,11 @@ * 10/00: add in optional software flow control for serial console. * Kanoj Sarcar (Modified by Theodore Ts'o) * + * 02/02: Fix for AMD Elan bug in transmit irq routine, by + * Christer Weinigel , + * Robert Schwebel , + * Juergen Beisert , + * Theodore Ts'o */ static char *serial_version = "5.05c"; @@ -122,11 +127,6 @@ #define ENABLE_SERIAL_ACPI #endif -#ifdef __ISAPNP__ -#ifndef ENABLE_SERIAL_PNP -#define ENABLE_SERIAL_PNP -#endif -#endif /* Set of debugging defines */ @@ -198,6 +198,7 @@ #include #include #include +#include #if (LINUX_VERSION_CODE >= 131343) #include #endif @@ -211,9 +212,14 @@ #ifdef ENABLE_SERIAL_PCI #include #endif -#ifdef ENABLE_SERIAL_PNP + #include +#ifdef __ISAPNP__ +#ifndef ENABLE_SERIAL_PNP +#define ENABLE_SERIAL_PNP #endif +#endif + #ifdef CONFIG_MAGIC_SYSRQ #include #endif @@ -231,8 +237,8 @@ #include #include -#ifdef CONFIG_MAC_SERIAL -#define SERIAL_DEV_OFFSET 2 +#if defined(CONFIG_MAC_SERIAL) +#define SERIAL_DEV_OFFSET ((_machine == _MACH_prep || _machine == _MACH_chrp) ? 0 : 2) #else #define SERIAL_DEV_OFFSET 0 #endif @@ -645,7 +651,7 @@ if (break_pressed && info->line == sercons.index) { if (ch != 0 && time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); break_pressed = 0; goto ignore_char; } @@ -801,7 +807,7 @@ */ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) { - int status; + int status, iir; struct async_struct * info; int pass_counter = 0; struct async_struct *end_mark = 0; @@ -826,7 +832,7 @@ do { if (!info->tty || - (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) { + ((iir=serial_in(info, UART_IIR)) & UART_IIR_NO_INT)) { if (!end_mark) end_mark = info; goto next; @@ -845,7 +851,9 @@ if (status & UART_LSR_DR) receive_chars(info, &status, regs); check_modem_status(info); - if (status & UART_LSR_THRE) + if ((status & UART_LSR_THRE) || + /* for buggy ELAN processors */ + ((iir & UART_IIR_ID) == UART_IIR_THRI)) transmit_chars(info, 0); next: @@ -879,7 +887,7 @@ */ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) { - int status; + int status, iir; int pass_counter = 0; struct async_struct * info; #ifdef CONFIG_SERIAL_MULTIPORT @@ -901,6 +909,7 @@ first_multi = inb(multi->port_monitor); #endif + iir = serial_in(info, UART_IIR); do { status = serial_inp(info, UART_LSR); #ifdef SERIAL_DEBUG_INTR @@ -909,18 +918,21 @@ if (status & UART_LSR_DR) receive_chars(info, &status, regs); check_modem_status(info); - if (status & UART_LSR_THRE) + if ((status & UART_LSR_THRE) || + /* For buggy ELAN processors */ + ((iir & UART_IIR_ID) == UART_IIR_THRI)) transmit_chars(info, 0); if (pass_counter++ > RS_ISR_PASS_LIMIT) { -#if 0 +#if SERIAL_DEBUG_INTR printk("rs_single loop break.\n"); #endif break; } + iir = serial_in(info, UART_IIR); #ifdef SERIAL_DEBUG_INTR - printk("IIR = %x...", serial_in(info, UART_IIR)); + printk("IIR = %x...", iir); #endif - } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); + } while ((iir & UART_IIR_NO_INT) == 0); info->last_active = jiffies; #ifdef CONFIG_SERIAL_MULTIPORT if (multi->port_monitor) @@ -1210,7 +1222,7 @@ if (!page) return -ENOMEM; - save_flags(flags); cli(); + spin_lock_irqsave( &info->irq_spinlock, flags); if (info->flags & ASYNC_INITIALIZED) { free_page(page); @@ -1448,11 +1460,11 @@ change_speed(info, 0); info->flags |= ASYNC_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore( &info->irq_spinlock, flags); return 0; errout: - restore_flags(flags); + spin_unlock_irqrestore( &info->irq_spinlock, flags); return retval; } @@ -1476,7 +1488,7 @@ state->irq); #endif - save_flags(flags); cli(); /* Disable interrupts */ + spin_lock_irqsave( &info->irq_spinlock, flags); /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq @@ -1484,41 +1496,6 @@ */ wake_up_interruptible(&info->delta_msr_wait); - /* - * First unlink the serial port from the IRQ chain... - */ - if (info->next_port) - info->next_port->prev_port = info->prev_port; - if (info->prev_port) - info->prev_port->next_port = info->next_port; - else - IRQ_ports[state->irq] = info->next_port; - figure_IRQ_timeout(state->irq); - - /* - * Free the IRQ, if necessary - */ - if (state->irq && (!IRQ_ports[state->irq] || - !IRQ_ports[state->irq]->next_port)) { - if (IRQ_ports[state->irq]) { - free_irq(state->irq, &IRQ_ports[state->irq]); - retval = request_irq(state->irq, rs_interrupt_single, - SA_SHIRQ, "serial", - &IRQ_ports[state->irq]); - - if (retval) - printk("serial shutdown: request_irq: error %d" - " Couldn't reacquire IRQ.\n", retval); - } else - free_irq(state->irq, &IRQ_ports[state->irq]); - } - - if (info->xmit.buf) { - unsigned long pg = (unsigned long) info->xmit.buf; - info->xmit.buf = 0; - free_page(pg); - } - info->IER = 0; serial_outp(info, UART_IER, 0x00); /* disable all intrs */ #ifdef CONFIG_SERIAL_MANY_PORTS @@ -1575,7 +1552,43 @@ serial_outp(info, UART_IER, UART_IERX_SLEEP); } info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + figure_IRQ_timeout(state->irq); + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, &IRQ_ports[state->irq]); + retval = request_irq(state->irq, rs_interrupt_single, + SA_SHIRQ, "serial", + &IRQ_ports[state->irq]); + + if (retval) + printk("serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, &IRQ_ports[state->irq]); + } + + if (info->xmit.buf) { + unsigned long pg = (unsigned long) info->xmit.buf; + info->xmit.buf = 0; + free_page(pg); + } + + spin_unlock_irqrestore( &info->irq_spinlock, flags); } #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ @@ -3119,6 +3132,7 @@ info->flags = sstate->flags; info->xmit_fifo_size = sstate->xmit_fifo_size; info->state = sstate; + spin_lock_init(&info->irq_spinlock); info->line = line; info->iomem_base = sstate->iomem_base; info->iomem_reg_shift = sstate->iomem_reg_shift; @@ -3149,6 +3163,10 @@ * enables interrupts for a serial port, linking in its async structure into * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. + * + * Note that on failure, we don't decrement the module use count - the tty + * later will call rs_close, which will decrement it for us as long as + * tty->driver_data is set non-NULL. --rmk */ static int rs_open(struct tty_struct *tty, struct file * filp) { @@ -3169,10 +3187,8 @@ } tty->driver_data = info; info->tty = tty; - if (serial_paranoia_check(info, tty->device, "rs_open")) { - MOD_DEC_USE_COUNT; + if (serial_paranoia_check(info, tty->device, "rs_open")) return -ENODEV; - } #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, @@ -3187,10 +3203,8 @@ */ if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); - if (!page) { - MOD_DEC_USE_COUNT; + if (!page) return -ENOMEM; - } if (tmp_buf) free_page(page); else @@ -3204,7 +3218,6 @@ (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); - MOD_DEC_USE_COUNT; #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); @@ -3217,10 +3230,8 @@ * Start up serial port */ retval = startup(info); - if (retval) { - MOD_DEC_USE_COUNT; + if (retval) return retval; - } retval = block_til_ready(tty, filp, info); if (retval) { @@ -3228,7 +3239,6 @@ printk("rs_open returning after block_til_ready with %d\n", retval); #endif - MOD_DEC_USE_COUNT; return retval; } @@ -3663,6 +3673,7 @@ info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; save_flags(flags); cli(); @@ -3915,7 +3926,14 @@ case 6: /* BAR 4*/ case 7: base_idx=idx-2; /* BAR 5*/ } - + + /* AFAVLAB uses a different mixture of BARs and offsets */ + /* Not that ugly ;) -- HW */ + if (dev->vendor == PCI_VENDOR_ID_AFAVLAB && idx >= 4) { + base_idx = 4; + offset = (idx - 4) * 8; + } + /* Some Titan cards are also a little weird */ if (dev->vendor == PCI_VENDOR_ID_TITAN && (dev->device == PCI_DEVICE_ID_TITAN_400L || @@ -4262,8 +4280,10 @@ pbn_b0_bt_1_115200, pbn_b0_bt_2_115200, + pbn_b0_bt_8_115200, pbn_b0_bt_1_460800, pbn_b0_bt_2_460800, + pbn_b0_bt_4_460800, pbn_b1_1_115200, pbn_b1_2_115200, @@ -4340,8 +4360,10 @@ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 8, 115200 }, /* pbn_b0_bt_8_115200 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 460800 }, /* pbn_b0_bt_4_460800 */ { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */ { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */ @@ -4467,6 +4489,12 @@ return 1; } +static inline int serial_is_redundant(const struct pci_board *board) +{ + return !((board->num_ports > 1) || (board->base_baud != 115200) || + (board->init_fn) || (board->first_uart_offset)); +} + static int __devinit serial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) { @@ -4481,7 +4509,8 @@ if (ent->driver_data == pbn_default && serial_pci_guess_board(dev, board)) return -ENODEV; - else if (serial_pci_guess_board(dev, &tmp) == 0) { + else if ((serial_pci_guess_board(dev, &tmp) == 0) && + (serial_is_redundant(board))) { printk(KERN_INFO "Redundant entry in serial pci_table. " "Please send the output of\n" "lspci -vv, this message (%04x,%04x,%04x,%04x)\n" @@ -4849,6 +4878,12 @@ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_460800 }, { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_1_115200 }, @@ -4861,6 +4896,11 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_2_115200 }, + /* AFAVLAB serial card, from Harald Welte */ + { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_8_115200 }, + /* EKF addition for i960 Boards form EKF with serial port */ { PCI_VENDOR_ID_INTEL, 0x1960, 0xE4BF, PCI_ANY_ID, 0, 0, @@ -5413,6 +5453,7 @@ #endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; + serial_driver.name_base = SERIAL_DEV_OFFSET; serial_driver.num = NR_PORTS; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; @@ -5424,7 +5465,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -5638,6 +5681,7 @@ info->io_type = req->io_type; info->iomem_base = req->iomem_base; info->iomem_reg_shift = req->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; } autoconfig(state); if (state->type == PORT_UNKNOWN) { @@ -5945,6 +5989,7 @@ info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; quot = state->baud_base / baud; cval = cflag & (CSIZE | CSTOPB); #if defined(__powerpc__) || defined(__alpha__) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/serial167.c linux-2.5/drivers/char/serial167.c --- linux-2.5.5/drivers/char/serial167.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/char/serial167.c Sun Jan 6 01:38:27 2002 @@ -102,6 +102,7 @@ DECLARE_TASK_QUEUE(tq_cyclades); struct tty_driver cy_serial_driver, cy_callout_driver; +static struct console sercons; extern int serial_console; static struct cyclades_port *serial_console_info = NULL; static unsigned int serial_console_cflag = 0; @@ -2408,6 +2409,7 @@ cy_serial_driver.table = serial_table; cy_serial_driver.termios = serial_termios; cy_serial_driver.termios_locked = serial_termios_locked; + cy_serial_driver.console = &sercons; cy_serial_driver.open = cy_open; cy_serial_driver.close = cy_close; cy_serial_driver.write = cy_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/serial_21285.c linux-2.5/drivers/char/serial_21285.c --- linux-2.5.5/drivers/char/serial_21285.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/char/serial_21285.c Sun Jan 6 01:38:27 2002 @@ -45,6 +45,7 @@ static struct termios *rs285_termios[1]; static struct termios *rs285_termios_locked[1]; +static struct console rs285_cons; static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char; static struct tty_struct *rs285_tty; @@ -312,7 +313,9 @@ rs285_driver.table = rs285_table; rs285_driver.termios = rs285_termios; rs285_driver.termios_locked = rs285_termios_locked; - +#ifdef CONFIG_SERIAL_21285_CONSOLE + rs285_driver.console = &rs285_cons; +#endif rs285_driver.open = rs285_open; rs285_driver.close = rs285_close; rs285_driver.write = rs285_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/serial_amba.c linux-2.5/drivers/char/serial_amba.c --- linux-2.5.5/drivers/char/serial_amba.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/char/serial_amba.c Sun Mar 3 23:50:42 2002 @@ -356,7 +356,7 @@ #ifdef SUPPORT_SYSRQ if (info->sysrq) { if (ch && time_before(jiffies, info->sysrq)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); info->sysrq = 0; goto ignore_char; } @@ -1789,7 +1789,9 @@ ambanormal_driver.table = ambauart_table; ambanormal_driver.termios = ambauart_termios; ambanormal_driver.termios_locked = ambauart_termios_locked; - +#ifdef CONFIG_SERIAL_AMBA_CONSOLE + ambanormal_driver.console = &ambauart_cons; +#endif ambanormal_driver.open = ambauart_open; ambanormal_driver.close = ambauart_close; ambanormal_driver.write = ambauart_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/serial_tx3912.c linux-2.5/drivers/char/serial_tx3912.c --- linux-2.5.5/drivers/char/serial_tx3912.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/char/serial_tx3912.c Fri Mar 1 18:58:13 2002 @@ -1,8 +1,6 @@ /* * drivers/char/serial_tx3912.c * - * Copyright (C) 1999 Harald Koerfgen - * Copyright (C) 2000 Jim Pick * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) * * This program is free software; you can redistribute it and/or modify @@ -15,19 +13,13 @@ #include #include #include -#include -#include #include -#include -#include #include #include -#include -#include +#include #include #include #include -#include #include #include "serial_tx3912.h" @@ -62,35 +54,19 @@ }; /* - * Structures and such for TTY sessions and usage counts + * Structures and usage counts */ static struct tty_driver rs_driver, rs_callout_driver; -static struct tty_struct * rs_table[TX3912_UART_NPORTS] = { NULL, }; -static struct termios ** rs_termios; -static struct termios ** rs_termios_locked; -struct rs_port *rs_ports; -int rs_refcount; -int rs_initialized = 0; - -/* - * ---------------------------------------------------------------------- - * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * rs_interrupt(). They were separated out for readability's sake. - * - * Note: rs_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * rs_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c - * - * and look at the resulting assemble code in serial.s. - * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- +static struct tty_struct **rs_tty; +static struct termios **rs_termios; +static struct termios **rs_termios_locked; +static struct rs_port *rs_port; +static int rs_refcount; +static int rs_initialized; + + +/* + * Receive a character */ static inline void receive_char_pio(struct rs_port *port) { @@ -98,83 +74,34 @@ unsigned char ch; int counter = 2048; - /* While there are characters, get them ... */ - while (counter>0) { - if (!(inl(port->base + TX3912_UART_CTRL1) & UART_RX_HOLD_FULL)) + /* While there are characters */ + while (counter > 0) { + if (!(inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_RXHOLDFULL)) break; - ch = inb(port->base + TX3912_UART_DATA); + ch = inb(TX3912_UARTA_DATA); if (tty->flip.count < TTY_FLIPBUF_SIZE) { *tty->flip.char_buf_ptr++ = ch; *tty->flip.flag_buf_ptr++ = 0; tty->flip.count++; } - udelay(1); /* Allow things to happen - it take a while */ + udelay(1); counter--; } - if (!counter) - printk( "Ugh, looped in receive_char_pio!\n" ); tty_flip_buffer_push(tty); - -#if 0 - /* Now handle error conditions */ - if (*status & (INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_PARITYERR_INT) | - INTTYPE(UART_BREAK_INT))) { - - /* - * Now check to see if character should be - * ignored, and mask off conditions which - * should be ignored. - */ - if (*status & port->ignore_status_mask) { - goto ignore_char; - } - *status &= port->read_status_mask; - - if (*status & INTTYPE(UART_BREAK_INT)) { - rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "handling break...."); - *tty->flip.flag_buf_ptr = TTY_BREAK; - } - else if (*status & INTTYPE(UART_PARITYERR_INT)) { - *tty->flip.flag_buf_ptr = TTY_PARITY; - } - else if (*status & INTTYPE(UART_FRAMEERR_INT)) { - *tty->flip.flag_buf_ptr = TTY_FRAME; - } - if (*status & INTTYPE(UART_RXOVERRUN_INT)) { - /* - * Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - tty->flip.count++; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - } - } - } - - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; - -ignore_char: - tty_flip_buffer_push(tty); -#endif } +/* + * Transmit a character + */ static inline void transmit_char_pio(struct rs_port *port) { - /* While I'm able to transmit ... */ + /* TX while bytes available */ for (;;) { - if (!(inl(port->base + TX3912_UART_CTRL1) & UART_TX_EMPTY)) + if (!(inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_EMPTY)) break; else if (port->x_char) { - outb(port->x_char, port->base + TX3912_UART_DATA); + outb(port->x_char, TX3912_UARTA_DATA); port->icount.tx++; port->x_char = 0; } @@ -184,14 +111,14 @@ } else { outb(port->gs.xmit_buf[port->gs.xmit_tail++], - port->base + TX3912_UART_DATA); + TX3912_UARTA_DATA); port->icount.tx++; port->gs.xmit_tail &= SERIAL_XMIT_SIZE-1; if (--port->gs.xmit_cnt <= 0) { break; } } - udelay(10); /* Allow things to happen - it take a while */ + udelay(10); } if (port->gs.xmit_cnt <= 0 || port->gs.tty->stopped || @@ -203,519 +130,418 @@ if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && port->gs.tty->ldisc.write_wakeup) (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); - rs_dprintk (TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", + rs_dprintk(TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", port->gs.wakeup_chars); wake_up_interruptible(&port->gs.tty->write_wait); } } - - +/* + * We don't have MSR + */ static inline void check_modem_status(struct rs_port *port) { - /* We don't have a carrier detect line - but just respond - like we had one anyways so that open() becomes unblocked */ wake_up_interruptible(&port->gs.open_wait); } -int count = 0; - /* - * This is the serial driver's interrupt routine (inlined, because - * there are two different versions of this, one for each serial port, - * differing only by the bits used in interrupt status 2 register) + * RX interrupt handler */ - -static inline void rs_rx_interrupt(int irq, void *dev_id, - struct pt_regs * regs, int intshift) +static inline void rs_rx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct rs_port * port; - unsigned long int2status; - unsigned long flags; - unsigned long ints; + unsigned long flags, status; save_and_cli(flags); - port = (struct rs_port *)dev_id; - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift); - - /* Get the interrrupts we have enabled */ - int2status = IntStatus2 & IntEnable2; + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "rs_rx_interrupt..."); - /* Get interrupts in easy to use form */ - ints = int2status >> intshift; + /* Get the interrupts */ + status = inl(TX3912_INT2_STATUS); /* Clear any interrupts we might be about to handle */ - IntClear2 = int2status & ( - (INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT) | - INTTYPE(UART_RX_INT)) << intshift); + outl(TX3912_INT2_UARTA_RX_BITS, TX3912_INT2_CLEAR); - if (!port || !port->gs.tty) { + if(!rs_port || !rs_port->gs.tty) { restore_flags(flags); return; } /* RX Receiver Holding Register Overrun */ - if (ints & INTTYPE(UART_RXOVERRUN_INT)) { - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "overrun"); - port->icount.overrun++; + if(status & TX3912_INT2_UARTATXOVERRUNINT) { + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "overrun"); + rs_port->icount.overrun++; } /* RX Frame Error */ - if (ints & INTTYPE(UART_FRAMEERR_INT)) { - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "frame error"); - port->icount.frame++; + if(status & TX3912_INT2_UARTAFRAMEERRINT) { + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "frame error"); + rs_port->icount.frame++; } /* Break signal received */ - if (ints & INTTYPE(UART_BREAK_INT)) { - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "break"); - port->icount.brk++; + if(status & TX3912_INT2_UARTABREAKINT) { + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "break"); + rs_port->icount.brk++; } /* RX Parity Error */ - if (ints & INTTYPE(UART_PARITYERR_INT)) { - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "parity error"); - port->icount.parity++; + if(status & TX3912_INT2_UARTAPARITYINT) { + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "parity error"); + rs_port->icount.parity++; } - /* Receive byte (non-DMA) */ - if (ints & INTTYPE(UART_RX_INT)) { - receive_char_pio(port); + /* Byte received */ + if(status & TX3912_INT2_UARTARXINT) { + receive_char_pio(rs_port); } restore_flags(flags); - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); } -static inline void rs_tx_interrupt(int irq, void *dev_id, - struct pt_regs * regs, int intshift) +/* + * TX interrupt handler + */ +static inline void rs_tx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct rs_port * port; - unsigned long int2status; - unsigned long flags; - unsigned long ints; + unsigned long flags, status; save_and_cli(flags); - port = (struct rs_port *)dev_id; - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift); + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "rs_tx_interrupt..."); - /* Get the interrrupts we have enabled */ - int2status = IntStatus2 & IntEnable2; + /* Get the interrupts */ + status = inl(TX3912_INT2_STATUS); - if (!port || !port->gs.tty) { + if(!rs_port || !rs_port->gs.tty) { restore_flags(flags); return; } - /* Get interrupts in easy to use form */ - ints = int2status >> intshift; + /* Clear interrupts */ + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); - /* Clear any interrupts we might be about to handle */ - IntClear2 = int2status & ( - (INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << intshift); - - /* TX holding register empty, so transmit byte (non-DMA) */ - if (ints & (INTTYPE(UART_TX_INT) | INTTYPE(UART_EMPTY_INT))) { - transmit_char_pio(port); + /* TX holding register empty - transmit a byte */ + if(status & TX3912_INT2_UARTAEMPTYINT) { + transmit_char_pio(rs_port); } /* TX Transmit Holding Register Overrun (shouldn't happen) */ - if (ints & INTTYPE(UART_TXOVERRUN_INT)) { - printk ( "rs: TX overrun\n"); + if(status & TX3912_INT2_UARTATXOVERRUNINT) { + printk( "rs_tx_interrupt: TX overrun\n"); } - /* - check_modem_status(); - */ - restore_flags(flags); - rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); -} - -static void rs_rx_interrupt_uarta(int irq, void *dev_id, - struct pt_regs * regs) -{ - rs_rx_interrupt(irq, dev_id, regs, UARTA_SHIFT); -} - -static void rs_tx_interrupt_uarta(int irq, void *dev_id, - struct pt_regs * regs) -{ - rs_tx_interrupt(irq, dev_id, regs, UARTA_SHIFT); + rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); } /* - *********************************************************************** - * Here are the routines that actually * - * interface with the generic_serial driver * - *********************************************************************** + * Here are the routines that actually interface with the generic driver */ static void rs_disable_tx_interrupts (void * ptr) { - struct rs_port *port = ptr; unsigned long flags; save_and_cli(flags); - port->gs.flags &= ~GS_TX_INTEN; - IntEnable2 &= ~((INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << port->intshift); - - IntClear2 = (INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << port->intshift; + outl(inl(TX3912_INT2_ENABLE) & ~TX3912_INT2_UARTA_TX_BITS, + TX3912_INT2_ENABLE); + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); restore_flags(flags); } static void rs_enable_tx_interrupts (void * ptr) { - struct rs_port *port = ptr; unsigned long flags; save_and_cli(flags); - IntClear2 = (INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << port->intshift; - - IntEnable2 |= (INTTYPE(UART_TX_INT) | - INTTYPE(UART_EMPTY_INT) | - INTTYPE(UART_TXOVERRUN_INT)) << port->intshift; - - /* Send a char to start TX interrupts happening */ - transmit_char_pio(port); + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); + outl(inl(TX3912_INT2_ENABLE) | TX3912_INT2_UARTA_TX_BITS, + TX3912_INT2_ENABLE); + transmit_char_pio(rs_port); restore_flags(flags); } static void rs_disable_rx_interrupts (void * ptr) { - struct rs_port *port = ptr; unsigned long flags; save_and_cli(flags); - IntEnable2 &= ~((INTTYPE(UART_RX_INT) | - INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT)) << port->intshift); - - IntClear2 = (INTTYPE(UART_RX_INT) | - INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT)) << port->intshift; + outl(inl(TX3912_INT2_ENABLE) & ~TX3912_INT2_UARTA_RX_BITS, + TX3912_INT2_ENABLE); + outl(TX3912_INT2_UARTA_RX_BITS, TX3912_INT2_CLEAR); restore_flags(flags); } static void rs_enable_rx_interrupts (void * ptr) { - struct rs_port *port = ptr; unsigned long flags; save_and_cli(flags); - IntEnable2 |= (INTTYPE(UART_RX_INT) | - INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT)) << port->intshift; - - /* Empty the input buffer - apparently this is *vital* */ - while (inl(port->base + TX3912_UART_CTRL1) & UART_RX_HOLD_FULL) { - inb(port->base + TX3912_UART_DATA); - } - - IntClear2 = (INTTYPE(UART_RX_INT) | - INTTYPE(UART_RXOVERRUN_INT) | - INTTYPE(UART_FRAMEERR_INT) | - INTTYPE(UART_BREAK_INT) | - INTTYPE(UART_PARITYERR_INT)) << port->intshift; + outl(inl(TX3912_INT2_ENABLE) | TX3912_INT2_UARTA_RX_BITS, + TX3912_INT2_ENABLE); + while (inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_RXHOLDFULL) + inb(TX3912_UARTA_DATA); + outl(TX3912_INT2_UARTA_RX_BITS, TX3912_INT2_CLEAR); restore_flags(flags); } - +/* + * We have no CD + */ static int rs_get_CD (void * ptr) { - /* No Carried Detect in Hardware - just return true */ - func_exit(); - return (1); + return 1; } +/* + * Shut down the port + */ static void rs_shutdown_port (void * ptr) { - struct rs_port *port = ptr; - func_enter(); - - port->gs.flags &= ~GS_ACTIVE; - + rs_port->gs.flags &= ~GS_ACTIVE; func_exit(); } static int rs_set_real_termios (void *ptr) { - struct rs_port *port = ptr; - int t; + unsigned int ctrl1 = 0; + unsigned int ctrl2 = 0; - switch (port->gs.baud) { - /* Save some typing work... */ -#define e(x) case x:t= TX3912_UART_CTRL2_B ## x ; break - e(300);e(600);e(1200);e(2400);e(4800);e(9600); - e(19200);e(38400);e(57600);e(76800);e(115200);e(230400); - case 0 :t = -1; - break; - default: - /* Can I return "invalid"? */ - t = TX3912_UART_CTRL2_B9600; - printk (KERN_INFO "rs: unsupported baud rate: %d.\n", port->gs.baud); - break; - } -#undef e - if (t >= 0) { - /* Jim: Set Hardware Baud rate - there is some good - code in drivers/char/serial.c */ - - /* Program hardware for parity, data bits, stop bits (note: these are hardcoded to 8N1 */ - UartA_Ctrl1 &= 0xf000000f; - UartA_Ctrl1 &= ~(UART_DIS_TXD | SER_SEVEN_BIT | SER_EVEN_PARITY | SER_TWO_STOP); - -#define CFLAG port->gs.tty->termios->c_cflag - if (C_PARENB(port->gs.tty)) { - if (!C_PARODD(port->gs.tty)) - UartA_Ctrl1 |= SER_EVEN_PARITY; - else - UartA_Ctrl1 |= SER_ODD_PARITY; - } - if ((CFLAG & CSIZE)==CS6) - printk(KERN_ERR "6 bits not supported\n"); - if ((CFLAG & CSIZE)==CS5) - printk(KERN_ERR "5 bits not supported\n"); - if ((CFLAG & CSIZE)==CS7) - UartA_Ctrl1 |= SER_SEVEN_BIT; - if (C_CSTOPB(port->gs.tty)) - UartA_Ctrl1 |= SER_TWO_STOP; - - outl(t, port->base + TX3912_UART_CTRL2); - outl(0, port->base + TX3912_UART_DMA_CTRL1); - outl(0, port->base + TX3912_UART_DMA_CTRL2); - UartA_Ctrl1 |= TX3912_UART_CTRL1_UARTON; + /* Set baud rate */ + switch (rs_port->gs.baud) { + case 0: + goto done; + case 1200: + ctrl2 = TX3912_UART_CTRL2_B1200; + break; + case 2400: + ctrl2 = TX3912_UART_CTRL2_B2400; + break; + case 4800: + ctrl2 = TX3912_UART_CTRL2_B4800; + break; + case 9600: + ctrl2 = TX3912_UART_CTRL2_B9600; + break; + case 19200: + ctrl2 = TX3912_UART_CTRL2_B19200; + break; + case 38400: + ctrl2 = TX3912_UART_CTRL2_B38400; + break; + case 57600: + ctrl2 = TX3912_UART_CTRL2_B57600; + break; + case 115200: + default: + ctrl2 = TX3912_UART_CTRL2_B115200; + break; + } + + /* Clear current UARTA settings */ + ctrl1 = inl(TX3912_UARTA_CTRL1) & 0xf000000f; - /* wait until UARTA is stable */ - while (~UartA_Ctrl1 & TX3912_UART_CTRL1_UARTON); + /* Set parity */ + if(C_PARENB(rs_port->gs.tty)) { + if (!C_PARODD(rs_port->gs.tty)) + ctrl1 |= (TX3912_UART_CTRL1_ENPARITY | + TX3912_UART_CTRL1_EVENPARITY); + else + ctrl1 |= TX3912_UART_CTRL1_ENPARITY; } - func_exit (); - return 0; + /* Set data size */ + switch(rs_port->gs.tty->termios->c_cflag & CSIZE) { + case CS7: + ctrl1 |= TX3912_UART_CTRL1_BIT_7; + break; + case CS5: + case CS6: + printk(KERN_ERR "Data byte size unsupported. Defaulting to CS8\n"); + case CS8: + default: + ctrl1 &= ~TX3912_UART_CTRL1_BIT_7; + } + + /* Set stop bits */ + if(C_CSTOPB(rs_port->gs.tty)) + ctrl1 |= TX3912_UART_CTRL1_TWOSTOP; + + /* Write the control registers */ + outl(ctrl2, TX3912_UARTA_CTRL2); + outl(0, TX3912_UARTA_DMA_CTRL1); + outl(0, TX3912_UARTA_DMA_CTRL2); + outl(ctrl1, TX3912_UARTA_CTRL1); + + /* Loop until the UART is on */ + while(~inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_UARTON); + +done: + func_exit(); + return 0; } +/* + * Anyone in the buffer? + */ static int rs_chars_in_buffer (void * ptr) { - struct rs_port *port = ptr; - int scratch; - - scratch = inl(port->base + TX3912_UART_CTRL1); - - return ((scratch & UART_TX_EMPTY) ? 0 : 1); + return ((inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_EMPTY) ? 0 : 1); } -/* ********************************************************************** * - * Here are the routines that actually * - * interface with the rest of the system * - * ********************************************************************** */ -static int rs_open (struct tty_struct * tty, struct file * filp) +/* + * Open the serial port + */ +static int rs_open(struct tty_struct * tty, struct file * filp) { - struct rs_port *port; - int retval, line; + int retval; func_enter(); - if (!rs_initialized) { + if(!rs_initialized) { return -EIO; } - line = minor(tty->device) - tty->driver.minor_start; - rs_dprintk (TX3912_UART_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p)\n", - (int) current->pid, line, tty, current->tty); - - if ((line < 0) || (line >= TX3912_UART_NPORTS)) + if(minor(tty->device) - tty->driver.minor_start) { return -ENODEV; + } - /* Pre-initialized already */ - port = & rs_ports[line]; - - rs_dprintk (TX3912_UART_DEBUG_OPEN, "port = %p\n", port); - - tty->driver_data = port; - port->gs.tty = tty; - port->gs.count++; + rs_dprintk(TX3912_UART_DEBUG_OPEN, "Serial opening...\n"); - rs_dprintk (TX3912_UART_DEBUG_OPEN, "starting port\n"); + tty->driver_data = rs_port; + rs_port->gs.tty = tty; + rs_port->gs.count++; /* * Start up serial port */ - retval = gs_init_port(&port->gs); - rs_dprintk (TX3912_UART_DEBUG_OPEN, "done gs_init\n"); - if (retval) { - port->gs.count--; + retval = gs_init_port(&rs_port->gs); + rs_dprintk(TX3912_UART_DEBUG_OPEN, "Finished gs_init...\n"); + if(retval) { + rs_port->gs.count--; return retval; } - port->gs.flags |= GS_ACTIVE; - - rs_dprintk (TX3912_UART_DEBUG_OPEN, "before inc_use_count (count=%d.\n", - port->gs.count); - if (port->gs.count == 1) { + rs_port->gs.flags |= GS_ACTIVE; + if(rs_port->gs.count == 1) { MOD_INC_USE_COUNT; } - rs_dprintk (TX3912_UART_DEBUG_OPEN, "after inc_use_count\n"); - - /* Jim: Initialize port hardware here */ - - /* Enable high-priority interrupts for UARTA */ - IntEnable6 |= INT6_UARTARXINT; - rs_enable_rx_interrupts(&rs_ports[0]); - retval = gs_block_til_ready(&port->gs, filp); - rs_dprintk (TX3912_UART_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n", - retval, port->gs.count); + rs_enable_rx_interrupts(rs_port); + rs_enable_tx_interrupts(rs_port); - if (retval) { + retval = gs_block_til_ready(&rs_port->gs, filp); + if(retval) { MOD_DEC_USE_COUNT; - port->gs.count--; + rs_port->gs.count--; return retval; } - /* tty->low_latency = 1; */ - if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { + if((rs_port->gs.count == 1) && + (rs_port->gs.flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) - *tty->termios = port->gs.normal_termios; + *tty->termios = rs_port->gs.normal_termios; else - *tty->termios = port->gs.callout_termios; - rs_set_real_termios (port); + *tty->termios = rs_port->gs.callout_termios; + rs_set_real_termios(rs_port); } - port->gs.session = current->session; - port->gs.pgrp = current->pgrp; + rs_port->gs.session = current->session; + rs_port->gs.pgrp = current->pgrp; func_exit(); - /* Jim */ -/* cli(); */ - return 0; - } - - -static void rs_close (void *ptr) +/* + * Close the serial port + */ +static void rs_close(void *ptr) { - func_enter (); - - /* Anything to do here? */ - + func_enter(); MOD_DEC_USE_COUNT; - func_exit (); + func_exit(); } - -/* I haven't the foggiest why the decrement use count has to happen - here. The whole linux serial drivers stuff needs to be redesigned. - My guess is that this is a hack to minimize the impact of a bug - elsewhere. Thinking about it some more. (try it sometime) Try - running minicom on a serial port that is driven by a modularized - driver. Have the modem hangup. Then remove the driver module. Then - exit minicom. I expect an "oops". -- REW */ -static void rs_hungup (void *ptr) +/* + * Hang up the serial port + */ +static void rs_hungup(void *ptr) { - func_enter (); + func_enter(); MOD_DEC_USE_COUNT; - func_exit (); + func_exit(); } -static int rs_ioctl (struct tty_struct * tty, struct file * filp, +/* + * Serial ioctl call + */ +static int rs_ioctl(struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg) { - int rc; - struct rs_port *port = tty->driver_data; - int ival; + int ival, rc; rc = 0; switch (cmd) { - case TIOCGSOFTCAR: - rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), + case TIOCGSOFTCAR: + rc = put_user((tty->termios->c_cflag & CLOCAL) ? 1 : 0, (unsigned int *) arg); - break; - case TIOCSSOFTCAR: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(int))) == 0) { - get_user(ival, (unsigned int *) arg); - tty->termios->c_cflag = - (tty->termios->c_cflag & ~CLOCAL) | - (ival ? CLOCAL : 0); - } - break; - case TIOCGSERIAL: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct serial_struct))) == 0) - rc = gs_getserial(&port->gs, (struct serial_struct *) arg); - break; - case TIOCSSERIAL: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(struct serial_struct))) == 0) - rc = gs_setserial(&port->gs, (struct serial_struct *) arg); - break; - default: - rc = -ENOIOCTLCMD; - break; + break; + case TIOCSSOFTCAR: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(int))) == 0) { + get_user(ival, (unsigned int *) arg); + tty->termios->c_cflag = + (tty->termios->c_cflag & ~CLOCAL) | + (ival ? CLOCAL : 0); + } + break; + case TIOCGSERIAL: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct))) == 0) + rc = gs_getserial(&rs_port->gs, (struct serial_struct *) arg); + break; + case TIOCSSERIAL: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct serial_struct))) == 0) + rc = gs_setserial(&rs_port->gs, (struct serial_struct *) arg); + break; + default: + rc = -ENOIOCTLCMD; + break; } - /* func_exit(); */ return rc; } - /* - * This function is used to send a high-priority XON/XOFF character to - * the device + * Send xchar */ static void rs_send_xchar(struct tty_struct * tty, char ch) { - struct rs_port *port = (struct rs_port *)tty->driver_data; - func_enter (); + func_enter(); - port->x_char = ch; + rs_port->x_char = ch; if (ch) { - /* Make sure transmit interrupts are on */ rs_enable_tx_interrupts(tty); } func_exit(); } - /* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ + * Throttle characters as directed by upper tty layer */ static void rs_throttle(struct tty_struct * tty) { @@ -726,17 +552,19 @@ tty->ldisc.chars_in_buffer(tty)); #endif - func_enter (); + func_enter(); if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); - func_exit (); + func_exit(); } +/* + * Un-throttle characters as directed by upper tty layer + */ static void rs_unthrottle(struct tty_struct * tty) { - struct rs_port *port = (struct rs_port *)tty->driver_data; #ifdef TX3912_UART_DEBUG_THROTTLE char buf[64]; @@ -747,8 +575,8 @@ func_enter(); if (I_IXOFF(tty)) { - if (port->x_char) - port->x_char = 0; + if (rs_port->x_char) + rs_port->x_char = 0; else rs_send_xchar(tty, START_CHAR(tty)); } @@ -756,105 +584,75 @@ func_exit(); } - - - - -/* ********************************************************************** * - * Here are the initialization routines. * - * ********************************************************************** */ - -void * ckmalloc (int size) -{ - void *p; - - p = kmalloc(size, GFP_KERNEL); - if (p) - memset(p, 0, size); - return p; -} - - - -static int rs_init_portstructs(void) +/* + * Initialize the serial port + */ +void __init tx3912_rs_init(void) { - struct rs_port *port; - int i; - - /* Debugging */ func_enter(); + rs_dprintk(TX3912_UART_DEBUG_INIT, "Initializing serial...\n"); - rs_ports = ckmalloc(TX3912_UART_NPORTS * sizeof (struct rs_port)); - if (!rs_ports) - return -ENOMEM; - - rs_termios = ckmalloc(TX3912_UART_NPORTS * sizeof (struct termios *)); - if (!rs_termios) { - kfree (rs_ports); - return -ENOMEM; + /* Allocate critical structures */ + if(!(rs_tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL))) { + return; } - - rs_termios_locked = ckmalloc(TX3912_UART_NPORTS * sizeof (struct termios *)); - if (!rs_termios_locked) { - kfree (rs_ports); - kfree (rs_termios); - return -ENOMEM; + if(!(rs_port = kmalloc(sizeof(struct rs_port), GFP_KERNEL))) { + kfree(rs_tty); + return; + } + if(!(rs_termios = kmalloc(sizeof(struct termios), GFP_KERNEL))) { + kfree(rs_port); + kfree(rs_tty); + return; + } + if(!(rs_termios_locked = kmalloc(sizeof(struct termios), GFP_KERNEL))) { + kfree(rs_termios); + kfree(rs_port); + kfree(rs_tty); + return; } - /* Adjust the values in the "driver" */ - rs_driver.termios = rs_termios; - rs_driver.termios_locked = rs_termios_locked; + /* Zero out the structures */ + memset(rs_tty, 0, sizeof(struct tty_struct)); + memset(rs_port, 0, sizeof(struct rs_port)); + memset(rs_termios, 0, sizeof(struct termios)); + memset(rs_termios_locked, 0, sizeof(struct termios)); + memset(&rs_driver, 0, sizeof(rs_driver)); + memset(&rs_callout_driver, 0, sizeof(rs_callout_driver)); - port = rs_ports; - for (i=0; i < TX3912_UART_NPORTS;i++) { - rs_dprintk (TX3912_UART_DEBUG_INIT, "initing port %d\n", i); - port->gs.callout_termios = tty_std_termios; - port->gs.normal_termios = tty_std_termios; - port->gs.magic = SERIAL_MAGIC; - port->gs.close_delay = HZ/2; - port->gs.closing_wait = 30 * HZ; - port->gs.rd = &rs_real_driver; + /* Fill in hardware specific port structure */ + rs_port->gs.callout_termios = tty_std_termios; + rs_port->gs.normal_termios = tty_std_termios; + rs_port->gs.magic = SERIAL_MAGIC; + rs_port->gs.close_delay = HZ/2; + rs_port->gs.closing_wait = 30 * HZ; + rs_port->gs.rd = &rs_real_driver; #ifdef NEW_WRITE_LOCKING - port->gs.port_write_sem = MUTEX; + rs_port->gs.port_write_sem = MUTEX; #endif #ifdef DECLARE_WAITQUEUE - init_waitqueue_head(&port->gs.open_wait); - init_waitqueue_head(&port->gs.close_wait); + init_waitqueue_head(&rs_port->gs.open_wait); + init_waitqueue_head(&rs_port->gs.close_wait); #endif - port->base = (i == 0) ? TX3912_UARTA_BASE : TX3912_UARTB_BASE; - port->intshift = (i == 0) ? UARTA_SHIFT : UARTB_SHIFT; - rs_dprintk (TX3912_UART_DEBUG_INIT, "base 0x%08lx intshift %d\n", - port->base, port->intshift); - port++; - } - - func_exit(); - return 0; -} - -static int rs_init_drivers(void) -{ - int error; - - func_enter(); - memset(&rs_driver, 0, sizeof(rs_driver)); + /* Fill in generic serial driver structures */ rs_driver.magic = TTY_DRIVER_MAGIC; rs_driver.driver_name = "serial"; rs_driver.name = "ttyS"; rs_driver.major = TTY_MAJOR; rs_driver.minor_start = 64; - rs_driver.num = TX3912_UART_NPORTS; + rs_driver.num = 1; rs_driver.type = TTY_DRIVER_TYPE_SERIAL; rs_driver.subtype = SERIAL_TYPE_NORMAL; rs_driver.init_termios = tty_std_termios; - rs_driver.init_termios.c_cflag = - B115200 | CS8 | CREAD | HUPCL | CLOCAL; + rs_driver.init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; rs_driver.refcount = &rs_refcount; - rs_driver.table = rs_table; + rs_driver.table = rs_tty; rs_driver.termios = rs_termios; rs_driver.termios_locked = rs_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + rs_driver.console = &sercons; +#endif rs_driver.open = rs_open; rs_driver.close = gs_close; rs_driver.write = gs_write; @@ -870,92 +668,59 @@ rs_driver.stop = gs_stop; rs_driver.start = gs_start; rs_driver.hangup = gs_hangup; - rs_callout_driver = rs_driver; rs_callout_driver.name = "cua"; rs_callout_driver.major = TTYAUX_MAJOR; rs_callout_driver.subtype = SERIAL_TYPE_CALLOUT; - if ((error = tty_register_driver(&rs_driver))) { - printk(KERN_ERR "Couldn't register serial driver, error = %d\n", - error); - return 1; + /* Register serial and callout drivers */ + if(tty_register_driver(&rs_driver)) { + printk(KERN_ERR "Unable to register serial driver\n"); + goto error; } - if ((error = tty_register_driver(&rs_callout_driver))) { + if(tty_register_driver(&rs_callout_driver)) { tty_unregister_driver(&rs_driver); - printk(KERN_ERR "Couldn't register callout driver, error = %d\n", - error); - return 1; + printk(KERN_ERR "Unable to register callout driver\n"); + goto error; } - func_exit(); - return 0; -} - - -void __init tx3912_rs_init(void) -{ - int rc; - - - func_enter(); - rs_dprintk (TX3912_UART_DEBUG_INIT, "Initing serial module... (rs_debug=%d)\n", rs_debug); + /* Assign IRQs */ + if(request_irq(2, rs_tx_interrupt, SA_SHIRQ, + "uarta_tx", rs_port)) { + printk(KERN_ERR "Cannot allocate IRQ for UARTA_TX.\n"); + goto error; + } - rc = rs_init_portstructs (); - rs_init_drivers (); - if (request_irq(2, rs_tx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT, - "serial", &rs_ports[0])) { - printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n"); - rc = 0; - } - if (request_irq(3, rs_rx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT, - "serial", &rs_ports[0])) { - printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n"); - rc = 0; + if(request_irq(3, rs_rx_interrupt, SA_SHIRQ, + "uarta_rx", rs_port)) { + printk(KERN_ERR "Cannot allocate IRQ for UARTA_RX.\n"); + goto error; } - IntEnable6 |= INT6_UARTARXINT; - rs_enable_rx_interrupts(&rs_ports[0]); + /* Enable the serial receive interrupt */ + rs_enable_rx_interrupts(rs_port); #ifndef CONFIG_SERIAL_TX3912_CONSOLE -{ - unsigned int scratch = 0; + /* Write the control registers */ + outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_CTRL2); + outl(0x00000000, TX3912_UARTA_DMA_CTRL1); + outl(0x00000000, TX3912_UARTA_DMA_CTRL2); + outl(inl(TX3912_UARTA_CTRL1) | TX3912_UART_CTRL1_ENUART, + TX3912_UARTA_CTRL1); - /* Setup master clock for UART */ - scratch = inl(TX3912_CLK_CTRL_BASE); - scratch &= ~TX3912_CLK_CTRL_SIBMCLKDIV_MASK; - scratch |= ((0x2 << TX3912_CLK_CTRL_SIBMCLKDIV_SHIFT) & - TX3912_CLK_CTRL_SIBMCLKDIV_MASK) - | TX3912_CLK_CTRL_SIBMCLKDIR - | TX3912_CLK_CTRL_ENSIBMCLK - | TX3912_CLK_CTRL_CSERSEL; - outl(scratch, TX3912_CLK_CTRL_BASE); - - /* Configure UARTA clock */ - scratch = inl(TX3912_CLK_CTRL_BASE); - scratch |= ((0x3 << TX3912_CLK_CTRL_CSERDIV_SHIFT) & - TX3912_CLK_CTRL_CSERDIV_MASK) - | TX3912_CLK_CTRL_ENCSERCLK - | TX3912_CLK_CTRL_ENUARTACLK; - outl(scratch, TX3912_CLK_CTRL_BASE); - - /* Setup UARTA for 115200,8N1 */ - outl(0, TX3912_UARTA_BASE + TX3912_UART_CTRL1); - outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_BASE + TX3912_UART_CTRL2); - outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL1); - outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL2); - - /* Enable UARTA */ - outl(TX3912_UART_CTRL1_ENUART, TX3912_UARTA_BASE + TX3912_UART_CTRL1); - while (~inl(TX3912_UARTA_BASE + TX3912_UART_CTRL1) & - TX3912_UART_CTRL1_UARTON); -} + /* Loop until the UART is on */ + while(~inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_UARTON); #endif - /* Note: I didn't do anything to enable the second UART */ - if (rc >= 0) - rs_initialized++; + rs_initialized = 1; + func_exit(); + return; +error: + kfree(rs_termios_locked); + kfree(rs_termios); + kfree(rs_port); + kfree(rs_tty); func_exit(); } @@ -963,40 +728,37 @@ * Begin serial console routines */ #ifdef CONFIG_SERIAL_TX3912_CONSOLE - void serial_outc(unsigned char c) { int i; unsigned long int2; - #define BUSY_WAIT 10000 - - /* - * Turn UARTA interrupts off - */ - int2 = IntEnable2; - IntEnable2 &= - ~(INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY); - - /* - * The UART_TX_EMPTY bit in UartA_Ctrl1 seems - * not to be very reliable :-( - * - * Wait for the Tx register to become empty - */ - for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < BUSY_WAIT); i++); - IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY; - UartA_Data = c; - for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < BUSY_WAIT); i++); - IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY; + /* Disable UARTA_TX interrupts */ + int2 = inl(TX3912_INT2_ENABLE); + outl(inl(TX3912_INT2_ENABLE) & ~TX3912_INT2_UARTA_TX_BITS, + TX3912_INT2_ENABLE); + + /* Wait for UARTA_TX register to empty */ + i = 10000; + while(!(inl(TX3912_INT2_STATUS) & TX3912_INT2_UARTATXINT) && i--); + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); + + /* Send the character */ + outl(c, TX3912_UARTA_DATA); + + /* Wait for UARTA_TX register to empty */ + i = 10000; + while(!(inl(TX3912_INT2_STATUS) & TX3912_INT2_UARTATXINT) && i--); + outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); - IntEnable2 = int2; + /* Enable UARTA_TX interrupts */ + outl(int2, TX3912_INT2_ENABLE); } static void serial_console_write(struct console *co, const char *s, - unsigned count) + unsigned count) { - unsigned int i; + unsigned int i; for (i = 0; i < count; i++) { if (*s == '\n') @@ -1012,36 +774,78 @@ static __init int serial_console_setup(struct console *co, char *options) { - unsigned int scratch = 0; + int baud = 115200; + int bits = 8; + int parity = 'n'; + char *s; + unsigned int ctrl1 = 0; + unsigned int ctrl2 = 0; + + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s++ - '0'; + } + + switch(baud) { + case 1200: + ctrl2 = TX3912_UART_CTRL2_B1200; + break; + case 2400: + ctrl2 = TX3912_UART_CTRL2_B2400; + break; + case 4800: + ctrl2 = TX3912_UART_CTRL2_B4800; + break; + case 9600: + ctrl2 = TX3912_UART_CTRL2_B9600; + break; + case 19200: + ctrl2 = TX3912_UART_CTRL2_B19200; + break; + case 38400: + ctrl2 = TX3912_UART_CTRL2_B38400; + break; + case 57600: + ctrl2 = TX3912_UART_CTRL2_B57600; + break; + case 115200: + default: + ctrl2 = TX3912_UART_CTRL2_B115200; + break; + } + + switch(bits) { + case 7: + ctrl1 = TX3912_UART_CTRL1_BIT_7; + break; + default: + break; + } + + switch(parity) { + case 'o': case 'O': + ctrl1 |= TX3912_UART_CTRL1_ENPARITY; + break; + case 'e': case 'E': + ctrl1 |= (TX3912_UART_CTRL1_ENPARITY | + TX3912_UART_CTRL1_EVENPARITY); + break; + default: + break; + } + + /* Write the control registers */ + outl(ctrl2, TX3912_UARTA_CTRL2); + outl(0x00000000, TX3912_UARTA_DMA_CTRL1); + outl(0x00000000, TX3912_UARTA_DMA_CTRL2); + outl((ctrl1 | TX3912_UART_CTRL1_ENUART), TX3912_UARTA_CTRL1); - /* Setup master clock for UART */ - scratch = inl(TX3912_CLK_CTRL_BASE); - scratch &= ~TX3912_CLK_CTRL_SIBMCLKDIV_MASK; - scratch |= ((0x2 << TX3912_CLK_CTRL_SIBMCLKDIV_SHIFT) & - TX3912_CLK_CTRL_SIBMCLKDIV_MASK) - | TX3912_CLK_CTRL_SIBMCLKDIR - | TX3912_CLK_CTRL_ENSIBMCLK - | TX3912_CLK_CTRL_CSERSEL; - outl(scratch, TX3912_CLK_CTRL_BASE); - - /* Configure UARTA clock */ - scratch = inl(TX3912_CLK_CTRL_BASE); - scratch |= ((0x3 << TX3912_CLK_CTRL_CSERDIV_SHIFT) & - TX3912_CLK_CTRL_CSERDIV_MASK) - | TX3912_CLK_CTRL_ENCSERCLK - | TX3912_CLK_CTRL_ENUARTACLK; - outl(scratch, TX3912_CLK_CTRL_BASE); - - /* Setup UARTA for 115200,8N1 */ - outl(0, TX3912_UARTA_BASE + TX3912_UART_CTRL1); - outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_BASE + TX3912_UART_CTRL2); - outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL1); - outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL2); - - /* Enable UARTA */ - outl(TX3912_UART_CTRL1_ENUART, TX3912_UARTA_BASE + TX3912_UART_CTRL1); - while (~inl(TX3912_UARTA_BASE + TX3912_UART_CTRL1) & - TX3912_UART_CTRL1_UARTON); + /* Loop until the UART is on */ + while(~inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_UARTON); return 0; } @@ -1059,5 +863,4 @@ { register_console(&sercons); } - #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/serial_tx3912.h linux-2.5/drivers/char/serial_tx3912.h --- linux-2.5.5/drivers/char/serial_tx3912.h Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/char/serial_tx3912.h Sun Mar 3 17:54:35 2002 @@ -1,8 +1,6 @@ /* * drivers/char/serial_tx3912.h * - * Copyright (C) 1999 Harald Koerfgen - * Copyright (C) 2000 Jim Pick * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) * * This program is free software; you can redistribute it and/or modify @@ -14,27 +12,6 @@ #include #include -/* UART Interrupt (Interrupt 2) bits (UARTA,UARTB) */ -#define UART_RX_INT 9 /* receiver holding register full (31, 21) */ -#define UART_RXOVERRUN_INT 8 /* receiver overrun error (30, 20) */ -#define UART_FRAMEERR_INT 7 /* receiver frame error (29, 19) */ -#define UART_BREAK_INT 6 /* received break signal (28, 18) */ -#define UART_PARITYERR_INT 5 /* receiver parity error (27, 17) */ -#define UART_TX_INT 4 /* transmit holding register empty (26, 16) */ -#define UART_TXOVERRUN_INT 3 /* transmit overrun error (25, 15) */ -#define UART_EMPTY_INT 2 /* both trans/recv regs empty (24, 14) */ -#define UART_DMAFULL_INT 1 /* DMA at end of buffer (23, 13) */ -#define UART_DMAHALF_INT 0 /* DMA halfway through buffer */ (22, 12) */ - -#define UARTA_SHIFT 22 -#define UARTB_SHIFT 12 - -#define INTTYPE(interrupttype) (1 << interrupttype) - -/* - * This driver can spew a whole lot of debugging output at you. If you - * need maximum performance, you should disable the DEBUG define. - */ #undef TX3912_UART_DEBUG #ifdef TX3912_UART_DEBUG @@ -53,39 +30,28 @@ #define TX3912_UART_DEBUG_FIRMWARE 0x00001000 #define TX3912_UART_DEBUG_MEMTEST 0x00002000 #define TX3912_UART_DEBUG_THROTTLE 0x00004000 +#define TX3912_UART_DEBUG_NO_TX 0xffffffdf #define TX3912_UART_DEBUG_ALL 0xffffffff -int rs_debug = TX3912_UART_DEBUG_ALL & ~TX3912_UART_DEBUG_TRANSMIT; - -#define rs_dprintk(f, str...) if (rs_debug & f) printk (str) -#define func_enter() rs_dprintk (TX3912_UART_DEBUG_FLOW, \ +#define rs_dprintk(f, str...) if(TX3912_UART_DEBUG_NO_TX & f) printk(str) +#define func_enter() rs_dprintk(TX3912_UART_DEBUG_FLOW, \ "rs: enter " __FUNCTION__ "\n") -#define func_exit() rs_dprintk (TX3912_UART_DEBUG_FLOW, \ +#define func_exit() rs_dprintk(TX3912_UART_DEBUG_FLOW, \ "rs: exit " __FUNCTION__ "\n") - #else #define rs_dprintk(f, str...) #define func_enter() #define func_exit() - -#endif /* TX3912_UART_DEBUG */ - -/* - * Number of serial ports - */ -#define TX3912_UART_NPORTS 2 +#endif /* * Hardware specific serial port structure */ struct rs_port { struct gs_port gs; /* Must be first field! */ - - unsigned long base; - int intshift; /* Register shift */ struct wait_queue *shutdown_wait; int stat_flags; - struct async_icount icount; /* Counters for 4 input IRQs */ + struct async_icount icount; /* Counters for 4 input IRQs */ int read_status_mask; int ignore_status_mask; int x_char; /* XON/XOFF character */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/serial_txx927.c linux-2.5/drivers/char/serial_txx927.c --- linux-2.5.5/drivers/char/serial_txx927.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/serial_txx927.c Mon Mar 4 01:51:25 2002 @@ -0,0 +1,2362 @@ +/* + * drivers/char/serial_txx927.c + * driver for TX[34]927 SIO + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Based on drivers/char/serial.c + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define SERIAL_DO_RESTART + +/* Set of debugging defines */ + +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT +#undef SERIAL_DEBUG_PCI +#undef SERIAL_DEBUG_AUTOCONF + +#ifdef MODULE +#undef CONFIG_TXX927_SERIAL_CONSOLE +#endif + +#define CONFIG_SERIAL_RSA + +#define RS_STROBE_TIME (10*HZ) +#define RS_ISR_PASS_LIMIT 256 + +/* + * End of serial driver configuration section. + */ + +#ifdef MODVERSIONS +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_TXX927_SERIAL_CONSOLE +#include +#endif +#ifdef CONFIG_MAGIC_SYSRQ +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_TOSHIBA_JMR3927 +#include +#endif + +#define _INLINE_ inline + +#ifdef CONFIG_MAC_SERIAL +#define SERIAL_DEV_OFFSET 2 +#else +#define SERIAL_DEV_OFFSET 0 +#endif + +static char *serial_name = "TXx927 Serial driver"; +static char *serial_version = "0.02"; + +static DECLARE_TASK_QUEUE(tq_serial); + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +static struct timer_list serial_timer; + +extern unsigned long get_txx927_uart_baud(void); + +/* serial subtype definitions */ +#ifndef SERIAL_TYPE_NORMAL +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 +#endif + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* + * IRQ_timeout - How long the timeout should be for each IRQ + * should be after the IRQ has been active. + */ + +static struct async_struct *IRQ_ports[NR_IRQS]; +static int IRQ_timeout[NR_IRQS]; +#ifdef CONFIG_TXX927_SERIAL_CONSOLE +static struct console sercons; +#endif +#if defined(CONFIG_TXX927_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +static unsigned long break_pressed; /* break, really ... */ +#endif + +static void change_speed(struct async_struct *info, struct termios *old); +static void rs_wait_until_sent(struct tty_struct *tty, int timeout); + +#ifndef PREPARE_FUNC +#define PREPARE_FUNC(dev) (dev->prepare) +#define ACTIVATE_FUNC(dev) (dev->activate) +#define DEACTIVATE_FUNC(dev) (dev->deactivate) +#endif + +#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) + + +#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) +#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ + kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s) +#else +#define DBG_CNT(s) +#endif + +#define SERIAL_DRIVER_NAME "TXx927SIO" + +#ifdef CONFIG_SERIAL +/* "ttyS","cua" is used for standard serial driver */ +#define TXX927_TTY_NAME "ttySC" +#define TXX927_TTY_MINOR_START (64 + 16) /* ttySC0(80), ttySC1(81) */ +#define TXX927_CU_NAME "cuac" +#define TXX927_SERIAL_BH TXX927SERIAL_BH +#else +/* acts like standard serial driver */ +#define TXX927_TTY_NAME "ttyS" +#define TXX927_TTY_MINOR_START 64 +#define TXX927_CU_NAME "cua" +#define TXX927_SERIAL_BH SERIAL_BH +#endif +#define TXX927_TTY_MAJOR TTY_MAJOR +#define TXX927_TTYAUX_MAJOR TTYAUX_MAJOR + +#define ASYNC_HAVE_CTS_LINE ASYNC_BOOT_AUTOCONF /* reuse */ + +static struct serial_state rs_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) + +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the copy_from_user blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *tmp_buf; +#ifdef DECLARE_MUTEX +static DECLARE_MUTEX(tmp_buf_sem); +#else +static struct semaphore tmp_buf_sem = MUTEX; +#endif + +static inline int serial_paranoia_check(struct async_struct *info, + kdev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%s) in %s\n"; + static const char *badinfo = + "Warning: null async_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +static inline struct txx927_sio_reg *sio_reg(struct async_struct *info) +{ + return (struct txx927_sio_reg *)info->port; +} + +/* + * Wait for transmitter & holding register to empty + */ +static inline void wait_for_xmitr(struct async_struct *info) +{ + unsigned int tmout = 1000000; + + do { + if (--tmout == 0) break; + } while (!(sio_reg(info)->cisr & TXx927_SICISR_TXALS)); +} + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + + save_flags(flags); cli(); + if (info->IER & UART_IER_THRI) { + info->IER &= ~UART_IER_THRI; + sio_reg(info)->dicr &= ~TXx927_SIDICR_TIE; + } + restore_flags(flags); +} + +static void rs_start(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_start")) + return; + + save_flags(flags); cli(); + if (info->xmit.head != info->xmit.tail + && info->xmit.buf + && !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + sio_reg(info)->dicr |= TXx927_SIDICR_TIE; + } + restore_flags(flags); +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static _INLINE_ void rs_sched_event(struct async_struct *info, + int event) +{ + info->event |= 1 << event; + queue_task(&info->tqueue, &tq_serial); + mark_bh(TXX927_SERIAL_BH); +} + +static _INLINE_ void receive_chars(struct async_struct *info, + int *status) +{ + struct tty_struct *tty = info->tty; + unsigned char ch; + int ignored = 0; + struct async_icount *icount; + + icount = &info->state->icount; + do { + ch = sio_reg(info)->rfifo; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; + *tty->flip.char_buf_ptr = ch; + icount->rx++; + +#ifdef SERIAL_DEBUG_INTR + printk("DR%02x:%02x...", ch, *status); +#endif + *tty->flip.flag_buf_ptr = 0; + if (*status & (TXx927_SIDISR_UBRK | TXx927_SIDISR_UPER | + TXx927_SIDISR_UFER | TXx927_SIDISR_UOER)) { + /* + * For statistics only + */ + if (*status & TXx927_SIDISR_UBRK) { + *status &= ~(TXx927_SIDISR_UFER | TXx927_SIDISR_UPER); + icount->brk++; + } else if (*status & TXx927_SIDISR_UPER) + icount->parity++; + else if (*status & TXx927_SIDISR_UFER) + icount->frame++; + if (*status & TXx927_SIDISR_UOER) + icount->overrun++; + + /* + * Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + */ + if (*status & info->ignore_status_mask) { + if (++ignored > 100) + break; + goto ignore_char; + } + *status &= info->read_status_mask; + + if (*status & (TXx927_SIDISR_UBRK)) { +#ifdef SERIAL_DEBUG_INTR + printk("handling break...."); +#endif + *tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } else if (*status & TXx927_SIDISR_UPER) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (*status & TXx927_SIDISR_UFER) + *tty->flip.flag_buf_ptr = TTY_FRAME; + if (*status & TXx927_SIDISR_UOER) { + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + } + } + } + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: + *status = sio_reg(info)->disr; + } while (!(*status & TXx927_SIDISR_UVALID)); + + tty_flip_buffer_push(tty); +} + +static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) +{ + int count; + + wait_for_xmitr(info); + + if (info->x_char) { + sio_reg(info)->tfifo = info->x_char; + info->state->icount.tx++; + info->x_char = 0; + if (intr_done) + *intr_done = 0; + return; + } + + if (info->xmit.head == info->xmit.tail + || info->tty->stopped + || info->tty->hw_stopped) { + sio_reg(info)->dicr &= ~TXx927_SIDICR_TIE; + return; + } + + count = info->xmit_fifo_size; + do { + sio_reg(info)->tfifo = info->xmit.buf[info->xmit.tail++]; + info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1); + info->state->icount.tx++; + if (info->xmit.head == info->xmit.tail) + break; + } while (--count > 0); + + if (CIRC_CNT(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE) < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif + if (intr_done) + *intr_done = 0; + + if (info->xmit.head == info->xmit.tail) { + sio_reg(info)->dicr &= ~TXx927_SIDICR_TIE; + } +} + +static _INLINE_ void check_modem_status(struct async_struct *info) +{ + /* RTS/CTS are controled by HW. (if possible) */ +} + +/* + * This is the serial driver's interrupt routine for a single port + */ +static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) +{ + int status; + int pass_counter = 0; + struct async_struct * info; + +#ifdef SERIAL_DEBUG_INTR + printk("rs_interrupt_single(%d)...", irq); +#endif + + info = IRQ_ports[irq]; + if (!info || !info->tty) + return; + + do { + status = sio_reg(info)->disr; +#ifdef SERIAL_DEBUG_INTR + printk("status = %x...", status); +#endif + if (!(sio_reg(info)->dicr & TXx927_SIDICR_TIE)) + status &= ~TXx927_SIDISR_TDIS; + if (!(status & (TXx927_SIDISR_TDIS | TXx927_SIDISR_RDIS | TXx927_SIDISR_TOUT))) + break; + + if (status & TXx927_SIDISR_RDIS) + receive_chars(info, &status); + check_modem_status(info); + if (status & TXx927_SIDISR_TDIS) + transmit_chars(info, 0); + /* Clear TX/RX Int. Status */ + sio_reg(info)->disr &= ~(TXx927_SIDISR_TDIS | TXx927_SIDISR_RDIS | TXx927_SIDISR_TOUT); + + if (pass_counter++ > RS_ISR_PASS_LIMIT) { +#ifdef SERIAL_DEBUG_INTR + printk("rs_single loop break.\n"); +#endif + break; + } + } while (1); + info->last_active = jiffies; +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void do_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void do_softint(void *private_) +{ + struct async_struct *info = (struct async_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif + } +} + +/* + * This subroutine is called when the RS_TIMER goes off. It is used + * by the serial driver to handle ports that do not have an interrupt + * (irq=0). This doesn't work very well for 16450's, but gives barely + * passable results for a 16550A. (Although at the expense of much + * CPU overhead). + */ +static void rs_timer(unsigned long dummy) +{ + static unsigned long last_strobe; + struct async_struct *info; + unsigned int i; + unsigned long flags; + + if ((jiffies - last_strobe) >= RS_STROBE_TIME) { + for (i=0; i < NR_IRQS; i++) { + info = IRQ_ports[i]; + if (!info) + continue; + save_flags(flags); cli(); + rs_interrupt_single(i, NULL, NULL); + restore_flags(flags); + } + } + last_strobe = jiffies; + mod_timer(&serial_timer, jiffies + RS_STROBE_TIME); + +#if 0 + if (IRQ_ports[0]) { + save_flags(flags); cli(); + rs_interrupt_single(0, NULL, NULL); + restore_flags(flags); + + mod_timer(&serial_timer, jiffies + IRQ_timeout[0]); + } +#endif +} + +/* + * --------------------------------------------------------------- + * Low level utility subroutines for the serial driver: routines to + * figure out the appropriate timeout for an interrupt chain, routines + * to initialize and startup a serial port, and routines to shutdown a + * serial port. Useful stuff like that. + * --------------------------------------------------------------- + */ + +/* + * This routine figures out the correct timeout for a particular IRQ. + * It uses the smallest timeout of all of the serial ports in a + * particular interrupt chain. Now only used for IRQ 0.... + */ +static void figure_IRQ_timeout(int irq) +{ + struct async_struct *info; + int timeout = 60*HZ; /* 60 seconds === a long time :-) */ + + info = IRQ_ports[irq]; + if (!info) { + IRQ_timeout[irq] = 60*HZ; + return; + } + while (info) { + if (info->timeout < timeout) + timeout = info->timeout; + info = info->next_port; + } + if (!irq) + timeout = timeout / 2; + IRQ_timeout[irq] = timeout ? timeout : 1; +} + +static int startup(struct async_struct * info) +{ + unsigned long flags; + int retval=0; + struct serial_state *state= info->state; + unsigned long page; + + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + + if (!state->port) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + goto errout; + } + if (info->xmit.buf) + free_page(page); + else + info->xmit.buf = (unsigned char *) page; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttys%d (irq %d)...", info->line, state->irq); +#endif + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + sio_reg(info)->fcr |= TXx927_SIFCR_TFRST | TXx927_SIFCR_RFRST | + TXx927_SIFCR_FRSTE; + /* clear reset */ + sio_reg(info)->fcr &= ~(TXx927_SIFCR_TFRST | TXx927_SIFCR_RFRST | + TXx927_SIFCR_FRSTE); + + /* + * Allocate the IRQ if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + retval = -EBUSY; + goto errout; + } + + retval = request_irq(state->irq, rs_interrupt_single, + SA_INTERRUPT, + "txx927serial", NULL); + if (retval) { + if (capable(CAP_SYS_ADMIN)) { + if (info->tty) + set_bit(TTY_IO_ERROR, + &info->tty->flags); + retval = 0; + } + goto errout; + } + } + + /* + * Insert serial port into IRQ chain. + */ + info->prev_port = 0; + info->next_port = IRQ_ports[state->irq]; + if (info->next_port) + info->next_port->prev_port = info; + IRQ_ports[state->irq] = info; + figure_IRQ_timeout(state->irq); + + /* + * Clear the interrupt registers. + */ + sio_reg(info)->disr = 0; + + /* + * Now, initialize the UART + */ + /* HW RTS/CTS control */ + if (state->flags & ASYNC_HAVE_CTS_LINE) + sio_reg(info)->flcr = TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | + TXx927_SIFLCR_RTSTL_MAX /* 15 */; + /* Enable RX/TX */ + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RSDE | TXx927_SIFLCR_TSDE); + + /* + * Finally, enable interrupts + */ + sio_reg(info)->dicr = TXx927_SIDICR_RIE; + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit.head = info->xmit.tail = 0; + + /* + * Set up the tty->alt_speed kludge + */ + if (info->tty) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + } + + /* + * and set the speed of the serial port + */ + change_speed(info, 0); + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return 0; + +errout: + restore_flags(flags); + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct async_struct * info) +{ + unsigned long flags; + struct serial_state *state; + int retval; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + state = info->state; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....", info->line, + state->irq); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + figure_IRQ_timeout(state->irq); + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, NULL); + retval = request_irq(state->irq, rs_interrupt_single, + SA_INTERRUPT, "txx927serial", NULL); + + if (retval) + printk(KERN_WARNING "txx927serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, NULL); + } + + if (info->xmit.buf) { + free_page((unsigned long) info->xmit.buf); + info->xmit.buf = 0; + } + + sio_reg(info)->dicr = 0; /* disable all intrs */ + + /* disable break condition */ + sio_reg(info)->flcr &= ~TXx927_SIFLCR_TBRK; + + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { + /* drop RTS */ + sio_reg(info)->flcr |= TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE; + /* TXx927-SIO can not control DTR... */ + } + + /* reset FIFO's */ + sio_reg(info)->fcr |= TXx927_SIFCR_TFRST | TXx927_SIFCR_RFRST | + TXx927_SIFCR_FRSTE; + /* clear reset */ + sio_reg(info)->fcr &= ~(TXx927_SIFCR_TFRST | TXx927_SIFCR_RFRST | + TXx927_SIFCR_FRSTE); + + /* DON'T disable Rx/Tx here, ie. DON'T set either + * TXx927_SIFLCR_RSDE or TXx927_SIFLCR_TSDE in flcr + */ + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void change_speed(struct async_struct *info, + struct termios *old_termios) +{ + int quot = 0, baud_base, baud; + unsigned cflag, cval; + int bits; + unsigned long flags; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + if (!info->port) + return; + + cval = sio_reg(info)->lcr; + /* byte size and parity */ + cval &= ~TXx927_SILCR_UMODE_MASK; + switch (cflag & CSIZE) { + case CS7: + cval |= TXx927_SILCR_UMODE_7BIT; + bits = 9; + break; + case CS5: /* not supported */ + case CS6: /* not supported */ + case CS8: + default: + cval |= TXx927_SILCR_UMODE_8BIT; + bits = 10; + break; + } + cval &= ~TXx927_SILCR_USBL_MASK; + if (cflag & CSTOPB) { + cval |= TXx927_SILCR_USBL_2BIT; + bits++; + } else { + cval |= TXx927_SILCR_USBL_1BIT; + } + + cval &= ~(TXx927_SILCR_UPEN|TXx927_SILCR_UEPS); + if (cflag & PARENB) { + cval |= TXx927_SILCR_UPEN; + bits++; + } + if (!(cflag & PARODD)) + cval |= TXx927_SILCR_UEPS; + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ + baud_base = info->state->baud_base; + quot = (baud_base + baud / 2) / baud; + /* If the quotient is zero refuse the change */ + if (!quot && old_termios) { + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; + quot = (baud_base + baud / 2) / baud; + } + /* As a last resort, if the quotient is zero, default to 9600 bps */ + if (!quot) + quot = (baud_base + 9600 / 2) / 9600; + info->quot = quot; + info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + /* CTS flow control flag */ + if (cflag & CRTSCTS) { + info->flags |= ASYNC_CTS_FLOW; + if (info->state->flags & ASYNC_HAVE_CTS_LINE) + sio_reg(info)->flcr = TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | + TXx927_SIFLCR_RTSTL_MAX /* 15 */; + } else { + info->flags &= ~ASYNC_CTS_FLOW; + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | TXx927_SIFLCR_RSDE | TXx927_SIFLCR_TSDE); + } + + /* + * Set up parity check flag + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + info->read_status_mask = TXx927_SIDISR_UOER | + TXx927_SIDISR_TDIS | TXx927_SIDISR_RDIS; + if (I_INPCK(info->tty)) + info->read_status_mask |= TXx927_SIDISR_UFER | TXx927_SIDISR_UPER; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= TXx927_SIDISR_UBRK; + + /* + * Characters to ignore + */ + info->ignore_status_mask = 0; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= TXx927_SIDISR_UPER | TXx927_SIDISR_UFER; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= TXx927_SIDISR_UBRK; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= TXx927_SIDISR_UOER; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + info->ignore_status_mask |= TXx927_SIDISR_RDIS; + save_flags(flags); cli(); + sio_reg(info)->lcr = cval | TXx927_SILCR_SCS_IMCLK_BG; + sio_reg(info)->bgr = quot | TXx927_SIBGR_BCLK_T0; + restore_flags(flags); +} + +static void rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_put_char")) + return; + + if (!tty || !info->xmit.buf) + return; + + save_flags(flags); cli(); + if (CIRC_SPACE(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE) == 0) { + restore_flags(flags); + return; + } + + info->xmit.buf[info->xmit.head++] = ch; + info->xmit.head &= SERIAL_XMIT_SIZE-1; + restore_flags(flags); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) + return; + + if (info->xmit.head == info->xmit.tail + || tty->stopped + || tty->hw_stopped + || !info->xmit.buf) + return; + + save_flags(flags); cli(); + sio_reg(info)->dicr |= TXx927_SIDICR_TIE; + restore_flags(flags); +} + +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_write")) + return 0; + + if (!tty || !info->xmit.buf || !tmp_buf) + return 0; + + save_flags(flags); + + if (from_user) { + down(&tmp_buf_sem); + while (1) { + int c1; + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + + if (count < c) + c = count; + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + cli(); + c1 = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + + if (c1 < c) + c = c1; + memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); + info->xmit.head = ((info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1)); + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + cli(); + while (1) { + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + + if (count < c) + c = count; + if (c <= 0) { + break; + } + memcpy(info->xmit.buf + info->xmit.head, buf, c); + info->xmit.head = ((info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1)); + buf += c; + count -= c; + ret += c; + } + restore_flags(flags); + } + if (info->xmit.head != info->xmit.tail + && !tty->stopped + && !tty->hw_stopped + && !(info->IER & UART_IER_THRI)) + sio_reg(info)->dicr |= TXx927_SIDICR_TIE; + + return ret; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_write_room")) + return 0; + + return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) + return 0; + + return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) + return; + save_flags(flags); cli(); + info->xmit.head = info->xmit.tail = 0; + restore_flags(flags); + wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void rs_send_xchar(struct tty_struct *tty, char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + + if (serial_paranoia_check(info, tty->device, "rs_send_char")) + return; + + info->x_char = ch; + if (ch) { + /* Make sure transmit interrupts are on */ + sio_reg(info)->dicr |= TXx927_SIDICR_TIE; + } +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + rs_send_xchar(tty, STOP_CHAR(tty)); + + if (tty->termios->c_cflag & CRTSCTS) { + save_flags(flags); cli(); + /* drop RTS */ + sio_reg(info)->flcr |= TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE; + restore_flags(flags); + } +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + rs_send_xchar(tty, START_CHAR(tty)); + } + if (tty->termios->c_cflag & CRTSCTS) { + save_flags(flags); cli(); + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + restore_flags(flags); + } +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_modem_info(struct async_struct * info, unsigned int *value) +{ + unsigned int result; + unsigned long flags; + + save_flags(flags); cli(); + result = ((sio_reg(info)->flcr & TXx927_SIFLCR_RTSSC) ? 0 : TIOCM_RTS) + | ((sio_reg(info)->cisr & TXx927_SICISR_CTSS) ? 0 : TIOCM_CTS); + restore_flags(flags); + return put_user(result,value); +} + +static int set_modem_info(struct async_struct * info, unsigned int cmd, + unsigned int *value) +{ + int error; + unsigned int arg; + unsigned long flags; + + error = get_user(arg, value); + if (error) + return error; + save_flags(flags); cli(); + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + sio_reg(info)->flcr |= TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE; + break; + case TIOCMSET: + sio_reg(info)->flcr = + (sio_reg(info)->flcr & ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE)) | + ((arg & TIOCM_RTS) ? 0 : TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + break; + default: + error = -EINVAL; + } + restore_flags(flags); + return error; +} + +/* + * rs_break() --- routine which turns the break handling on or off + */ +static void rs_break(struct tty_struct *tty, int break_state) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_break")) + return; + + if (!info->port) + return; + save_flags(flags); cli(); + if (break_state == -1) + sio_reg(info)->flcr |= TXx927_SIFLCR_TBRK; + else + sio_reg(info)->flcr &= ~TXx927_SIFLCR_TBRK; + restore_flags(flags); +} + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + return 0; + case TIOCGSERIAL: + printk("TIOCGSERIAL\n"); + return 0; + case TIOCSSERIAL: + printk("TIOCSSERIAL\n"); + return 0; + case TIOCSERCONFIG: + printk("TIOCSERCONFIG\n"); + return 0; + + case TIOCSERGETLSR: /* Get line status register */ + printk("TIOCSERGETLSR\n"); + return 0; + + case TIOCSERGSTRUCT: + printk("TIOCSERGSTRUCT\n"); + return 0; + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + printk("TIOCMIWAIT\n"); + return 0; + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + printk("TIOCGICOUNT\n"); + return 0; + + case TIOCSERGWILD: + case TIOCSERSWILD: + /* "setserial -W" is called in Debian boot */ + printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + unsigned int cflag = tty->termios->c_cflag; + + if ( (cflag == old_termios->c_cflag) + && ( RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + change_speed(info, old_termios); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && + !(cflag & CBAUD)) { + save_flags(flags); cli(); + sio_reg(info)->flcr |= TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE; + restore_flags(flags); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + (cflag & CBAUD)) { + if (!(tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) { + save_flags(flags); cli(); + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + restore_flags(flags); + } + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->device, "rs_close")) + return; + + state = info->state; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + restore_flags(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttys%d, count = %d\n", info->line, state->count); +#endif + if ((tty->count == 1) && (state->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk(KERN_WARNING "rs_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { + printk(KERN_WARNING "rs_close: bad serial port count for ttys%d: %d\n", + info->line, state->count); + state->count = 0; + } + if (state->count) { + restore_flags(flags); + return; + } + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->state->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->state->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->read_status_mask &= ~TXx927_SIDISR_RDIS; + if (info->flags & ASYNC_INITIALIZED) { +#if 0 + sio_reg(info)->dicr &= ~TXx927_SIDICR_RIE; +#endif + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + rs_wait_until_sent(tty, info->timeout); + } + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + restore_flags(flags); +} + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long orig_jiffies, char_time; + int cisr; + + if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) + return; + + if (info->xmit_fifo_size == 0) + return; /* Just in case.... */ + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout) + char_time = MIN(char_time, timeout); + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than info->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*info->timeout. + */ + if (!timeout || timeout > 2*info->timeout) + timeout = 2*info->timeout; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); + printk("jiff=%lu...", jiffies); +#endif + while (!((cisr = sio_reg(info)->cisr) & TXx927_SICISR_TXALS)) { +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("cisr = %d (jiff=%lu)...", cisr, jiffies); +#endif + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; /* make us low-priority */ + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + current->state = TASK_RUNNING; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("cisr = %d (jiff=%lu)...done\n", cisr, jiffies); +#endif +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_hangup(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state = info->state; + + if (serial_paranoia_check(info, tty->device, "rs_hangup")) + return; + + state = info->state; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + state->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct async_struct *info) +{ + DECLARE_WAITQUEUE(wait, current); + struct serial_state *state = info->state; + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (state->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, state->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + state->line, state->count); +#endif + save_flags(flags); cli(); + if (!tty_hung_up_p(filp)) { + extra_count = 1; + state->count--; + } + restore_flags(flags); + info->blocked_open++; + while (1) { + save_flags(flags); cli(); + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)) + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RTSSC|TXx927_SIFLCR_RSDE); + restore_flags(flags); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING)) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (extra_count) + state->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static int get_async_struct(int line, struct async_struct **ret_info) +{ + struct async_struct *info; + struct serial_state *sstate; + +#ifdef REMOTE_DEBUG + if (kdb_port_info.state && line == kdb_port_info.line) + return -ENODEV; +#endif + sstate = rs_table + line; + sstate->count++; + if (sstate->info) { + *ret_info = sstate->info; + return 0; + } + info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); + if (!info) { + sstate->count--; + return -ENOMEM; + } + memset(info, 0, sizeof(struct async_struct)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); + info->magic = SERIAL_MAGIC; + info->port = sstate->port; + info->flags = sstate->flags; + info->io_type = sstate->io_type; + info->xmit_fifo_size = sstate->xmit_fifo_size; + info->line = line; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->state = sstate; + if (sstate->info) { + kfree(info); + *ret_info = sstate->info; + return 0; + } + *ret_info = sstate->info = info; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct async_struct *info; + int retval, line; + unsigned long page; + + line = minor(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) { + return -ENODEV; + } + retval = get_async_struct(line, &info); + if (retval) { + return retval; + } + tty->driver_data = info; + info->tty = tty; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->state->count); +#endif + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) { + return -ENOMEM; + } + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) { + return retval; + } + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + + if ((info->state->count == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->state->normal_termios; + else + *tty->termios = info->state->callout_termios; + change_speed(info, 0); + } +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + if (sercons.cflag && sercons.index == line) { + tty->termios->c_cflag = sercons.cflag; + sercons.cflag = 0; + change_speed(info, 0); + } +#endif + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttys%d successful...", info->line); +#endif + return 0; +} + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, struct serial_state *state) +{ + struct async_struct *info = state->info, scr_info; + char stat_buf[30]; + int ret; + unsigned long flags; + + ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d", + state->line, SERIAL_DRIVER_NAME, + state->port, state->irq); + + if (!state->port) { + ret += sprintf(buf+ret, "\n"); + return ret; + } + + /* + * Figure out the current RS-232 lines + */ + if (!info) { + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->port = state->port; + info->flags = state->flags; + info->quot = 0; + info->tty = 0; + } + + stat_buf[0] = 0; + stat_buf[1] = 0; + save_flags(flags); cli(); + if (!(sio_reg(info)->flcr & TXx927_SIFLCR_RTSSC)) + strcat(stat_buf, "|RTS"); + if (!(sio_reg(info)->cisr & TXx927_SICISR_CTSS)) + strcat(stat_buf, "|CTS"); + restore_flags(flags); + + if (info->quot) { + ret += sprintf(buf+ret, " baud:%d", + state->baud_base / info->quot); + } + + ret += sprintf(buf+ret, " tx:%d rx:%d", + state->icount.tx, state->icount.rx); + + if (state->icount.frame) + ret += sprintf(buf+ret, " fe:%d", state->icount.frame); + + if (state->icount.parity) + ret += sprintf(buf+ret, " pe:%d", state->icount.parity); + + if (state->icount.brk) + ret += sprintf(buf+ret, " brk:%d", state->icount.brk); + + if (state->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); + + /* + * Last thing is the RS-232 status lines + */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + return ret; +} + +static int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i, len = 0, l; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + l = line_info(page + len, &rs_table[i]); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * --------------------------------------------------------------------- + * rs_init() and friends + * + * rs_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static _INLINE_ void show_serial_version(void) +{ + printk(KERN_INFO "%s version %s\n", serial_name, serial_version); +} + +/* + * The serial driver boot-time initialization code! + */ +static int __init rs_init(void) +{ + int i; + struct serial_state * state; + + if (rs_table[0].port == 0) + return -ENODEV; + + init_bh(TXX927_SERIAL_BH, do_serial_bh); + init_timer(&serial_timer); + serial_timer.function = rs_timer; + mod_timer(&serial_timer, jiffies + RS_STROBE_TIME); + + for (i = 0; i < NR_IRQS; i++) { + IRQ_ports[i] = 0; + IRQ_timeout[i] = 0; + } +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + /* + * The interrupt of the serial console port + * can't be shared. + */ + if (sercons.flags & CON_CONSDEV) { + for(i = 0; i < NR_PORTS; i++) + if (i != sercons.index && + rs_table[i].irq == rs_table[sercons.index].irq) + rs_table[i].irq = 0; + } +#endif + show_serial_version(); + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "txx927serial"; +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) + serial_driver.name = "tts/%d"; +#else + serial_driver.name = "ttyS"; +#endif + serial_driver.major = TXX927_TTY_MAJOR; + serial_driver.minor_start = TXX927_TTY_MINOR_START + SERIAL_DEV_OFFSET; + serial_driver.num = NR_PORTS; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + serial_driver.put_char = rs_put_char; + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.send_xchar = rs_send_xchar; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; + serial_driver.break_ctl = rs_break; + serial_driver.wait_until_sent = rs_wait_until_sent; + serial_driver.read_proc = rs_read_proc; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) + callout_driver.name = "cua/%d"; +#else + callout_driver.name = "cua"; +#endif + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; + + if (tty_register_driver(&serial_driver)){ + panic("Couldn't register serial driver\n"); + } + if (tty_register_driver(&callout_driver)) { + panic("Couldn't register callout driver\n"); + } + + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + state->magic = SSTATE_MAGIC; + state->line = i; + state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; + state->callout_termios = callout_driver.init_termios; + state->normal_termios = serial_driver.init_termios; + state->icount.cts = state->icount.dsr = + state->icount.rng = state->icount.dcd = 0; + state->icount.rx = state->icount.tx = 0; + state->icount.frame = state->icount.parity = 0; + state->icount.overrun = state->icount.brk = 0; + state->irq = irq_cannonicalize(state->irq); + state->xmit_fifo_size = TXx927_SIO_TX_FIFO; + if (state->hub6) + state->io_type = SERIAL_IO_HUB6; + if (state->port) { + continue; + } + } + + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + if (state->type == PORT_UNKNOWN) { + continue; + } + printk(KERN_INFO "%s%02d at 0x%04lx (irq = %d) is a %s\n", + TXX927_TTY_NAME, + state->line, + state->port, state->irq, + SERIAL_DRIVER_NAME); + tty_register_devfs(&serial_driver, 0, + serial_driver.minor_start + state->line); + tty_register_devfs(&callout_driver, 0, + callout_driver.minor_start + state->line); + } + return 0; +} + +static void __exit rs_fini(void) +{ + unsigned long flags; + int e1, e2; + int i; + struct async_struct *info; + + del_timer_sync(&serial_timer); + save_flags(flags); cli(); + remove_bh(TXX927_SERIAL_BH); + if ((e1 = tty_unregister_driver(&serial_driver))) + printk(KERN_WARNING "serial: failed to unregister serial driver (%d)\n", + e1); + if ((e2 = tty_unregister_driver(&callout_driver))) + printk(KERN_WARNING "serial: failed to unregister callout driver (%d)\n", + e2); + restore_flags(flags); + + for (i = 0; i < NR_PORTS; i++) { + if ((info = rs_table[i].info)) { + rs_table[i].info = NULL; + kfree(info); + } + } + if (tmp_buf) { + unsigned long pg = (unsigned long) tmp_buf; + tmp_buf = NULL; + free_page(pg); + } +} + +module_init(rs_init); +module_exit(rs_fini); +MODULE_DESCRIPTION("TXX927 serial driver"); + +/* + * ------------------------------------------------------------ + * Serial console driver + * ------------------------------------------------------------ + */ +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + +static struct async_struct async_sercons; + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void serial_console_write(struct console *co, const char *s, + unsigned count) +{ + static struct async_struct *info = &async_sercons; + int ier; + unsigned i; + + /* + * First save the IER then disable the interrupts + */ + ier = sio_reg(info)->dicr; + sio_reg(info)->dicr = 0; + + + /* + * Now, do each character + */ + for (i = 0; i < count; i++, s++) { + wait_for_xmitr(info); + + /* + * Send the character out. + * If a LF, also do CR... + */ + sio_reg(info)->tfifo = *s; + if (*s == 10) { + wait_for_xmitr(info); + sio_reg(info)->tfifo = 13; + } + } + + /* + * Finally, Wait for transmitter & holding register to empty + * and restore the IER + */ + wait_for_xmitr(info); + sio_reg(info)->dicr = ier; +} + +/* + * Receive character from the serial port + */ +static int serial_console_wait_key(struct console *co) +{ + static struct async_struct *info = &async_sercons; + int ier; + int c; + + /* + * First save the IER then disable the interrupts so + * that the real driver for the port does not get the + * character. + */ + ier = sio_reg(info)->dicr; + sio_reg(info)->dicr = 0; + + while (sio_reg(info)->disr & TXx927_SIDISR_UVALID) + ; + c = sio_reg(info)->rfifo; + + /* + * Restore the interrupts + */ + sio_reg(info)->dicr = ier; + + return c; +} + +static kdev_t serial_console_device(struct console *c) +{ + return mk_kdev(TXX927_TTY_MAJOR, TXX927_TTY_MINOR_START + c->index); +} + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first rs_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +static int serial_console_setup(struct console *co, char *options) +{ + static struct async_struct *info; + struct serial_state *state; + unsigned cval; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + int quot = 0; + char *s; + + if (co->index < 0 || co->index >= NR_PORTS) { + return -1; + } + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch(baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + case 9600: + default: + cflag |= B9600; + break; + } + switch(bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; + } + switch(parity) { + case 'o': case 'O': + cflag |= PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; + + /* + * Divisor, bytesize and parity + */ + state = rs_table + co->index; + info = &async_sercons; + info->magic = SERIAL_MAGIC; + info->state = state; + info->port = state->port; + info->flags = state->flags; + info->io_type = state->io_type; + info->iomem_base = state->iomem_base; + info->iomem_reg_shift = state->iomem_reg_shift; + quot = state->baud_base / baud; + + switch (cflag & CSIZE) { + case CS7: cval = TXx927_SILCR_UMODE_7BIT; break; + default: + case CS8: cval = TXx927_SILCR_UMODE_8BIT; break; + } + if (cflag & CSTOPB) + cval |= TXx927_SILCR_USBL_2BIT; + else + cval |= TXx927_SILCR_USBL_1BIT; + if (cflag & PARENB) + cval |= TXx927_SILCR_UPEN; + if (!(cflag & PARODD)) + cval |= TXx927_SILCR_UEPS; + + /* + * Disable UART interrupts, set DTR and RTS high + * and set speed. + */ + sio_reg(info)->dicr = 0; + sio_reg(info)->lcr = cval | TXx927_SILCR_SCS_IMCLK_BG; + sio_reg(info)->bgr = quot | TXx927_SIBGR_BCLK_T0; + /* HW RTS/CTS control */ + if (info->flags & ASYNC_HAVE_CTS_LINE) + sio_reg(info)->flcr = TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | + TXx927_SIFLCR_RTSTL_MAX /* 15 */; + /* Enable RX/TX */ + sio_reg(info)->flcr &= ~(TXx927_SIFLCR_RSDE | TXx927_SIFLCR_TSDE); + + return 0; +} + +static struct console sercons = { + name: TXX927_TTY_NAME, + write: serial_console_write, + device: serial_console_device, + wait_key: serial_console_wait_key, + setup: serial_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +/* + * Register console. + */ +void __init txx927_console_init(void) +{ + register_console(&sercons); +} +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/sh-sci.c linux-2.5/drivers/char/sh-sci.c --- linux-2.5.5/drivers/char/sh-sci.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/char/sh-sci.c Sun Jan 6 01:38:27 2002 @@ -1040,7 +1040,9 @@ sci_driver.table = sci_table; sci_driver.termios = sci_termios; sci_driver.termios_locked = sci_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + sci_driver.console = &sercons; +#endif sci_driver.open = sci_open; sci_driver.close = gs_close; sci_driver.write = gs_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/shwdt.c linux-2.5/drivers/char/shwdt.c --- linux-2.5.5/drivers/char/shwdt.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/char/shwdt.c Fri Jan 25 15:48:04 2002 @@ -9,6 +9,9 @@ * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. + * + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT */ #include #include @@ -88,6 +91,15 @@ static struct timer_list timer; static unsigned long next_heartbeat; +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + /** * sh_wdt_write_cnt - Write to Counter * @@ -175,6 +187,10 @@ if (test_and_set_bit(0, &sh_is_open)) return -EBUSY; + if (nowayout) { + MOD_INC_USE_COUNT; + } + sh_wdt_start(); break; @@ -196,9 +212,9 @@ static int sh_wdt_close(struct inode *inode, struct file *file) { if (minor(inode->i_rdev) == WATCHDOG_MINOR) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - sh_wdt_stop(); -#endif + if (!nowayout) { + sh_wdt_stop(); + } clear_bit(0, &sh_is_open); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/softdog.c linux-2.5/drivers/char/softdog.c --- linux-2.5.5/drivers/char/softdog.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/char/softdog.c Sun Jan 13 22:15:01 2002 @@ -1,5 +1,5 @@ /* - * SoftDog 0.05: A Software Watchdog Device + * SoftDog 0.06: A Software Watchdog Device * * (c) Copyright 1996 Alan Cox , All Rights Reserved. * http://www.redhat.com @@ -26,6 +26,10 @@ * * 19980911 Alan Cox * Made SMP safe for 2.3.x + * + * 20011214 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Didn't add timeout option, as soft_margin option already exists. */ #include @@ -46,6 +50,15 @@ static int soft_margin = TIMER_MARGIN; /* in seconds */ MODULE_PARM(soft_margin,"i"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); MODULE_LICENSE("GPL"); /* @@ -83,9 +96,9 @@ { if(timer_alive) return -EBUSY; -#ifdef CONFIG_WATCHDOG_NOWAYOUT - MOD_INC_USE_COUNT; -#endif + if (nowayout) { + MOD_INC_USE_COUNT; + } /* * Activate timer */ @@ -98,11 +111,11 @@ { /* * Shut off the timer. - * Lock it in if it's a module and we defined ...NOWAYOUT + * Lock it in if it's a module and we set nowayout */ -#ifndef CONFIG_WATCHDOG_NOWAYOUT - del_timer(&watchdog_ticktock); -#endif + if(!nowayout) { + del_timer(&watchdog_ticktock); + } timer_alive=0; return 0; } @@ -159,7 +172,7 @@ fops: &softdog_fops, }; -static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.05, timer margin: %d sec\n"; +static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.06, soft_margin: %d sec, nowayout: %d\n"; static int __init watchdog_init(void) { @@ -170,7 +183,7 @@ if (ret) return ret; - printk(banner, soft_margin); + printk(banner, soft_margin, nowayout); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/sonypi.c linux-2.5/drivers/char/sonypi.c --- linux-2.5.5/drivers/char/sonypi.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/char/sonypi.c Tue Jan 29 18:23:52 2002 @@ -109,25 +109,29 @@ return result; } -static void sonypi_ecrset(u16 addr, u16 value) { +static void sonypi_ecrset(u8 addr, u8 value) { - wait_on_command(1, inw_p(SONYPI_CST_IOPORT) & 3); - outw_p(0x81, SONYPI_CST_IOPORT); - wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2); - outw_p(addr, SONYPI_DATA_IOPORT); - wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2); - outw_p(value, SONYPI_DATA_IOPORT); - wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2); -} - -static u16 sonypi_ecrget(u16 addr) { - - wait_on_command(1, inw_p(SONYPI_CST_IOPORT) & 3); - outw_p(0x80, SONYPI_CST_IOPORT); - wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2); - outw_p(addr, SONYPI_DATA_IOPORT); - wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2); - return inw_p(SONYPI_DATA_IOPORT); + wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3); + outb_p(0x81, SONYPI_CST_IOPORT); + wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2); + outb_p(addr, SONYPI_DATA_IOPORT); + wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2); + outb_p(value, SONYPI_DATA_IOPORT); + wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2); +} + +static u8 sonypi_ecrget(u8 addr) { + + wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3); + outb_p(0x80, SONYPI_CST_IOPORT); + wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2); + outb_p(addr, SONYPI_DATA_IOPORT); + wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2); + return inb_p(SONYPI_DATA_IOPORT); +} + +static u16 sonypi_ecrget16(u8 addr) { + return sonypi_ecrget(addr) | (sonypi_ecrget(addr + 1) << 8); } /* Initializes the device - this comes from the AML code in the ACPI bios */ @@ -286,19 +290,38 @@ sonypi_device.camera_power = 1; } +/* sets the bluetooth subsystem power state */ +static void sonypi_setbluetoothpower(u8 state) { + + state = (state != 0); + if (sonypi_device.bluetooth_power && state) + return; + if (!sonypi_device.bluetooth_power && !state) + return; + + sonypi_call2(0x96, state); + sonypi_call1(0x93); + sonypi_device.bluetooth_power = state; +} + /* Interrupt handler: some event is available */ void sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) { u8 v1, v2, event = 0; int i; u8 sonypi_jogger_ev, sonypi_fnkey_ev; + u8 sonypi_capture_ev, sonypi_bluetooth_ev; if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) { sonypi_jogger_ev = SONYPI_TYPE2_JOGGER_EV; sonypi_fnkey_ev = SONYPI_TYPE2_FNKEY_EV; + sonypi_capture_ev = SONYPI_TYPE2_CAPTURE_EV; + sonypi_bluetooth_ev = SONYPI_TYPE2_BLUETOOTH_EV; } else { sonypi_jogger_ev = SONYPI_TYPE1_JOGGER_EV; sonypi_fnkey_ev = SONYPI_TYPE1_FNKEY_EV; + sonypi_capture_ev = SONYPI_TYPE1_CAPTURE_EV; + sonypi_bluetooth_ev = SONYPI_TYPE1_BLUETOOTH_EV; } v1 = inb_p(sonypi_device.ioport1); @@ -318,7 +341,7 @@ goto found; } } - if ((v2 & SONYPI_CAPTURE_EV) == SONYPI_CAPTURE_EV) { + if ((v2 & sonypi_capture_ev) == sonypi_capture_ev) { for (i = 0; sonypi_captureev[i].event; i++) if (sonypi_captureev[i].data == v1) { event = sonypi_captureev[i].event; @@ -332,7 +355,7 @@ goto found; } } - if ((v2 & SONYPI_BLUETOOTH_EV) == SONYPI_BLUETOOTH_EV) { + if ((v2 & sonypi_bluetooth_ev) == sonypi_bluetooth_ev) { for (i = 0; sonypi_blueev[i].event; i++) if (sonypi_blueev[i].data == v1) { event = sonypi_blueev[i].event; @@ -510,24 +533,74 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) { int ret = 0; - u8 val; + u8 val8; + u16 val16; down(&sonypi_device.lock); switch (cmd) { - case SONYPI_IOCGBRT: - val = sonypi_ecrget(0x96) & 0xff; - if (copy_to_user((u8 *)arg, &val, sizeof(val))) { - ret = -EFAULT; - goto out; - } - break; - case SONYPI_IOCSBRT: - if (copy_from_user(&val, (u8 *)arg, sizeof(val))) { - ret = -EFAULT; - goto out; - } - sonypi_ecrset(0x96, val); - break; + case SONYPI_IOCGBRT: + val8 = sonypi_ecrget(0x96); + if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) { + ret = -EFAULT; + goto out; + } + break; + case SONYPI_IOCSBRT: + if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) { + ret = -EFAULT; + goto out; + } + sonypi_ecrset(0x96, val8); + break; + case SONYPI_IOCGBAT1CAP: + val16 = sonypi_ecrget16(0xb2); + if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) { + ret = -EFAULT; + goto out; + } + break; + case SONYPI_IOCGBAT1REM: + val16 = sonypi_ecrget16(0xa2); + if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) { + ret = -EFAULT; + goto out; + } + break; + case SONYPI_IOCGBAT2CAP: + val16 = sonypi_ecrget16(0xba); + if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) { + ret = -EFAULT; + goto out; + } + break; + case SONYPI_IOCGBAT2REM: + val16 = sonypi_ecrget16(0xaa); + if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) { + ret = -EFAULT; + goto out; + } + break; + case SONYPI_IOCGBATFLAGS: + val8 = sonypi_ecrget(0x81) & 0x07; + if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) { + ret = -EFAULT; + goto out; + } + break; + case SONYPI_IOCGBLUE: + val8 = sonypi_device.bluetooth_power; + if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) { + ret = -EFAULT; + goto out; + } + break; + case SONYPI_IOCSBLUE: + if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) { + ret = -EFAULT; + goto out; + } + sonypi_setbluetoothpower(val8); + break; default: ret = -EINVAL; } @@ -562,6 +635,7 @@ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2; sonypi_initq(); init_MUTEX(&sonypi_device.lock); + sonypi_device.bluetooth_power = 0; if (pcidev && pci_enable_device(pcidev)) { printk(KERN_ERR "sonypi: pci_enable_device failed\n"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/sonypi.h linux-2.5/drivers/char/sonypi.h --- linux-2.5.5/drivers/char/sonypi.h Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/char/sonypi.h Thu Feb 21 16:24:56 2002 @@ -34,8 +34,8 @@ #ifdef __KERNEL__ -#define SONYPI_DRIVER_MAJORVERSION 1 -#define SONYPI_DRIVER_MINORVERSION 8 +#define SONYPI_DRIVER_MAJORVERSION 1 +#define SONYPI_DRIVER_MINORVERSION 10 #include #include @@ -132,15 +132,17 @@ #define SONYPI_CAMERA_ROMVERSION 9 /* key press event data (ioport2) */ -#define SONYPI_TYPE1_JOGGER_EV 0x10 -#define SONYPI_TYPE2_JOGGER_EV 0x08 -#define SONYPI_CAPTURE_EV 0x60 -#define SONYPI_TYPE1_FNKEY_EV 0x20 -#define SONYPI_TYPE2_FNKEY_EV 0x08 -#define SONYPI_BLUETOOTH_EV 0x30 -#define SONYPI_TYPE1_PKEY_EV 0x40 -#define SONYPI_BACK_EV 0x08 -#define SONYPI_LID_EV 0x38 +#define SONYPI_TYPE1_JOGGER_EV 0x10 +#define SONYPI_TYPE2_JOGGER_EV 0x08 +#define SONYPI_TYPE1_CAPTURE_EV 0x60 +#define SONYPI_TYPE2_CAPTURE_EV 0x08 +#define SONYPI_TYPE1_FNKEY_EV 0x20 +#define SONYPI_TYPE2_FNKEY_EV 0x08 +#define SONYPI_TYPE1_BLUETOOTH_EV 0x30 +#define SONYPI_TYPE2_BLUETOOTH_EV 0x08 +#define SONYPI_TYPE1_PKEY_EV 0x40 +#define SONYPI_BACK_EV 0x08 +#define SONYPI_LID_EV 0x38 struct sonypi_event { u8 data; @@ -203,6 +205,8 @@ /* The set of possible bluetooth events */ static struct sonypi_event sonypi_blueev[] = { { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED }, + { 0x59, SONYPI_EVENT_BLUETOOTH_ON }, + { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF }, { 0x00, 0x00 } }; @@ -241,6 +245,7 @@ u16 ioport2; u16 region_size; int camera_power; + int bluetooth_power; struct semaphore lock; struct sonypi_queue queue; int open_count; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/synclink.c linux-2.5/drivers/char/synclink.c --- linux-2.5.5/drivers/char/synclink.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/char/synclink.c Sun Mar 3 17:54:35 2002 @@ -60,13 +60,15 @@ # define BREAKPOINT() { } #endif -#error Please convert me to Documentation/DMA-mapping.txt - #define MAX_ISA_DEVICES 10 #define MAX_PCI_DEVICES 10 #define MAX_TOTAL_DEVICES 20 #include +#ifdef CONFIG_DEBUG_OBSOLETE +#error Please convert me to Documentation/DMA-mapping.txt +#endif + #include #include #include @@ -925,9 +927,9 @@ static char *driver_name = "SyncLink serial driver"; static char *driver_version = "$Revision: 3.12 $"; -static int __init synclink_init_one (struct pci_dev *dev, +static int synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); -static void __exit synclink_remove_one (struct pci_dev *dev); +static void synclink_remove_one (struct pci_dev *dev); static struct pci_device_id synclink_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, }, @@ -941,7 +943,7 @@ name: "synclink", id_table: synclink_pci_tbl, probe: synclink_init_one, - remove: synclink_remove_one, + remove: __devexit_p(synclink_remove_one), }; static struct tty_driver serial_driver, callout_driver; @@ -1812,7 +1814,7 @@ /* Allocate and claim adapter resources */ retval = mgsl_claim_resources(info); - /* perform existance check and diagnostics */ + /* perform existence check and diagnostics */ if ( !retval ) retval = mgsl_adapter_test(info); @@ -8220,7 +8222,7 @@ return 0; } -static void __exit synclink_remove_one (struct pci_dev *dev) +static void __devexit synclink_remove_one (struct pci_dev *dev) { } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/sysrq.c linux-2.5/drivers/char/sysrq.c --- linux-2.5.5/drivers/char/sysrq.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/char/sysrq.c Sun Mar 3 23:50:42 2002 @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -32,7 +32,6 @@ #include -extern void reset_vc(unsigned int); extern struct list_head super_blocks; /* Whether we react on sysrq keys or just ignore them */ @@ -43,7 +42,8 @@ /* Loglevel sysrq handler */ static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ int i; i = key - '0'; console_loglevel = 7; @@ -60,10 +60,14 @@ /* SAK sysrq handler */ #ifdef CONFIG_VT static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + if (tty) do_SAK(tty); - reset_vc(fg_console); + if ((tty->driver.subtype == SYSTEM_TYPE_CONSOLE) && vc) + reset_vc(vc->display_fg->vc_cons[fg_console]); } static struct sysrq_key_op sysrq_SAK_op = { handler: sysrq_handle_SAK, @@ -75,9 +79,12 @@ /* unraw sysrq handler */ static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { - if (kbd) - kbd->kbdmode = VC_XLATE; + struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + + if ((tty->driver.subtype == SYSTEM_TYPE_CONSOLE) && vc) + vc->kbd_table.kbdmode = VC_XLATE; } static struct sysrq_key_op sysrq_unraw_op = { handler: sysrq_handle_unraw, @@ -88,7 +95,8 @@ /* reboot sysrq handler */ static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ machine_restart(NULL); } static struct sysrq_key_op sysrq_reboot_op = { @@ -97,8 +105,6 @@ action_msg: "Resetting", }; - - /* SYNC SYSRQ HANDLERS BLOCK */ /* do_emergency_sync helper function */ @@ -161,7 +167,7 @@ } file_list_unlock(); DQUOT_OFF(sb); - fsync_dev(sb->s_dev); + fsync_bdev(sb->s_bdev); flags = MS_RDONLY; if (sb->s_op && sb->s_op->remount_fs) { ret = sb->s_op->remount_fs(sb, &flags, NULL); @@ -174,7 +180,7 @@ } else printk("nothing to do\n"); } else { /* Sync only */ - fsync_dev(sb->s_dev); + fsync_bdev(sb->s_bdev); printk("OK\n"); } console_loglevel = orig_loglevel; @@ -218,7 +224,8 @@ } static void sysrq_handle_sync(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ emergency_sync_scheduled = EMERG_SYNC; wakeup_bdflush(); } @@ -229,7 +236,8 @@ }; static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ emergency_sync_scheduled = EMERG_REMOUNT; wakeup_bdflush(); } @@ -245,7 +253,8 @@ /* SHOW SYSRQ HANDLERS BLOCK */ static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ if (pt_regs) show_regs(pt_regs); } @@ -257,7 +266,8 @@ static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ show_state(); } static struct sysrq_key_op sysrq_showstate_op = { @@ -266,9 +276,9 @@ action_msg: "Show State", }; - static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ show_mem(); } static struct sysrq_key_op sysrq_showmem_op = { @@ -300,7 +310,8 @@ } static void sysrq_handle_term(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ send_sig_all(SIGTERM, 0); console_loglevel = 8; } @@ -311,7 +322,8 @@ }; static void sysrq_handle_kill(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ send_sig_all(SIGKILL, 0); console_loglevel = 8; } @@ -322,7 +334,8 @@ }; static void sysrq_handle_killall(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ send_sig_all(SIGKILL, 1); console_loglevel = 8; } @@ -431,13 +444,13 @@ * and any other keycode arrives. */ -void handle_sysrq(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { +void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty) +{ if (!sysrq_enabled) return; __sysrq_lock_table(); - __handle_sysrq_nolock(key, pt_regs, kbd, tty); + __handle_sysrq_nolock(key, pt_regs, tty); __sysrq_unlock_table(); } @@ -448,7 +461,8 @@ */ void __handle_sysrq_nolock(int key, struct pt_regs *pt_regs, - struct kbd_struct *kbd, struct tty_struct *tty) { + struct tty_struct *tty) +{ struct sysrq_key_op *op_p; int orig_log_level; int i, j; @@ -464,7 +478,7 @@ if (op_p) { printk ("%s\n", op_p->action_msg); console_loglevel = orig_log_level; - op_p->handler(key, pt_regs, kbd, tty); + op_p->handler(key, pt_regs, tty); } else { printk("HELP : "); /* Only print the help msg once per handler */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/tpqic02.c linux-2.5/drivers/char/tpqic02.c --- linux-2.5.5/drivers/char/tpqic02.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/char/tpqic02.c Thu Feb 14 00:47:46 2002 @@ -2748,7 +2748,9 @@ * the config parameters have been set using MTSETCONFIG. */ - if (check_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE)) { + /* Grab the IO region. */ + if (!request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE, + TPQIC02_NAME)) { printk(TPQIC02_NAME ": IO space at 0x%x [%d ports] already reserved\n", QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE); @@ -2762,6 +2764,7 @@ printk(TPQIC02_NAME ": can't allocate IRQ%d for QIC-02 tape\n", QIC02_TAPE_IRQ); + release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE); return -EBUSY; } @@ -2771,12 +2774,9 @@ ": can't allocate DMA%d for QIC-02 tape\n", QIC02_TAPE_DMA); free_irq(QIC02_TAPE_IRQ, NULL); + release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE); return -EBUSY; } - - /* Grab the IO region. We already made sure it's available. */ - request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE, - TPQIC02_NAME); /* Setup the page-address for the dma transfer. */ buffaddr = diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/tty_io.c linux-2.5/drivers/char/tty_io.c --- linux-2.5.5/drivers/char/tty_io.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/char/tty_io.c Sun Mar 3 17:54:35 2002 @@ -156,6 +156,8 @@ extern void sci_console_init(void); extern void tx3912_console_init(void); extern void tx3912_rs_init(void); +extern void txx927_console_init(void); +extern void sb1250_serial_console_init(void); #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -687,8 +689,13 @@ { ssize_t ret = 0, written = 0; - if (down_interruptible(&tty->atomic_write)) { - return -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (down_trylock(&tty->atomic_write)) + return -EAGAIN; + } + else { + if (down_interruptible(&tty->atomic_write)) + return -ERESTARTSYS; } if ( test_bit(TTY_NO_WRITE_SPLIT, &tty->flags) ) { lock_kernel(); @@ -2169,7 +2176,7 @@ * inform about problems etc.. */ #ifdef CONFIG_VT - con_init(); + vt_console_init(); #endif #ifdef CONFIG_AU1000_SERIAL_CONSOLE au1000_serial_console_init(); @@ -2177,6 +2184,11 @@ #ifdef CONFIG_SERIAL_CONSOLE #if (defined(CONFIG_8xx) || defined(CONFIG_8260)) console_8xx_init(); +#elif defined(CONFIG_MAC_SERIAL) && defined(CONFIG_SERIAL) + if (_machine == _MACH_Pmac) + mac_scc_console_init(); + else + serial_console_init(); #elif defined(CONFIG_MAC_SERIAL) mac_scc_console_init(); #elif defined(CONFIG_PARISC) @@ -2224,6 +2236,12 @@ #ifdef CONFIG_SERIAL_TX3912_CONSOLE tx3912_console_init(); #endif +#ifdef CONFIG_TXX927_SERIAL_CONSOLE + txx927_console_init(); +#endif +#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE + sb1250_serial_console_init(); +#endif } static struct tty_driver dev_tty_driver, dev_syscons_driver; @@ -2231,9 +2249,8 @@ static struct tty_driver dev_ptmx_driver; #endif #ifdef CONFIG_VT -extern void con_init_devfs (void); -extern void console_map_init(void); static struct tty_driver dev_console_driver; +extern int vty_init(void); #endif /* @@ -2273,13 +2290,6 @@ if (tty_register_driver(&dev_syscons_driver)) panic("Couldn't register /dev/console driver\n"); - /* console calls tty_register_driver() before kmalloc() works. - * Thus, we can't devfs_register() then. Do so now, instead. - */ -#ifdef CONFIG_VT - con_init_devfs(); -#endif - #ifdef CONFIG_UNIX98_PTYS dev_ptmx_driver = dev_tty_driver; dev_ptmx_driver.driver_name = "/dev/ptmx"; @@ -2303,10 +2313,7 @@ if (tty_register_driver(&dev_console_driver)) panic("Couldn't register /dev/tty0 driver\n"); - - vcs_init(); - kbd_init(); - console_map_init(); + vty_init(); #endif #ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/vc_screen.c linux-2.5/drivers/char/vc_screen.c --- linux-2.5.5/drivers/char/vc_screen.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/char/vc_screen.c Mon Feb 25 18:54:26 2002 @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -46,20 +45,60 @@ #undef addr #define HEADER_SIZE 4 +/* used by vcs - note the word offset */ +unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed) +{ + return screenpos(vc, 2 * w_offset, viewed); +} + +void getconsxy(struct vc_data *vc, char *p) +{ + p[0] = vc->vc_x; + p[1] = vc->vc_y; +} + +void putconsxy(struct vc_data *vc, char *p) +{ + gotoxy(vc, p[0], p[1]); + set_cursor(vc); +} + +u16 vcs_scr_readw(struct vc_data *vc, const u16 *org) +{ + if ((unsigned long)org == vc->vc_pos && vc->display_fg->cursor_original != -1) + return vc->display_fg->cursor_original; + return scr_readw(org); +} + +void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org) +{ + scr_writew(val, org); + if ((unsigned long)org == vc->vc_pos) { + vc->display_fg->cursor_original = -1; + add_softcursor(vc); + } +} + + static int vcs_size(struct inode *inode) { - int size; int minor = minor(inode->i_rdev); int currcons = minor & 127; + struct vc_data *vc; + int size; + if (currcons == 0) currcons = fg_console; else currcons--; - if (!vc_cons_allocated(currcons)) + + vc = vt_cons->vc_cons[currcons]; + + if (!vc) return -ENXIO; - size = video_num_lines * video_num_columns; + size = vc->vc_rows * vc->vc_cols; if (minor & 128) size = 2*size + HEADER_SIZE; @@ -106,6 +145,7 @@ { struct inode *inode = file->f_dentry->d_inode; unsigned int currcons = minor(inode->i_rdev); + struct vc_data *vc; long pos = *ppos; long viewed, attr, read; int col, maxcol; @@ -129,7 +169,10 @@ viewed = 0; } ret = -ENXIO; - if (!vc_cons_allocated(currcons)) + + vc = vt_cons->vc_cons[currcons]; + + if (!vc) goto unlock_out; ret = -EINVAL; @@ -164,15 +207,15 @@ con_buf_start = con_buf0 = con_buf; orig_count = this_round; - maxcol = video_num_columns; + maxcol = vc->vc_cols; if (!attr) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = p % maxcol; p += maxcol - col; while (this_round-- > 0) { - *con_buf0++ = (vcs_scr_readw(currcons, org++) & 0xff); + *con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff); if (++col == maxcol) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = 0; p += maxcol; } @@ -181,9 +224,9 @@ if (p < HEADER_SIZE) { size_t tmp_count; - con_buf0[0] = (char) video_num_lines; - con_buf0[1] = (char) video_num_columns; - getconsxy(currcons, con_buf0 + 2); + con_buf0[0] = (char) vc->vc_rows; + con_buf0[1] = (char) vc->vc_cols; + getconsxy(vc, con_buf0 + 2); con_buf_start += p; this_round += p; @@ -219,7 +262,7 @@ p /= 2; col = p % maxcol; - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); p += maxcol - col; /* Buffer has even length, so we can always copy @@ -229,10 +272,10 @@ this_round = (this_round + 1) >> 1; while (this_round) { - *tmp_buf++ = vcs_scr_readw(currcons, org++); + *tmp_buf++ = vcs_scr_readw(vc, org++); this_round --; if (++col == maxcol) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = 0; p += maxcol; } @@ -275,6 +318,7 @@ { struct inode *inode = file->f_dentry->d_inode; unsigned int currcons = minor(inode->i_rdev); + struct vc_data *vc; long pos = *ppos; long viewed, attr, size, written; char *con_buf0; @@ -300,7 +344,10 @@ viewed = 0; } ret = -ENXIO; - if (!vc_cons_allocated(currcons)) + + vc = vt_cons->vc_cons[currcons]; + + if (!vc) goto unlock_out; size = vcs_size(inode); @@ -354,10 +401,10 @@ con_buf0 = con_buf; orig_count = this_round; - maxcol = video_num_columns; + maxcol = vc->vc_cols; p = pos; if (!attr) { - org0 = org = screen_pos(currcons, p, viewed); + org0 = org = screen_pos(vc, p, viewed); col = p % maxcol; p += maxcol - col; @@ -365,11 +412,11 @@ unsigned char c = *con_buf0++; this_round--; - vcs_scr_writew(currcons, - (vcs_scr_readw(currcons, org) & 0xff00) | c, org); + vcs_scr_writew(vc, + (vcs_scr_readw(vc, org) & 0xff00) | c, org); org++; if (++col == maxcol) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = 0; p += maxcol; } @@ -378,34 +425,34 @@ if (p < HEADER_SIZE) { char header[HEADER_SIZE]; - getconsxy(currcons, header + 2); + getconsxy(vc, header + 2); while (p < HEADER_SIZE && this_round > 0) { this_round--; header[p++] = *con_buf0++; } if (!viewed) - putconsxy(currcons, header + 2); + putconsxy(vc, header + 2); } p -= HEADER_SIZE; col = (p/2) % maxcol; if (this_round > 0) { - org0 = org = screen_pos(currcons, p/2, viewed); + org0 = org = screen_pos(vc, p/2, viewed); if ((p & 1) && this_round > 0) { char c; this_round--; c = *con_buf0++; #ifdef __BIG_ENDIAN - vcs_scr_writew(currcons, c | - (vcs_scr_readw(currcons, org) & 0xff00), org); + vcs_scr_writew(vc, c | + (vcs_scr_readw(vc, org) & 0xff00), org); #else - vcs_scr_writew(currcons, (c << 8) | - (vcs_scr_readw(currcons, org) & 0xff), org); + vcs_scr_writew(vc, (c << 8) | + (vcs_scr_readw(vc, org) & 0xff), org); #endif org++; p++; if (++col == maxcol) { - org = screen_pos(currcons, p/2, viewed); + org = screen_pos(vc, p/2, viewed); col = 0; } } @@ -416,11 +463,11 @@ unsigned short w; w = get_unaligned(((const unsigned short *)con_buf0)); - vcs_scr_writew(currcons, w, org++); + vcs_scr_writew(vc, w, org++); con_buf0 += 2; this_round -= 2; if (++col == maxcol) { - org = screen_pos(currcons, p, viewed); + org = screen_pos(vc, p, viewed); col = 0; p += maxcol; } @@ -430,9 +477,9 @@ c = *con_buf0++; #ifdef __BIG_ENDIAN - vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff) | (c << 8), org); + vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org); #else - vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org); + vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org); #endif } } @@ -441,7 +488,7 @@ buf += orig_count; pos += orig_count; if (org0) - update_region(currcons, (unsigned long)(org0), org-org0); + update_region(vc, (unsigned long)(org0), org-org0); } *ppos += written; ret = written; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/vme_scc.c linux-2.5/drivers/char/vme_scc.c --- linux-2.5.5/drivers/char/vme_scc.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/char/vme_scc.c Sun Jan 6 01:38:27 2002 @@ -92,10 +92,10 @@ static void scc_break_ctl(struct tty_struct *tty, int break_state); static struct tty_driver scc_driver, scc_callout_driver; - static struct tty_struct *scc_table[2] = { NULL, }; static struct termios * scc_termios[2]; static struct termios * scc_termios_locked[2]; +static struct console sercons; struct scc_port scc_ports[2]; int scc_refcount; @@ -145,7 +145,9 @@ scc_driver.table = scc_table; scc_driver.termios = scc_termios; scc_driver.termios_locked = scc_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + scc_driver.console = &sercons; +#endif scc_driver.open = scc_open; scc_driver.close = gs_close; scc_driver.write = gs_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/vt.c linux-2.5/drivers/char/vt.c --- linux-2.5.5/drivers/char/vt.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/char/vt.c Sun Mar 3 23:50:42 2002 @@ -1,1316 +1,1896 @@ /* - * linux/drivers/char/vt.c + * vt.c - Built-in console device * - * Copyright (C) 1992 obz under the linux copyright + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * Hopefully this will be a rather complete VT102 implementation. + * + * Beeping thanks to John T Kohl. + * + * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics + * Chars, and VT100 enhancements by Peter MacDonald. + * + * Copy and paste function by Andrew Haylett, + * some enhancements by Alessandro Rubini. + * + * Code to check for different video-cards mostly by Galen Hunt, + * + * + * Rudimentary ISO 10646/Unicode/UTF-8 character set support by + * Markus Kuhn, . + * + * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 + * Resizing of consoles, aeb, 940926 + * + * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 + * + * + * User-defined bell sound, new setterm control sequences and printk + * redirection by Martin Mares 19-Nov-95 + * + * APM screenblank bug fixed Takashi Manabe + * + * Merge with the abstract console driver by Geert Uytterhoeven + * , Jan 1997. + * + * Original m68k console driver modifications by + * + * - Arno Griffioen + * - David Carter + * + * Note that the abstract console driver allows all consoles to be of + * potentially different sizes, so the following variables depend on the + * current console (currcons): * - * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 - * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 - * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 - * Some code moved for less code duplication - Andi Kleen - Mar 1997 - * Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001 + * - video_num_columns + * - video_num_lines + * - video_size_row + * - can_do_color + * + * The abstract console driver provides a generic interface for a text + * console. It supports VGA text mode, frame buffer based graphical consoles + * and special graphics processors that are only accessible through some + * registers (e.g. a TMS340x0 GSP). + * + * The interface to the hardware is specified using a special structure + * (struct consw) which contains function pointers to console operations + * (see for more information). + * + * Support for changeable cursor shape + * by Pavel Machek , August 1997 + * + * Ported to i386 and con_scrolldelta fixed + * by Emmanuel Marty , April 1998 + * + * Resurrected character buffers in videoram plus lots of other trickery + * by Martin Mares , July 1998 + * + * Removed old-style timers, introduced console_timer, made timer + * deletion SMP-safe. 17Jun00, Andrew Morton + * + * Removed console_lock, enabled interrupts across all console operations + * 13 March 2001, Andrew Morton */ -#include -#include -#include +#include #include #include -#include +#include #include -#include -#include #include +#include +#include #include #include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include +#include -#include -#include -#include -#include +#include "console_macros.h" -#ifdef CONFIG_FB_COMPAT_XPMAC -#include -#endif /* CONFIG_FB_COMPAT_XPMAC */ +const struct consw *conswitchp; -char vt_dont_switch; -extern struct tty_driver console_driver; +/* A bitmap for codes <32. A bit of 1 indicates that the code + * corresponding to that bit number invokes some special action + * (such as cursor movement) and should not be displayed as a + * glyph unless the disp_ctrl mode is explicitly enabled. + */ +#define CTRL_ACTION 0x0d00ff81 +#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ -#define VT_IS_IN_USE(i) (console_driver.table[i] && console_driver.table[i]->count) -#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons) +extern void vcs_make_devfs (unsigned int index, int unregister); +extern void console_map_init(void); -/* - * Console (vt and kd) routines, as defined by USL SVR4 manual, and by - * experimentation and study of X386 SYSV handling. - * - * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and - * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, - * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will - * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to - * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using - * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing - * to the current console is done by the main ioctl code. +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +static struct tty_struct *console_table[MAX_NR_CONSOLES]; +static struct termios *console_termios[MAX_NR_CONSOLES]; +static struct termios *console_termios_locked[MAX_NR_CONSOLES]; + +#ifndef VT_SINGLE_DRIVER +static const struct consw *con_driver_map[MAX_NR_CONSOLES]; +#endif + +static void con_flush_chars(struct tty_struct *tty); +static void unblank_screen_t(unsigned long private); + +static int printable; /* Is console ready for printing? */ + +/* + * the default colour table, for VGA+ colour systems */ +int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, + 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; +int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, + 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; +int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, + 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; + +unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, + 8,12,10,14, 9,13,11,15 }; +int do_poke_blanked_console; -struct vt_struct *vt_cons[MAX_NR_CONSOLES]; +/* + * fg_console is the current virtual console, + * kmsg_redirect is the console for kernel messages, + */ +int fg_console; +int kmsg_redirect; -/* Keyboard type: Default is KB_101, but can be set by machine - * specific code. +/* + * Hook so that the power management routines can (un)blank + * the console on our behalf. */ -unsigned char keyboard_type = KB_101; +int (*console_blank_hook)(int); -#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); +/* + * Low-Level Functions + */ +#ifdef VT_BUF_VRAM_ONLY +#define DO_UPDATE 0 +#else +#define DO_UPDATE IS_VISIBLE #endif -unsigned int video_font_height; -unsigned int default_font_height; -unsigned int video_scan_lines; +static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data); +static struct pm_dev *pm_con; + + +void respond_string(const char * p, struct tty_struct * tty) +{ + while (*p) { + tty_insert_flip_char(tty, *p, 0); + p++; + } + con_schedule_flip(tty); +} + +/* + * Console cursor handling + */ +void add_softcursor(struct vc_data *vc) +{ + int i = scr_readw((u16 *) pos); u32 type = cursor_type; + + if (!(type & 0x10)) return; + if (softcursor_original != -1) return; + softcursor_original = i; + i |= ((type >> 8) & 0xff00 ); + i ^= ((type) & 0xff00 ); + if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) + i ^= 0x7000; + if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; + scr_writew(i, (u16 *) pos); + if (DO_UPDATE) + sw->con_putc(vc, i, y, x); +} + +void hide_cursor(struct vc_data *vc) +{ + if (cons_num == sel_cons) + clear_selection(); + if (softcursor_original != -1) { + scr_writew(softcursor_original,(u16 *) pos); + if (DO_UPDATE) + sw->con_putc(vc, softcursor_original, y, x); + softcursor_original = -1; + } + sw->con_cursor(vc, CM_ERASE); +} + +void set_cursor(struct vc_data *vc) +{ + if (!IS_VISIBLE || vc->display_fg->vt_blanked || vcmode == KD_GRAPHICS) + return; + if (dectcem) { + if (cons_num == sel_cons) + clear_selection(); + add_softcursor(vc); + if ((cursor_type & 0x0f) != 1) + sw->con_cursor(vc, CM_DRAW); + } else + hide_cursor(vc); +} /* - * these are the valid i/o ports we're allowed to change. they map all the - * video ports + * gotoxy() must verify all boundaries, because the arguments + * might also be negative. If the given position is out of + * bounds, the cursor is placed at the nearest margin. */ -#define GPFIRST 0x3b4 -#define GPLAST 0x3df -#define GPNUM (GPLAST - GPFIRST + 1) +void gotoxy(struct vc_data *vc, int new_x, int new_y) +{ + int min_y, max_y; + + if (new_x < 0) + x = 0; else + if (new_x >= video_num_columns) + x = video_num_columns - 1; + else + x = new_x; + if (decom) { + min_y = top; + max_y = bottom; + } else { + min_y = 0; + max_y = video_num_lines; + } + if (new_y < min_y) + y = min_y; + else if (new_y >= max_y) + y = max_y - 1; + else + y = new_y; + pos = origin + y*video_size_row + (x<<1); + need_wrap = 0; +} + +/* for absolute user moves, when decom is set */ +void gotoxay(struct vc_data *vc, int new_x, int new_y) +{ + gotoxy(vc, new_x, decom ? (top+new_y) : new_y); +} /* - * Generates sound of some frequency for some number of clock ticks - * - * If freq is 0, will turn off sound, else will turn it on for that time. - * If msec is 0, will return immediately, else will sleep for msec time, then - * turn sound off. - * - * We also return immediately, which is what was implied within the X - * comments - KDMKTONE doesn't put the process to sleep. + * Palettes + */ + +void set_palette(struct vc_data *vc) +{ + if (vcmode != KD_GRAPHICS) + sw->con_set_palette(vc, color_table); +} + +void reset_palette(struct vc_data *vc) +{ + int j, k; + + for (j=k=0; j<16; j++) { + palette[k++] = default_red[j]; + palette[k++] = default_grn[j]; + palette[k++] = default_blu[j]; + } + set_palette(vc); +} + +/* + * Load palette into the DAC registers. arg points to a colour + * map, 3 bytes per colour, 16 colours, range from 0 to 255. */ -#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \ - || (defined(__mips__) && defined(CONFIG_ISA)) \ - || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) \ - || defined(__x86_64__) +static int set_get_cmap(unsigned char *arg, int set) +{ + struct vc_data *vc; + int i, j, k; + + for (i = 0; i < 16; i++) + if (set) { + get_user(default_red[i], arg++); + get_user(default_grn[i], arg++); + get_user(default_blu[i], arg++); + } else { + put_user(default_red[i], arg++); + put_user(default_grn[i], arg++); + put_user(default_blu[i], arg++); + } + if (set) { + for (i = 0; i < MAX_NR_CONSOLES; i++) { + vc = vt_cons->vc_cons[i]; + if (vc) { + for (j = k = 0; j < 16; j++) { + palette[k++] = default_red[j]; + palette[k++] = default_grn[j]; + palette[k++] = default_blu[j]; + } + set_palette(vc); + } + } + } + return 0; +} -static void -kd_nosound(unsigned long ignored) +int con_set_cmap(unsigned char *arg) { - /* disable counter 2 */ - outb(inb_p(0x61)&0xFC, 0x61); - return; + return set_get_cmap (arg,1); } -void -_kd_mksound(unsigned int hz, unsigned int ticks) +int con_get_cmap(unsigned char *arg) { - static struct timer_list sound_timer = { function: kd_nosound }; - unsigned int count = 0; - unsigned long flags; + return set_get_cmap (arg,0); +} - if (hz > 20 && hz < 32767) - count = 1193180 / hz; +/* + * Functions to handle console scrolling. + */ +static inline void scrolldelta(struct vt_struct *vt, int lines) +{ + vt->scrollback_delta += lines; - save_flags(flags); - cli(); - del_timer(&sound_timer); - if (count) { - /* enable counter 2 */ - outb_p(inb_p(0x61)|3, 0x61); - /* set command for counter 2, 2 byte write */ - outb_p(0xB6, 0x43); - /* select desired HZ */ - outb_p(count & 0xff, 0x42); - outb((count >> 8) & 0xff, 0x42); - - if (ticks) { - sound_timer.expires = jiffies+ticks; - add_timer(&sound_timer); - } - } else - kd_nosound(0); - restore_flags(flags); - return; + schedule_task(&vt->vt_tq); +} + +void scrollback(struct vc_data *vc, int lines) +{ + if (!lines) + lines = video_num_lines/2; + scrolldelta(vc->display_fg, -lines); } -#else +void scrollfront(struct vc_data *vc, int lines) +{ + if (!lines) + lines = video_num_lines/2; + scrolldelta(vc->display_fg, lines); +} + +void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) +{ + unsigned short *d, *s; + + if (t+nr >= b) + nr = b - t; + if (b > video_num_lines || t >= b || nr < 1) + return; + if (IS_VISIBLE && sw->con_scroll(vc, t, b, SM_UP, nr)) + return; + d = (unsigned short *) (origin+video_size_row*t); + s = (unsigned short *) (origin+video_size_row*(t+nr)); + scr_memcpyw(d, s, (b-t-nr) * video_size_row); + scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr); +} + +void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) +{ + unsigned short *s; + unsigned int step; + + if (t+nr >= b) + nr = b - t; + if (b > video_num_lines || t >= b || nr < 1) + return; + if (IS_VISIBLE && sw->con_scroll(vc, t, b, SM_DOWN, nr)) + return; + s = (unsigned short *) (origin+video_size_row*t); + step = video_num_columns * nr; + scr_memmovew(s + step, s, (b-t-nr)*video_size_row); + scr_memsetw(s, video_erase_char, 2*step); +} -void -_kd_mksound(unsigned int hz, unsigned int ticks) +/* + * Console attribute handling. Structure of attributes is hardware-dependent + */ +void default_attr(struct vc_data *vc) { + intensity = 1; + underline = 0; + reverse = 0; + blink = 0; + color = def_color; } +/* + * ++roman: I completely changed the attribute format for monochrome + * mode (!can_do_color). The formerly used MDA (monochrome display + * adapter) format didn't allow the combination of certain effects. + * Now the attribute is just a bit vector: + * Bit 0..1: intensity (0..2) + * Bit 2 : underline + * Bit 3 : reverse + * Bit 7 : blink + */ +static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse) +{ + if (sw->con_build_attr) + return sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse); + +#ifndef VT_BUF_VRAM_ONLY + { + u8 a = color; + if (!can_do_color) + return _intensity | + (_underline ? 4 : 0) | + (_reverse ? 8 : 0) | + (_blink ? 0x80 : 0); + if (_underline) + a = (a & 0xf0) | ulcolor; + else if (_intensity == 0) + a = (a & 0xf0) | halfcolor; + if (_reverse) + a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77); + if (_blink) + a ^= 0x80; + if (_intensity == 2) + a ^= 0x08; + if (hi_font_mask == 0x100) + a <<= 1; + return a; + } +#else + return 0; #endif +} -int _kbd_rate(struct kbd_repeat *rep) +void update_attr(struct vc_data *vc) { - return -EINVAL; + attr = build_attr(vc, color, intensity, blink, underline, reverse ^ decscnm); + video_erase_char = (build_attr(vc, color, intensity, 0, 0, decscnm) << 8) | ' '; } -void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound; -int (*kbd_rate)(struct kbd_repeat *rep) = _kbd_rate; +/* + * Character management + */ +void insert_char(struct vc_data *vc, unsigned int nr) +{ + unsigned short *p, *q = (unsigned short *) pos; + + p = q + video_num_columns - nr - x; + while (--p >= q) + scr_writew(scr_readw(p), p + nr); + scr_memsetw(q, video_erase_char, nr*2); + need_wrap = 0; + if (DO_UPDATE) { + unsigned short oldattr = attr; + + sw->con_bmove(vc, y, x, y, x+nr, 1, video_num_columns-x-nr); + attr = video_erase_char >> 8; + while (nr--) + sw->con_putc(vc, video_erase_char, y, x+nr); + attr = oldattr; + } +} -#define i (tmp.kb_index) -#define s (tmp.kb_table) -#define v (tmp.kb_value) -static inline int -do_kdsk_ioctl(int cmd, struct kbentry *user_kbe, int perm, struct kbd_struct *kbd) +void delete_char(struct vc_data *vc, unsigned int nr) { - struct kbentry tmp; - ushort *key_map, val, ov; + unsigned int i = x; + unsigned short *p = (unsigned short *) pos; - if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) - return -EFAULT; - if (i >= NR_KEYS || s >= MAX_NR_KEYMAPS) - return -EINVAL; + while (++i <= video_num_columns - nr) { + scr_writew(scr_readw(p+nr), p); + p++; + } + scr_memsetw(p, video_erase_char, nr*2); + need_wrap = 0; + if (DO_UPDATE) { + unsigned short oldattr = attr; + sw->con_bmove(vc, y, x+nr, y, x, 1, + video_num_columns-x-nr); + attr = video_erase_char >> 8; + while (nr--) + sw->con_putc(vc, video_erase_char, y, + video_num_columns-1-nr); + attr = oldattr; + } +} + +void insert_line(struct vc_data *vc, unsigned int nr) +{ + scrdown(vc, y, bottom, nr); + need_wrap = 0; +} + +void delete_line(struct vc_data *vc, unsigned int nr) +{ + scrup(vc, y, bottom, nr); + need_wrap = 0; +} + +/* + * Functions that manage whats displayed on the screen + */ +void set_origin(struct vc_data *vc) +{ + if (!IS_VISIBLE || !sw->con_set_origin || !sw->con_set_origin(vc)) + origin = (unsigned long) screenbuf; + visible_origin = origin; + scr_end = origin + screenbuf_size; + pos = origin + video_size_row*y + 2*x; +} + +inline void clear_region(struct vc_data *vc,int sx,int sy,int width,int height) +{ + /* Clears the video memory, not the screen buffer */ + if (DO_UPDATE && sw->con_clear) + return sw->con_clear(vc, sy, sx, height, width); +} + +inline void save_screen(struct vc_data *vc) +{ + if (sw->con_save_screen) + sw->con_save_screen(vc); +} - switch (cmd) { - case KDGKBENT: - key_map = key_maps[s]; - if (key_map) { - val = U(key_map[i]); - if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) - val = K_HOLE; - } else - val = (i ? K_HOLE : K_NOSUCHMAP); - return put_user(val, &user_kbe->kb_value); - case KDSKBENT: - if (!perm) - return -EPERM; - if (!i && v == K_NOSUCHMAP) { - /* disallocate map */ - key_map = key_maps[s]; - if (s && key_map) { - key_maps[s] = 0; - if (key_map[0] == U(K_ALLOCATED)) { - kfree(key_map); - keymap_count--; - } +void do_update_region(struct vc_data *vc, unsigned long start, int count) +{ +#ifndef VT_BUF_VRAM_ONLY + unsigned int xx, yy, offset; + u16 *p; + + p = (u16 *) start; + if (!sw->con_getxy) { + offset = (start - origin) / 2; + xx = offset % video_num_columns; + yy = offset / video_num_columns; + } else { + int nxx, nyy; + start = sw->con_getxy(vc, start, &nxx, &nyy); + xx = nxx; yy = nyy; + } + for(;;) { + u16 attrib = scr_readw(p) & 0xff00; + int startx = xx; + u16 *q = p; + while (xx < video_num_columns && count) { + if (attrib != (scr_readw(p) & 0xff00)) { + if (p > q) + sw->con_putcs(vc, q, p-q, yy, startx); + startx = xx; + q = p; + attrib = scr_readw(p) & 0xff00; } - break; + p++; + xx++; + count--; } - - if (KTYP(v) < NR_TYPES) { - if (KVAL(v) > max_vals[KTYP(v)]) - return -EINVAL; - } else - if (kbd->kbdmode != VC_UNICODE) - return -EINVAL; - - /* ++Geert: non-PC keyboards may generate keycode zero */ -#if !defined(__mc68000__) && !defined(__powerpc__) - /* assignment to entry 0 only tests validity of args */ - if (!i) + if (p > q) + sw->con_putcs(vc, q, p-q, yy, startx); + if (!count) break; + xx = 0; + yy++; + if (sw->con_getxy) { + p = (u16 *)start; + start = sw->con_getxy(vc, start, NULL, NULL); + } + } #endif +} + +void update_region(struct vc_data *vc, unsigned long start, int count) +{ + if (DO_UPDATE) { + hide_cursor(vc); + do_update_region(vc, start, count); + set_cursor(vc); + } +} + +inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) +{ + unsigned short *p; - if (!(key_map = key_maps[s])) { - int j; + if (!viewed) + p = (unsigned short *)(origin + offset); + else if (!sw->con_screen_pos) + p = (unsigned short *)(visible_origin + offset); + else + p = sw->con_screen_pos(vc, offset); + return p; +} - if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && - !capable(CAP_SYS_RESOURCE)) - return -EPERM; - - key_map = (ushort *) kmalloc(sizeof(plain_map), - GFP_KERNEL); - if (!key_map) - return -ENOMEM; - key_maps[s] = key_map; - key_map[0] = U(K_ALLOCATED); - for (j = 1; j < NR_KEYS; j++) - key_map[j] = U(K_HOLE); - keymap_count++; +/* Note: inverting the screen twice should revert to the original state */ +void invert_screen(struct vc_data *vc, int offset, int count, int viewed) +{ + unsigned short *p; + + count /= 2; + p = screenpos(vc, offset, viewed); + if (sw->con_invert_region) + sw->con_invert_region(vc, p, count); +#ifndef VT_BUF_VRAM_ONLY + else { + u16 *q = p; + int cnt = count; + u16 a; + + if (!can_do_color) { + while (cnt--) { + a = scr_readw(q); + a ^= 0x0800; + scr_writew(a, q); + q++; + } + } else if (hi_font_mask == 0x100) { + while (cnt--) { + a = scr_readw(q); + a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); + scr_writew(a, q); + q++; + } + } else { + while (cnt--) { + a = scr_readw(q); + a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); + scr_writew(a, q); + q++; + } } - ov = U(key_map[i]); - if (v == ov) - break; /* nothing to do */ - /* - * Attention Key. - */ - if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) - return -EPERM; - key_map[i] = U(v); - if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) - compute_shiftstate(); - break; } - return 0; +#endif + if (DO_UPDATE) + do_update_region(vc, (unsigned long) p, count); } -#undef i -#undef s -#undef v -static inline int -do_kbkeycode_ioctl(int cmd, struct kbkeycode *user_kbkc, int perm) +/* Redrawing of screen */ +void update_screen(struct vc_data *vc) { - struct kbkeycode tmp; - int kc = 0; + int update; - if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) - return -EFAULT; - switch (cmd) { - case KDGETKEYCODE: - kc = getkeycode(tmp.scancode); - if (kc >= 0) - kc = put_user(kc, &user_kbkc->keycode); - break; - case KDSETKEYCODE: - if (!perm) - return -EPERM; - kc = setkeycode(tmp.scancode, tmp.keycode); - break; - } - return kc; -} - -static inline int -do_kdgkb_ioctl(int cmd, struct kbsentry *user_kdgkb, int perm) -{ - struct kbsentry tmp; - char *p; - u_char *q; - int sz; - int delta; - char *first_free, *fj, *fnw; - int i, j, k; + if (!vc) return; - /* we mostly copy too much here (512bytes), but who cares ;) */ - if (copy_from_user(&tmp, user_kdgkb, sizeof(struct kbsentry))) - return -EFAULT; - tmp.kb_string[sizeof(tmp.kb_string)-1] = '\0'; - if (tmp.kb_func >= MAX_NR_FUNC) - return -EINVAL; - i = tmp.kb_func; + hide_cursor(vc); + set_origin(vc); - switch (cmd) { - case KDGKBSENT: - sz = sizeof(tmp.kb_string) - 1; /* sz should have been - a struct member */ - q = user_kdgkb->kb_string; - p = func_table[i]; - if(p) - for ( ; *p && sz; p++, sz--) - if (put_user(*p, q++)) - return -EFAULT; - if (put_user('\0', q)) - return -EFAULT; - return ((p && *p) ? -EOVERFLOW : 0); - case KDSKBSENT: - if (!perm) - return -EPERM; - - q = func_table[i]; - first_free = funcbufptr + (funcbufsize - funcbufleft); - for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) - ; - if (j < MAX_NR_FUNC) - fj = func_table[j]; - else - fj = first_free; - - delta = (q ? -strlen(q) : 1) + strlen(tmp.kb_string); - if (delta <= funcbufleft) { /* it fits in current buf */ - if (j < MAX_NR_FUNC) { - memmove(fj + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] += delta; - } - if (!q) - func_table[i] = fj; - funcbufleft -= delta; - } else { /* allocate a larger buffer */ - sz = 256; - while (sz < funcbufsize - funcbufleft + delta) - sz <<= 1; - fnw = (char *) kmalloc(sz, GFP_KERNEL); - if(!fnw) - return -ENOMEM; - - if (!q) - func_table[i] = fj; - if (fj > funcbufptr) - memmove(fnw, funcbufptr, fj - funcbufptr); - for (k = 0; k < j; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr); - - if (first_free > fj) { - memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; - } - if (funcbufptr != func_buf) - kfree(funcbufptr); - funcbufptr = fnw; - funcbufleft = funcbufleft - delta + sz - funcbufsize; - funcbufsize = sz; + update = sw->con_switch(vc); + set_palette(vc); + + if (update && vcmode != KD_GRAPHICS) + do_update_region(vc, origin, screenbuf_size/2); + + set_cursor(vc); +} + +/* used by selection: complement pointer position */ +void complement_pos(struct vc_data *vc, int offset) +{ + static unsigned short *p; + static unsigned short old; + static unsigned short oldx, oldy; + + if (p) { + scr_writew(old, p); + if (DO_UPDATE) + sw->con_putc(vc, old, oldy, oldx); + } + if (offset == -1) + p = NULL; + else { + unsigned short new; + p = screenpos(vc, offset, 1); + old = scr_readw(p); + new = old ^ complement_mask; + scr_writew(new, p); + if (DO_UPDATE) { + oldx = (offset >> 1) % video_num_columns; + oldy = (offset >> 1) / video_num_columns; + sw->con_putc(vc, new, oldy, oldx); } - strcpy(func_table[i], tmp.kb_string); - break; } - return 0; } -static inline int -do_fontx_ioctl(int cmd, struct consolefontdesc *user_cfd, int perm) +/* + * Screen blanking + */ + +/* This is a timer handler */ +static void powerdown_screen(unsigned long private) +{ + struct vt_struct *vt = (struct vt_struct *) private; + struct vc_data *vc = vt->vc_cons[fg_console]; + + vt->timer.function = unblank_screen_t; + + /* + * Power down if currently suspended (1 or 2), + * suspend if currently blanked (0), + * else do nothing (i.e. already powered down (3)). + * Called only if powerdown features are allowed. + */ + switch (vt->blank_mode) { + case VESA_NO_BLANKING: + vt->vt_sw->con_blank(vc, VESA_VSYNC_SUSPEND+1); + break; + case VESA_VSYNC_SUSPEND: + case VESA_HSYNC_SUSPEND: + vt->vt_sw->con_blank(vc, VESA_POWERDOWN+1); + break; + } +} + +static void timer_do_blank_screen(struct vt_struct *vt, int entering_gfx, + int from_timer_handler) { - struct consolefontdesc cfdarg; - struct console_font_op op; + struct vc_data *vc = vt->vc_cons[fg_console]; int i; - if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) - return -EFAULT; - - switch (cmd) { - case PIO_FONTX: - if (!perm) - return -EPERM; - op.op = KD_FONT_OP_SET; - op.flags = KD_FONT_FLAG_OLD; - op.width = 8; - op.height = cfdarg.charheight; - op.charcount = cfdarg.charcount; - op.data = cfdarg.chardata; - return con_font_op(fg_console, &op); - case GIO_FONTX: { - op.op = KD_FONT_OP_GET; - op.flags = KD_FONT_FLAG_OLD; - op.width = 8; - op.height = cfdarg.charheight; - op.charcount = cfdarg.charcount; - op.data = cfdarg.chardata; - i = con_font_op(fg_console, &op); - if (i) - return i; - cfdarg.charheight = op.height; - cfdarg.charcount = op.charcount; - if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc))) - return -EFAULT; - return 0; - } + if (vt->vt_blanked) + return; + + /* entering graphics mode? */ + if (entering_gfx) { + hide_cursor(vc); + save_screen(vc); + sw->con_blank(vc, -1); + vt->vt_blanked = fg_console + 1; + set_origin(vc); + return; + } + + /* don't blank graphics */ + if (vcmode != KD_TEXT) { + vt->vt_blanked = fg_console + 1; + return; } - return -EINVAL; + + hide_cursor(vc); + if (!from_timer_handler) + del_timer_sync(&vt->timer); + if (vt->off_interval) { + vt->timer.function = powerdown_screen; + mod_timer(&vt->timer, jiffies + vt->off_interval); + } else { + if (!from_timer_handler) + del_timer_sync(&vt->timer); + vt->timer.function = unblank_screen_t; + } + + save_screen(vc); + /* In case we need to reset origin, blanking hook returns 1 */ + i = sw->con_blank(vc, 1); + vt->vt_blanked = fg_console + 1; + if (i) + set_origin(vc); + + if (console_blank_hook && console_blank_hook(1)) + return; + if (vt->blank_mode) + sw->con_blank(vc, vt->blank_mode + 1); } -static inline int -do_unimap_ioctl(int cmd, struct unimapdesc *user_ud,int perm) +void do_blank_screen(struct vt_struct *vt, int entering_gfx) { - struct unimapdesc tmp; - int i = 0; + timer_do_blank_screen(vt, entering_gfx, 0); +} - if (copy_from_user(&tmp, user_ud, sizeof tmp)) - return -EFAULT; - if (tmp.entries) { - i = verify_area(VERIFY_WRITE, tmp.entries, - tmp.entry_ct*sizeof(struct unipair)); - if (i) return i; - } - switch (cmd) { - case PIO_UNIMAP: - if (!perm) - return -EPERM; - return con_set_unimap(fg_console, tmp.entry_ct, tmp.entries); - case GIO_UNIMAP: - return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); +/* This is both a user-level callable and a timer handler */ +static void blank_screen(unsigned long private) +{ + struct vt_struct *vt = (struct vt_struct *) private; + + timer_do_blank_screen(vt, 0, 1); +} + +/* This is a timer handler */ +static void unblank_screen_t(unsigned long private) +{ + unblank_screen(); +} + +/* Called by timer as well as from vt_console_driver */ +void unblank_screen(void) +{ + struct vt_struct *vt = vt_cons; + struct vc_data *vc = vt->vc_cons[fg_console]; + + if (!vt->vt_blanked) + return; + if (!vc) { + /* impossible */ + printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); + return; + } + if (vcmode != KD_TEXT) + return; /* but leave console_blanked != 0 */ + + vt->timer.function = blank_screen; + if (vt->blank_interval) + mod_timer(&vt->timer, jiffies + vt->blank_interval); + + vt->vt_blanked = 0; + if (console_blank_hook) + console_blank_hook(0); + if (sw->con_blank(vc, 0)) + /* Low-level driver cannot restore -> do it ourselves */ + update_screen(vc); + set_cursor(vc); +} + +void poke_blanked_console(struct vt_struct *vt) +{ + del_timer(&vt->timer); + if (!vt->vc_cons[fg_console] || vt->vc_cons[fg_console]->vc_mode == KD_GRAPHICS) + return; + if (vt->vt_blanked) { + vt->timer.function = unblank_screen_t; + mod_timer(&vt->timer, jiffies); /* Now */ + } else if (vt->blank_interval) { + mod_timer(&vt->timer, jiffies + vt->blank_interval); } - return 0; } /* - * We handle the console-specific ioctl's here. We allow the - * capability to modify any console, not just the fg_console. + * Power management for the console system. */ -int vt_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) +static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data) { - int i, perm; - unsigned int console; - unsigned char ucval; - struct kbd_struct * kbd; - struct vt_struct *vt = (struct vt_struct *)tty->driver_data; + struct vt_struct *vt = dev->data; - console = vt->vc_num; + if (vt) { + switch (rqst) { + case PM_RESUME: + unblank_screen(); + break; + case PM_SUSPEND: + do_blank_screen(vt, 0); + break; + } + } + return 0; +} - if (!vc_cons_allocated(console)) /* impossible? */ - return -ENOIOCTLCMD; +/* + * Allocation, freeing and resizing of VCs. + */ - /* - * To have permissions to do most of the vt ioctls, we either have - * to be the owner of the tty, or super-user. - */ - perm = 0; - if (current->tty == tty || suser()) - perm = 1; - - kbd = kbd_table + console; - switch (cmd) { - case KIOCSOUND: - if (!perm) - return -EPERM; - if (arg) - arg = 1193180 / arg; - kd_mksound(arg, 0); - return 0; +int vc_cons_allocated(unsigned int i) +{ + return (i < MAX_NR_CONSOLES && vt_cons->vc_cons[i]); +} - case KDMKTONE: - if (!perm) - return -EPERM; - { - unsigned int ticks, count; - - /* - * Generate the tone for the appropriate number of ticks. - * If the time is zero, turn off sound ourselves. - */ - ticks = HZ * ((arg >> 16) & 0xffff) / 1000; - count = ticks ? (arg & 0xffff) : 0; - if (count) - count = 1193180 / count; - kd_mksound(count, ticks); - return 0; - } +void set_console(int nr) +{ + struct vt_struct *vt = vt_cons; - case KDGKBTYPE: - /* - * this is naive. - */ - ucval = keyboard_type; - goto setchar; + vt->want_vc = vt->vc_cons[nr]; + schedule_task(&vt->vt_tq); +} -#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) - /* - * These cannot be implemented on any machine that implements - * ioperm() in user level (such as Alpha PCs). - */ - case KDADDIO: - case KDDELIO: - /* - * KDADDIO and KDDELIO may be able to add ports beyond what - * we reject here, but to be safe... - */ - if (arg < GPFIRST || arg > GPLAST) - return -EINVAL; - return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; - - case KDENABIO: - case KDDISABIO: - return sys_ioperm(GPFIRST, GPNUM, - (cmd == KDENABIO)) ? -ENXIO : 0; +static void visual_init(struct vc_data *vc, int init) +{ + /* ++Geert: sw->con_init determines console size */ + int currcons = cons_num; + + sw = conswitchp; +#ifndef VT_SINGLE_DRIVER + if (con_driver_map[currcons]) + sw = con_driver_map[currcons]; #endif + vc->display_fg->vc_cons[currcons] = vc; + vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir; + vc->vc_uni_pagedir = 0; + hi_font_mask = 0; + complement_mask = 0; + can_do_color = 0; + sw->con_init(vc, init); + if (!complement_mask) + complement_mask = can_do_color ? 0x7700 : 0x0800; + s_complement_mask = complement_mask; + video_size_row = video_num_columns<<1; + screenbuf_size = video_num_lines*video_size_row; +} - /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */ - - case KDKBDREP: - { - struct kbd_repeat kbrep; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; +static void vc_init(struct vc_data *vc, int do_clear) +{ + set_origin(vc); + pos = origin; + reset_vc(vc); + def_color = 0x07; /* white */ + ulcolor = 0x0f; /* bold white */ + halfcolor = 0x08; /* grey */ + init_waitqueue_head(&vc->paste_wait); + vte_ris(vc, do_clear); +} - if (copy_from_user(&kbrep, (void *)arg, - sizeof(struct kbd_repeat))) - return -EFAULT; - if ((i = kbd_rate( &kbrep ))) - return i; - if (copy_to_user((void *)arg, &kbrep, - sizeof(struct kbd_repeat))) - return -EFAULT; - return 0; +int vc_allocate(unsigned int currcons) /* return 0 on success */ +{ + struct vc_data *vc; + + if (currcons >= MAX_NR_CONSOLES) + return -ENXIO; + if (!vt_cons->vc_cons[currcons]) { + long p, q; + + /* prevent users from taking too much memory */ + if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) + return -EPERM; + + /* due to the granularity of kmalloc, we waste some memory here */ + /* the alloc is done in two steps, to optimize the common situation + of a 25x80 console (structsize=216, screenbuf_size=4000) */ + /* although the numbers above are not valid since long ago, the + point is still up-to-date and the comment still has its value + even if only as a historical artifact. --mj, July 1998 */ + p = (long) kmalloc(sizeof(struct vc_data), GFP_KERNEL); + if (!p) + return -ENOMEM; + vc = (struct vc_data *)p; + cons_num = currcons; + vc->display_fg = vt_cons; + visual_init(vc, 1); + if (!*vc->vc_uni_pagedir_loc) + con_set_default_unimap(vc); + q = (long)kmalloc(screenbuf_size, GFP_KERNEL); + if (!q) { + kfree((char *) p); + vc->display_fg->vc_cons[currcons] = NULL; + return -ENOMEM; + } + screenbuf = (unsigned short *) q; + kmalloced = 1; + vc_init(vc, 1); + + if (!pm_con) { + pm_con = pm_register(PM_SYS_DEV, PM_SYS_VGA, + pm_con_request); + if (pm_con) + pm_con->data = vt_cons; + } } + return 0; +} - case KDSETMODE: - /* - * currently, setting the mode from KD_TEXT to KD_GRAPHICS - * doesn't do a whole lot. i'm not sure if it should do any - * restoration of modes or what... - */ - if (!perm) - return -EPERM; - switch (arg) { - case KD_GRAPHICS: - break; - case KD_TEXT0: - case KD_TEXT1: - arg = KD_TEXT; - case KD_TEXT: - break; - default: - return -EINVAL; +/* + * Change # of rows and columns (0 means unchanged/the size of fg_console) + * [this is to be used together with some user program + * like resize that changes the hardware videomode] + */ +int vc_resize(unsigned int lines, unsigned int cols, + unsigned int first, unsigned int last) +{ + unsigned int cc, ll, ss, sr, todo = 0; + unsigned int currcons = fg_console, i; + unsigned short *newscreens[MAX_NR_CONSOLES]; + struct vc_data *vc = vt_cons->vc_cons[currcons]; + + cc = (cols ? cols : video_num_columns); + ll = (lines ? lines : video_num_lines); + sr = cc << 1; + ss = sr * ll; + + for (currcons = first; currcons <= last; currcons++) { + if (!vc_cons_allocated(currcons) || + (cc == video_num_columns && ll == video_num_lines)) + newscreens[currcons] = NULL; + else { + unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER); + if (!p) { + for (i = first; i < currcons; i++) + if (newscreens[i]) + kfree(newscreens[i]); + return -ENOMEM; + } + newscreens[currcons] = p; + todo++; } - if (vt_cons[console]->vc_mode == (unsigned char) arg) - return 0; - vt_cons[console]->vc_mode = (unsigned char) arg; - if (console != fg_console) - return 0; - /* - * explicitly blank/unblank the screen if switching modes - */ - if (arg == KD_TEXT) - unblank_screen(); - else - do_blank_screen(1); + } + if (!todo) return 0; - case KDGETMODE: - ucval = vt_cons[console]->vc_mode; - goto setint; - - case KDMAPDISP: - case KDUNMAPDISP: - /* - * these work like a combination of mmap and KDENABIO. - * this could be easily finished. - */ - return -EINVAL; + for (currcons = first; currcons <= last; currcons++) { + unsigned int occ, oll, oss, osr; + unsigned long ol, nl, nlend, rlth, rrem; + struct vc_data *vc = vt_cons->vc_cons[currcons]; + + if (!newscreens[currcons] || !vc) + continue; - case KDSKBMODE: - if (!perm) - return -EPERM; - switch(arg) { - case K_RAW: - kbd->kbdmode = VC_RAW; - break; - case K_MEDIUMRAW: - kbd->kbdmode = VC_MEDIUMRAW; - break; - case K_XLATE: - kbd->kbdmode = VC_XLATE; - compute_shiftstate(); - break; - case K_UNICODE: - kbd->kbdmode = VC_UNICODE; - compute_shiftstate(); - break; - default: - return -EINVAL; + oll = video_num_lines; + occ = video_num_columns; + osr = video_size_row; + oss = screenbuf_size; + + video_num_lines = ll; + video_num_columns = cc; + video_size_row = sr; + screenbuf_size = ss; + + rlth = MIN(osr, sr); + rrem = sr - rlth; + ol = origin; + nl = (long) newscreens[currcons]; + nlend = nl + ss; + if (ll < oll) + ol += (oll - ll) * osr; + + update_attr(vc); + + while (ol < scr_end) { + scr_memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); + if (rrem) + scr_memsetw((void *)(nl + rlth), video_erase_char, rrem); + ol += osr; + nl += sr; } - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - return 0; - - case KDGKBMODE: - ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : - (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : - (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : - K_XLATE); - goto setint; - - /* this could be folded into KDSKBMODE, but for compatibility - reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ - case KDSKBMETA: - switch(arg) { - case K_METABIT: - clr_vc_kbd_mode(kbd, VC_META); - break; - case K_ESCPREFIX: - set_vc_kbd_mode(kbd, VC_META); - break; - default: - return -EINVAL; + if (nlend > nl) + scr_memsetw((void *) nl, video_erase_char, nlend - nl); + if (kmalloced) + kfree(screenbuf); + screenbuf = newscreens[currcons]; + kmalloced = 1; + screenbuf_size = ss; + set_origin(vc); + + /* do part of a vte_ris() */ + top = 0; + bottom = video_num_lines; + gotoxy(vc, x, y); + vte_decsc(vc); + + if (console_table[currcons]) { + struct winsize ws, *cws = &console_table[currcons]->winsize; + memset(&ws, 0, sizeof(ws)); + ws.ws_row = video_num_lines; + ws.ws_col = video_num_columns; + if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) && + console_table[currcons]->pgrp > 0) + kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1); + *cws = ws; } - return 0; - - case KDGKBMETA: - ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); - setint: - return put_user(ucval, (int *)arg); - - case KDGETKEYCODE: - case KDSETKEYCODE: - if(!capable(CAP_SYS_ADMIN)) - perm=0; - return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm); - - case KDGKBENT: - case KDSKBENT: - return do_kdsk_ioctl(cmd, (struct kbentry *)arg, perm, kbd); - - case KDGKBSENT: - case KDSKBSENT: - return do_kdgkb_ioctl(cmd, (struct kbsentry *)arg, perm); - - case KDGKBDIACR: - { - struct kbdiacrs *a = (struct kbdiacrs *)arg; - if (put_user(accent_table_size, &a->kb_cnt)) - return -EFAULT; - if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr))) - return -EFAULT; - return 0; + if (IS_VISIBLE) + update_screen(vc); } + return 0; +} - case KDSKBDIACR: - { - struct kbdiacrs *a = (struct kbdiacrs *)arg; - unsigned int ct; +void vc_disallocate(unsigned int currcons) +{ + struct vc_data *vc = vt_cons->vc_cons[currcons]; - if (!perm) - return -EPERM; - if (get_user(ct,&a->kb_cnt)) - return -EFAULT; - if (ct >= MAX_DIACR) - return -EINVAL; - accent_table_size = ct; - if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr))) - return -EFAULT; - return 0; + acquire_console_sem(); + if (vc) { + sw->con_deinit(vc); + if (kmalloced) + kfree(screenbuf); + if (currcons >= MIN_NR_CONSOLES) + kfree(vt_cons->vc_cons[currcons]); + vt_cons->vc_cons[currcons] = NULL; } + release_console_sem(); +} - /* the ioctls below read/set the flags usually shown in the leds */ - /* don't use them - they will go away without warning */ - case KDGKBLED: - ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); - goto setchar; - - case KDSKBLED: - if (!perm) - return -EPERM; - if (arg & ~0x77) - return -EINVAL; - kbd->ledflagstate = (arg & 7); - kbd->default_ledflagstate = ((arg >> 4) & 7); - set_leds(); - return 0; +/* + * Selection stuff for GPM. + */ +void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry) +{ + char buf[8]; - /* the ioctls below only set the lights, not the functions */ - /* for those, see KDGKBLED and KDSKBLED above */ - case KDGETLED: - ucval = getledstate(); - setchar: - return put_user(ucval, (char*)arg); - - case KDSETLED: - if (!perm) - return -EPERM; - setledstate(kbd, arg); - return 0; + sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), + (char)('!' + mry)); + respond_string(buf, tty); +} - /* - * A process can indicate its willingness to accept signals - * generated by pressing an appropriate key combination. - * Thus, one can have a daemon that e.g. spawns a new console - * upon a keypress and then changes to it. - * Probably init should be changed to do this (and have a - * field ks (`keyboard signal') in inittab describing the - * desired action), so that the number of background daemons - * does not increase. - */ - case KDSIGACCEPT: - { - extern int spawnpid, spawnsig; - if (!perm || !capable(CAP_KILL)) - return -EPERM; - if (arg < 1 || arg > _NSIG || arg == SIGKILL) - return -EINVAL; - spawnpid = current->pid; - spawnsig = arg; - return 0; - } +/* invoked via ioctl(TIOCLINUX) and through set_selection */ +int mouse_reporting(struct vc_data *vc) +{ + return report_mouse; +} - case VT_SETMODE: - { - struct vt_mode tmp; +/* This is a temporary buffer used to prepare a tty console write + * so that we can easily avoid touching user space while holding the + * console spinlock. It is allocated in vt_console_init and is shared by + * this code and the vc_screen read/write tty calls. + * + * We have to allocate this statically in the kernel data section + * since console_init (and thus vt_console_init) are called before any + * kernel memory allocation is available. + */ +char con_buf[PAGE_SIZE]; +#define CON_BUF_SIZE PAGE_SIZE +DECLARE_MUTEX(con_buf_sem); - if (!perm) - return -EPERM; - if (copy_from_user(&tmp, (void*)arg, sizeof(struct vt_mode))) - return -EFAULT; - if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) - return -EINVAL; - vt_cons[console]->vt_mode = tmp; - /* the frsig is ignored, so we set it to 0 */ - vt_cons[console]->vt_mode.frsig = 0; - vt_cons[console]->vt_pid = current->pid; - /* no switch is required -- saw@shade.msu.ru */ - vt_cons[console]->vt_newvt = -1; - return 0; +static int do_con_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ +#ifdef VT_BUF_VRAM_ONLY +#define FLUSH do { } while(0); +#else +#define FLUSH if (draw_x >= 0) { \ + sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \ + draw_x = -1; \ } +#endif - case VT_GETMODE: - return copy_to_user((void*)arg, &(vt_cons[console]->vt_mode), - sizeof(struct vt_mode)) ? -EFAULT : 0; - - /* - * Returns global vt state. Note that VT 0 is always open, since - * it's an alias for the current VT, and people can't use it here. - * We cannot return state for more than 16 VTs, since v_state is short. - */ - case VT_GETSTATE: - { - struct vt_stat *vtstat = (struct vt_stat *)arg; - unsigned short state, mask; + int c, tc, ok, n = 0, draw_x = -1; + unsigned long draw_from = 0, draw_to = 0; + struct vc_data *vc = (struct vc_data *)tty->driver_data; + u16 himask, charmask; + const unsigned char *orig_buf = NULL; + int orig_count; + + if (in_interrupt()) + return count; + + if (!vc) { + /* could this happen? */ + static int error = 0; + if (!error) { + error = 1; + printk("con_write: tty %d not allocated\n", minor(tty->device)); + } + return 0; + } + + orig_buf = buf; + orig_count = count; + + if (from_user) { + down(&con_buf_sem); + +again: + if (count > CON_BUF_SIZE) + count = CON_BUF_SIZE; + console_conditional_schedule(); + if (copy_from_user(con_buf, buf, count)) { + n = 0; /* ?? are error codes legal here ?? */ + goto out; + } - if (put_user(fg_console + 1, &vtstat->v_active)) - return -EFAULT; - state = 1; /* /dev/tty0 is always open */ - for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) - if (VT_IS_IN_USE(i)) - state |= mask; - return put_user(state, &vtstat->v_state); + buf = con_buf; } - /* - * Returns the first available (non-opened) console. + /* At this point 'buf' is guarenteed to be a kernel buffer + * and therefore no access to userspace (and therefore sleeping) + * will be needed. The con_buf_sem serializes all tty based + * console rendering and vcs write/read operations. We hold + * the console spinlock during the entire write. */ - case VT_OPENQRY: - for (i = 0; i < MAX_NR_CONSOLES; ++i) - if (! VT_IS_IN_USE(i)) - break; - ucval = i < MAX_NR_CONSOLES ? (i+1) : -1; - goto setint; - /* - * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, - * with num >= 1 (switches to vt 0, our console, are not allowed, just - * to preserve sanity). - */ - case VT_ACTIVATE: - if (!perm) - return -EPERM; - if (arg == 0 || arg > MAX_NR_CONSOLES) - return -ENXIO; - arg--; - i = vc_allocate(arg); - if (i) - return i; - set_console(arg); - return 0; + acquire_console_sem(); - /* - * wait until the specified VT has been activated - */ - case VT_WAITACTIVE: - if (!perm) - return -EPERM; - if (arg == 0 || arg > MAX_NR_CONSOLES) - return -ENXIO; - return vt_waitactive(arg-1); + himask = hi_font_mask; + charmask = himask ? 0x1ff : 0xff; - /* - * If a vt is under process control, the kernel will not switch to it - * immediately, but postpone the operation until the process calls this - * ioctl, allowing the switch to complete. - * - * According to the X sources this is the behavior: - * 0: pending switch-from not OK - * 1: pending switch-from OK - * 2: completed switch-to OK - */ - case VT_RELDISP: - if (!perm) - return -EPERM; - if (vt_cons[console]->vt_mode.mode != VT_PROCESS) - return -EINVAL; + /* undraw cursor first */ + if (IS_VISIBLE) + hide_cursor(vc); + + while (!tty->stopped && count) { + c = *buf; + buf++; + n++; + count--; + + if (utf) { + /* Combine UTF-8 into Unicode */ + /* Incomplete characters silently ignored */ + if(c > 0x7f) { + if (utf_count > 0 && (c & 0xc0) == 0x80) { + utf_char = (utf_char << 6) | (c & 0x3f); + utf_count--; + if (utf_count == 0) + tc = c = utf_char; + else continue; + } else { + if ((c & 0xe0) == 0xc0) { + utf_count = 1; + utf_char = (c & 0x1f); + } else if ((c & 0xf0) == 0xe0) { + utf_count = 2; + utf_char = (c & 0x0f); + } else if ((c & 0xf8) == 0xf0) { + utf_count = 3; + utf_char = (c & 0x07); + } else if ((c & 0xfc) == 0xf8) { + utf_count = 4; + utf_char = (c & 0x03); + } else if ((c & 0xfe) == 0xfc) { + utf_count = 5; + utf_char = (c & 0x01); + } else + utf_count = 0; + continue; + } + } else { + tc = c; + utf_count = 0; + } + } else { /* no utf */ + tc = translate[toggle_meta ? (c|0x80) : c]; + } - /* - * Switching-from response - */ - if (vt_cons[console]->vt_newvt >= 0) - { - if (arg == 0) - /* - * Switch disallowed, so forget we were trying - * to do it. - */ - vt_cons[console]->vt_newvt = -1; - - else - { - /* - * The current vt has been released, so - * complete the switch. - */ - int newvt = vt_cons[console]->vt_newvt; - vt_cons[console]->vt_newvt = -1; - i = vc_allocate(newvt); - if (i) - return i; - /* - * When we actually do the console switch, - * make sure we are atomic with respect to - * other console switches.. - */ - acquire_console_sem(); - complete_change_console(newvt); - release_console_sem(); + /* If the original code was a control character we + * only allow a glyph to be displayed if the code is + * not normally used (such as for cursor movement) or + * if the disp_ctrl mode has been explicitly enabled. + * Certain characters (as given by the CTRL_ALWAYS + * bitmap) are always displayed as control characters, + * as the console would be pretty useless without + * them; to display an arbitrary font position use the + * direct-to-font zone in UTF-8 mode. + */ + ok = tc && (c >= 32 || + (!utf && !(((disp_ctrl ? CTRL_ALWAYS + : CTRL_ACTION) >> c) & 1))) + && (c != 127 || disp_ctrl) + && (c != 128+27); + + if (!vc_state && ok) { + /* Now try to find out how to display it */ + tc = conv_uni_to_pc(vc, tc); + if ( tc == -4 ) { + /* If we got -4 (not found) then see if we have + defined a replacement character (U+FFFD) */ + tc = conv_uni_to_pc(vc, 0xfffd); + + /* One reason for the -4 can be that we just + did a clear_unimap(); + try at least to show something. */ + if (tc == -4) + tc = c; + } else if ( tc == -3 ) { + /* Bad hash table -- hope for the best */ + tc = c; + } + if (tc & ~charmask) + continue; /* Conversion failed */ + + if (need_wrap || irm) + FLUSH + if (need_wrap) { + vte_cr(vc); + vte_lf(vc); } + if (irm) + insert_char(vc, 1); + scr_writew(himask ? + ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : + (attr << 8) + tc, + (u16 *) pos); + if (DO_UPDATE && draw_x < 0) { + draw_x = x; + draw_from = pos; + } + if (x == video_num_columns - 1) { + need_wrap = decawm; + draw_to = pos+2; + } else { + x++; + draw_to = (pos+=2); + } + continue; } - - /* - * Switched-to response + FLUSH + terminal_emulation(tty, c); + } + FLUSH + console_conditional_schedule(); + release_console_sem(); + +out: + if (from_user) { + /* If the user requested something larger than + * the CON_BUF_SIZE, and the tty is not stopped, + * keep going. */ - else - { - /* - * If it's just an ACK, ignore it - */ - if (arg != VT_ACKACQ) - return -EINVAL; - } - - return 0; - - /* - * Disallocate memory associated to VT (but leave VT1) - */ - case VT_DISALLOCATE: - if (arg > MAX_NR_CONSOLES) - return -ENXIO; - if (arg == 0) { - /* disallocate all unused consoles, but leave 0 */ - for (i=1; i CON_BUF_SIZE) && !tty->stopped) { + orig_count -= CON_BUF_SIZE; + orig_buf += CON_BUF_SIZE; + count = orig_count; + buf = orig_buf; + goto again; } - return 0; - case VT_RESIZE: - { - struct vt_sizes *vtsizes = (struct vt_sizes *) arg; - ushort ll,cc; - if (!perm) - return -EPERM; - if (get_user(ll, &vtsizes->v_rows) || - get_user(cc, &vtsizes->v_cols)) - return -EFAULT; - return vc_resize_all(ll, cc); + up(&con_buf_sem); } - case VT_RESIZEX: - { - struct vt_consize *vtconsize = (struct vt_consize *) arg; - ushort ll,cc,vlin,clin,vcol,ccol; - if (!perm) - return -EPERM; - if (verify_area(VERIFY_READ, (void *)vtconsize, - sizeof(struct vt_consize))) - return -EFAULT; - __get_user(ll, &vtconsize->v_rows); - __get_user(cc, &vtconsize->v_cols); - __get_user(vlin, &vtconsize->v_vlin); - __get_user(clin, &vtconsize->v_clin); - __get_user(vcol, &vtconsize->v_vcol); - __get_user(ccol, &vtconsize->v_ccol); - vlin = vlin ? vlin : video_scan_lines; - if ( clin ) - { - if ( ll ) - { - if ( ll != vlin/clin ) - return -EINVAL; /* Parameters don't add up */ - } - else - ll = vlin/clin; - } - if ( vcol && ccol ) - { - if ( cc ) - { - if ( cc != vcol/ccol ) - return -EINVAL; - } - else - cc = vcol/ccol; - } - - if ( clin > 32 ) - return -EINVAL; - - if ( vlin ) - video_scan_lines = vlin; - if ( clin ) - video_font_height = clin; - - return vc_resize_all(ll, cc); - } + return n; +#undef FLUSH +} - case PIO_FONT: { - struct console_font_op op; - if (!perm) - return -EPERM; - op.op = KD_FONT_OP_SET; - op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ - op.width = 8; - op.height = 0; - op.charcount = 256; - op.data = (char *) arg; - return con_font_op(fg_console, &op); - } - - case GIO_FONT: { - struct console_font_op op; - op.op = KD_FONT_OP_GET; - op.flags = KD_FONT_FLAG_OLD; - op.width = 8; - op.height = 32; - op.charcount = 256; - op.data = (char *) arg; - return con_font_op(fg_console, &op); - } - - case PIO_CMAP: - if (!perm) - return -EPERM; - return con_set_cmap((char *)arg); - - case GIO_CMAP: - return con_get_cmap((char *)arg); - - case PIO_FONTX: - case GIO_FONTX: - return do_fontx_ioctl(cmd, (struct consolefontdesc *)arg, perm); +/* + * This is the console switching callback. + * + * Doing console switching in a process context allows + * us to do the switches asynchronously (needed when we want + * to switch due to a keyboard interrupt). Synchronization + * with other console code and prevention of re-entrancy is + * ensured with console_sem. + */ +static void vt_callback(void *private) +{ + struct vt_struct *vt = (struct vt_struct *) private; - case PIO_FONTRESET: - { - if (!perm) - return -EPERM; + if (!vt || !vt->want_vc || !vt->want_vc->vc_tty) + return; -#ifdef BROKEN_GRAPHICS_PROGRAMS - /* With BROKEN_GRAPHICS_PROGRAMS defined, the default - font is not saved. */ - return -ENOSYS; -#else - { - struct console_font_op op; - op.op = KD_FONT_OP_SET_DEFAULT; - op.data = NULL; - i = con_font_op(fg_console, &op); - if (i) return i; - con_set_default_unimap(fg_console); - return 0; - } -#endif - } + acquire_console_sem(); - case KDFONTOP: { - struct console_font_op op; - if (copy_from_user(&op, (void *) arg, sizeof(op))) - return -EFAULT; - if (!perm && op.op != KD_FONT_OP_GET) - return -EPERM; - i = con_font_op(console, &op); - if (i) return i; - if (copy_to_user((void *) arg, &op, sizeof(op))) - return -EFAULT; - return 0; + if (vt->want_vc->vc_num != fg_console) { + hide_cursor(vt->vc_cons[fg_console]); + change_console(vt->want_vc, vt->vc_cons[fg_console]); + /* we only changed when the console had already + been allocated - a new console is not created + in an interrupt routine */ + } + /* do not unblank for a LED change */ + if (do_poke_blanked_console) { + do_poke_blanked_console = 0; + poke_blanked_console(vt); + } + if (vt->scrollback_delta) { + int currcons = fg_console; + struct vc_data *vc = vt->vc_cons[currcons]; + + clear_selection(); + if (vcmode == KD_TEXT) + sw->con_scrolldelta(vc, vt->scrollback_delta); + vt->scrollback_delta = 0; } + release_console_sem(); +} - case PIO_SCRNMAP: - if (!perm) - return -EPERM; - return con_set_trans_old((unsigned char *)arg); - - case GIO_SCRNMAP: - return con_get_trans_old((unsigned char *)arg); - - case PIO_UNISCRNMAP: - if (!perm) - return -EPERM; - return con_set_trans_new((unsigned short *)arg); - - case GIO_UNISCRNMAP: - return con_get_trans_new((unsigned short *)arg); - - case PIO_UNIMAPCLR: - { struct unimapinit ui; - if (!perm) - return -EPERM; - i = copy_from_user(&ui, (void *)arg, sizeof(struct unimapinit)); - if (i) return -EFAULT; - con_clear_unimap(fg_console, &ui); - return 0; - } +/* + * Handling of Linux-specific VC ioctls + */ - case PIO_UNIMAP: - case GIO_UNIMAP: - return do_unimap_ioctl(cmd, (struct unimapdesc *)arg, perm); - - case VT_LOCKSWITCH: - if (!suser()) - return -EPERM; - vt_dont_switch = 1; - return 0; - case VT_UNLOCKSWITCH: - if (!suser()) - return -EPERM; - vt_dont_switch = 0; - return 0; -#ifdef CONFIG_FB_COMPAT_XPMAC - case VC_GETMODE: - { - struct vc_mode mode; - - i = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct vc_mode)); - if (i == 0) - i = console_getmode(&mode); - if (i) - return i; - if (copy_to_user((void *) arg, &mode, sizeof(mode))) - return -EFAULT; - return 0; - } - case VC_SETMODE: - case VC_INQMODE: - { - struct vc_mode mode; - - if (!perm) - return -EPERM; - if (copy_from_user(&mode, (void *) arg, sizeof(mode))) +int tioclinux(struct tty_struct *tty, unsigned long arg) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + char type, data; + int ret; + + if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) + return -EINVAL; + if (current->tty != tty && !capable(CAP_SYS_ADMIN)) + return -EPERM; + if (get_user(type, (char *)arg)) + return -EFAULT; + ret = 0; + switch (type) + { + case 2: + acquire_console_sem(); + ret = set_selection(arg, tty, 1); + release_console_sem(); + break; + case 3: + ret = paste_selection(tty); + break; + case 4: + unblank_screen(); + break; + case 5: + ret = sel_loadlut(arg); + break; + case 6: + + /* + * Make it possible to react to Shift+Mousebutton. + * Note that 'shift_state' is an undocumented + * kernel-internal variable; programs not closely + * related to the kernel should not use this. + */ + data = shift_state; + ret = __put_user(data, (char *) arg); + break; + case 7: + data = mouse_reporting(vc); + ret = __put_user(data, (char *) arg); + break; + case 10: + if (get_user(data, (char *)arg+1)) return -EFAULT; - return console_setmode(&mode, cmd == VC_SETMODE); - } - case VC_SETCMAP: - { - unsigned char cmap[3][256], *p; - int n_entries, cmap_size, i, j; - - if (!perm) - return -EPERM; - if (arg == (unsigned long) VC_POWERMODE_INQUIRY - || arg <= VESA_POWERDOWN) { - /* compatibility hack: VC_POWERMODE - was changed from 0x766a to 0x766c */ - return console_powermode((int) arg); + vc->display_fg->blank_mode = (data < 4) ? data : 0; + break; + case 11: /* set kmsg redirect */ + if (!capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + } else { + if (get_user(data, (char *)arg+1)) + ret = -EFAULT; + else + kmsg_redirect = data; } - if (get_user(cmap_size, (int *) arg)) - return -EFAULT; - if (cmap_size % 3) - return -EINVAL; - n_entries = cmap_size / 3; - if ((unsigned) n_entries > 256) - return -EINVAL; - p = (unsigned char *) (arg + sizeof(int)); - for (j = 0; j < n_entries; ++j) - for (i = 0; i < 3; ++i) - if (get_user(cmap[i][j], p++)) - return -EFAULT; - return console_setcmap(n_entries, cmap[0], - cmap[1], cmap[2]); - } - case VC_GETCMAP: - /* not implemented yet */ - return -ENOIOCTLCMD; - case VC_POWERMODE: - if (!perm) - return -EPERM; - return console_powermode((int) arg); -#endif /* CONFIG_FB_COMPAT_XPMAC */ - default: - return -ENOIOCTLCMD; + break; + case 12: /* get fg_console */ + ret = fg_console; + break; + default: + ret = -EINVAL; + break; } + return ret; } /* - * Sometimes we want to wait until a particular VT has been activated. We - * do it in a very simple manner. Everybody waits on a single queue and - * get woken up at once. Those that are satisfied go on with their business, - * while those not ready go back to sleep. Seems overkill to add a wait - * to each vt just for this - usually this does nothing! + * /dev/ttyN handling */ -static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); -/* - * Sleeps until a vt is activated, or the task is interrupted. Returns - * 0 if activation, -EINTR if interrupted. - */ -int vt_waitactive(int vt) +/* Allocate the console screen memory. */ +static int con_open(struct tty_struct *tty, struct file * filp) { - int retval; - DECLARE_WAITQUEUE(wait, current); + struct vc_data *vc; + unsigned int currcons; + int i; - add_wait_queue(&vt_activate_queue, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - retval = 0; - if (vt == fg_console) - break; - retval = -EINTR; - if (signal_pending(current)) - break; - schedule(); + currcons = minor(tty->device) - tty->driver.minor_start; + + i = vc_allocate(currcons); + if (i) + return i; + + vc = vt_cons->vc_cons[currcons]; + tty->driver_data = vc; + vc->vc_tty = tty; + + if (!tty->winsize.ws_row && !tty->winsize.ws_col) { + tty->winsize.ws_row = video_num_lines; + tty->winsize.ws_col = video_num_columns; } - remove_wait_queue(&vt_activate_queue, &wait); - current->state = TASK_RUNNING; + if (tty->count == 1) + vcs_make_devfs(currcons, 0); + return 0; +} + +static void con_close(struct tty_struct *tty, struct file * filp) +{ + if (!tty || tty->count != 1) + return; + + vcs_make_devfs (minor(tty->device) - tty->driver.minor_start, 1); + tty->driver_data = 0; +} + +static int con_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int retval; + + pm_access(pm_con); + retval = do_con_write(tty, from_user, buf, count); + con_flush_chars(tty); + return retval; } -#define vt_wake_waitactive() wake_up(&vt_activate_queue) +static void con_put_char(struct tty_struct *tty, unsigned char ch) +{ + if (in_interrupt()) + return; /* n_r3964 calls put_char() from interrupt context */ + pm_access(pm_con); + do_con_write(tty, 0, &ch, 1); +} + +static int con_write_room(struct tty_struct *tty) +{ + if (tty->stopped) + return 0; + return 4096; /* No limit, really; we're not buffering */ +} + +static void con_flush_chars(struct tty_struct *tty) +{ + struct vc_data *vc; + + if (in_interrupt()) /* from flush_to_ldisc */ + return; + + pm_access(pm_con); + lock_kernel(); + acquire_console_sem(); + vc = (struct vc_data *)tty->driver_data; + if (vc) + set_cursor(vc); + release_console_sem(); + unlock_kernel(); +} -void reset_vc(unsigned int new_console) +static int con_chars_in_buffer(struct tty_struct *tty) { - vt_cons[new_console]->vc_mode = KD_TEXT; - kbd_table[new_console].kbdmode = VC_XLATE; - vt_cons[new_console]->vt_mode.mode = VT_AUTO; - vt_cons[new_console]->vt_mode.waitv = 0; - vt_cons[new_console]->vt_mode.relsig = 0; - vt_cons[new_console]->vt_mode.acqsig = 0; - vt_cons[new_console]->vt_mode.frsig = 0; - vt_cons[new_console]->vt_pid = -1; - vt_cons[new_console]->vt_newvt = -1; - if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ - reset_palette(new_console) ; + return 0; /* we're not buffering */ } /* - * Performs the back end of a vt switch + * Turn the Scroll-Lock LED on when the tty is stopped */ -void complete_change_console(unsigned int new_console) +static void con_stop(struct tty_struct *tty) { - unsigned char old_vc_mode; + struct vc_data *vc = (struct vc_data *) tty->driver_data; - last_console = fg_console; + if (!tty || !vc) + return; + set_kbd_led(&vc->kbd_table, VC_SCROLLOCK); + set_leds(); +} - /* - * If we're switching, we could be going from KD_GRAPHICS to - * KD_TEXT mode or vice versa, which means we need to blank or - * unblank the screen later. - */ - old_vc_mode = vt_cons[fg_console]->vc_mode; - switch_screen(new_console); +/* + * Turn the Scroll-Lock LED off when the console is started + */ +static void con_start(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; + + if (!tty || !vc) + return; + clr_kbd_led(&vc->kbd_table, VC_SCROLLOCK); + set_leds(); +} - /* - * This can't appear below a successful kill_proc(). If it did, - * then the *blank_screen operation could occur while X, having - * received acqsig, is waking up on another processor. This - * condition can lead to overlapping accesses to the VGA range - * and the framebuffer (causing system lockups). - * - * To account for this we duplicate this code below only if the - * controlling process is gone and we've called reset_vc. - */ - if (old_vc_mode != vt_cons[new_console]->vc_mode) - { - if (vt_cons[new_console]->vc_mode == KD_TEXT) - unblank_screen(); - else - do_blank_screen(1); - } +/* + * con_throttle and con_unthrottle are only used for + * paste_selection(), which has to stuff in a large number of + * characters... + */ +static void con_throttle(struct tty_struct *tty) +{ +} - /* - * If this new console is under process control, send it a signal - * telling it that it has acquired. Also check if it has died and - * clean up (similar to logic employed in change_console()) - */ - if (vt_cons[new_console]->vt_mode.mode == VT_PROCESS) - { - /* - * Send the signal as privileged - kill_proc() will - * tell us if the process has gone or something else - * is awry - */ - if (kill_proc(vt_cons[new_console]->vt_pid, - vt_cons[new_console]->vt_mode.acqsig, - 1) != 0) - { - /* - * The controlling process has died, so we revert back to - * normal operation. In this case, we'll also change back - * to KD_TEXT mode. I'm not sure if this is strictly correct - * but it saves the agony when the X server dies and the screen - * remains blanked due to KD_GRAPHICS! It would be nice to do - * this outside of VT_PROCESS but there is no single process - * to account for and tracking tty count may be undesirable. - */ - reset_vc(new_console); +static void con_unthrottle(struct tty_struct *tty) +{ + struct vc_data *vc = (struct vc_data *) tty->driver_data; - if (old_vc_mode != vt_cons[new_console]->vc_mode) - { - if (vt_cons[new_console]->vc_mode == KD_TEXT) - unblank_screen(); - else - do_blank_screen(1); + wake_up_interruptible(&vc->paste_wait); +} + +#ifdef CONFIG_VT_CONSOLE + +/* + * Console on virtual terminal + * + * The console_lock must be held when we get here. + */ + +void vt_console_print(struct console *co, const char * b, unsigned count) +{ + int currcons = fg_console; + unsigned char c; + static unsigned long printing = 0; + struct vc_data *vc; + const ushort *start; + ushort cnt = 0; + ushort myx; + + /* console busy or not yet initialized */ + if (!printable || test_and_set_bit(0, &printing)) + return; + + pm_access(pm_con); + + if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) + currcons = kmsg_redirect - 1; + + vc = vt_cons->vc_cons[currcons]; + + /* read `x' only after setting currecons properly (otherwise + the `x' macro will read the x of the foreground console). */ + myx = x; + + if (!vc) { + /* impossible */ + /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */ + goto quit; + } + + if (vcmode != KD_TEXT) + goto quit; + + /* undraw cursor first */ + if (IS_VISIBLE) + hide_cursor(vc); + + start = (ushort *)pos; + + /* Contrived structure to try to emulate original need_wrap behaviour + * Problems caused when we have need_wrap set on '\n' character */ + while (count--) { + c = *b++; + if (c == 10 || c == 13 || c == 8 || need_wrap) { + if (cnt > 0) { + if (IS_VISIBLE) + sw->con_putcs(vc, start, cnt, y, x); + x += cnt; + if (need_wrap) + x--; + cnt = 0; + } + if (c == 8) { /* backspace */ + vte_bs(vc); + start = (ushort *)pos; + myx = x; + continue; } + if (c != 13) + vte_lf(vc); + vte_cr(vc); + start = (ushort *)pos; + myx = x; + if (c == 10 || c == 13) + continue; + } + scr_writew((attr << 8) + c, (unsigned short *) pos); + cnt++; + if (myx == video_num_columns - 1) { + need_wrap = 1; + continue; + } + pos+=2; + myx++; + } + if (cnt > 0) { + if (IS_VISIBLE) + sw->con_putcs(vc, start, cnt, y, x); + x += cnt; + if (x == video_num_columns) { + x--; + need_wrap = 1; } } + set_cursor(vc); + + if (!oops_in_progress) + poke_blanked_console(vc->display_fg); + +quit: + clear_bit(0, &printing); +} + +static kdev_t vt_console_device(struct console *c) +{ + return mk_kdev(TTY_MAJOR, c->index ? c->index : fg_console + 1); +} + +struct console vt_console_driver = { + name: "tty", + write: vt_console_print, + device: vt_console_device, + unblank: unblank_screen, + flags: CON_PRINTBUFFER, + index: -1, +}; +#endif + +/* + * Mapping and unmapping displays to a VT + */ +const char *vt_map_display(struct vt_struct *vt, int init) +{ + const char *display_desc = NULL; + struct vc_data *vc; + unsigned int currcons = 0; + + if (conswitchp) + display_desc = conswitchp->con_startup(); + + if (!display_desc) { + fg_console = 0; + return NULL; + } + + vt->vt_blanked = 0; + vt->blank_interval = 10*60*HZ; + vt->off_interval = 0; + init_timer(&vt->timer); + vt->timer.data = (long) vt; + vt->timer.function = blank_screen; + mod_timer(&vt->timer, jiffies + vt->blank_interval); + INIT_TQUEUE(&vt->vt_tq, vt_callback, vt); /* - * Wake anyone waiting for their VT to activate + * kmalloc is not running yet - we use the bootmem allocator. */ - vt_wake_waitactive(); - return; + for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { + vc = (struct vc_data *) + alloc_bootmem(sizeof(struct vc_data)); + cons_num = currcons; + vc->display_fg = vt_cons; + visual_init(vc, 1); + screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size); + kmalloced = 0; + vc_init(vc, currcons || !sw->con_save_screen); + } +#ifdef CONFIG_VT_CONSOLE + register_console(&vt_console_driver); +#endif + fg_console = 0; + vc = vt->want_vc = vt->last_console = vt->vc_cons[fg_console]; + set_origin(vc); + save_screen(vc); + gotoxy(vc, x, y); + vte_ed(vc, 0); + update_screen(vc); + return display_desc; } /* - * Performs the front-end of a vt switch + * This routine initializes console interrupts, and does nothing + * else. If you want the screen to clear, call tty_write with + * the appropriate escape-sequence. */ -void change_console(unsigned int new_console) + +struct tty_driver console_driver; +static int console_refcount; + +void __init vt_console_init(void) { - if ((new_console == fg_console) || (vt_dont_switch)) - return; - if (!vc_cons_allocated(new_console)) + const char *display_desc = NULL; + struct vc_data *vc; + + vt_cons = (struct vt_struct *) alloc_bootmem(sizeof(struct vt_struct)); + + display_desc = vt_map_display(vt_cons, 0); + + if (!display_desc) { + fg_console = 0; return; + } + vc = vt_cons->vc_cons[fg_console]; - /* - * If this vt is in process mode, then we need to handshake with - * that process before switching. Essentially, we store where that - * vt wants to switch to and wait for it to tell us when it's done - * (via VT_RELDISP ioctl). - * - * We also check to see if the controlling process still exists. - * If it doesn't, we reset this vt to auto mode and continue. - * This is a cheap way to track process control. The worst thing - * that can happen is: we send a signal to a process, it dies, and - * the switch gets "lost" waiting for a response; hopefully, the - * user will try again, we'll detect the process is gone (unless - * the user waits just the right amount of time :-) and revert the - * vt to auto control. - */ - if (vt_cons[fg_console]->vt_mode.mode == VT_PROCESS) - { - /* - * Send the signal as privileged - kill_proc() will - * tell us if the process has gone or something else - * is awry - */ - if (kill_proc(vt_cons[fg_console]->vt_pid, - vt_cons[fg_console]->vt_mode.relsig, - 1) == 0) - { - /* - * It worked. Mark the vt to switch to and - * return. The process needs to send us a - * VT_RELDISP ioctl to complete the switch. - */ - vt_cons[fg_console]->vt_newvt = new_console; - return; - } + printk("Console: %s %s %dx%d", + can_do_color ? "colour" : "mono", + display_desc, video_num_columns, video_num_lines); + printable = 1; + printk("\n"); +} - /* - * The controlling process has died, so we revert back to - * normal operation. In this case, we'll also change back - * to KD_TEXT mode. I'm not sure if this is strictly correct - * but it saves the agony when the X server dies and the screen - * remains blanked due to KD_GRAPHICS! It would be nice to do - * this outside of VT_PROCESS but there is no single process - * to account for and tracking tty count may be undesirable. - */ - reset_vc(fg_console); +int __init vty_init(void) +{ + memset(&console_driver, 0, sizeof(struct tty_driver)); + console_driver.magic = TTY_DRIVER_MAGIC; + console_driver.name = "vc/%d"; + console_driver.name_base = 1; + console_driver.major = TTY_MAJOR; + console_driver.minor_start = 1; + console_driver.num = MAX_NR_CONSOLES; + console_driver.type = TTY_DRIVER_TYPE_CONSOLE; + console_driver.init_termios = tty_std_termios; + console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; + console_driver.refcount = &console_refcount; + console_driver.table = console_table; + console_driver.termios = console_termios; + console_driver.termios_locked = console_termios_locked; +#ifdef CONFIG_VT_CONSOLE + console_driver.console = &vt_console_driver; +#endif + console_driver.open = con_open; + console_driver.close = con_close; + console_driver.write = con_write; + console_driver.write_room = con_write_room; + console_driver.put_char = con_put_char; + console_driver.flush_chars = con_flush_chars; + console_driver.chars_in_buffer = con_chars_in_buffer; + console_driver.ioctl = vt_ioctl; + console_driver.stop = con_stop; + console_driver.start = con_start; + console_driver.throttle = con_throttle; + console_driver.unthrottle = con_unthrottle; + + if (tty_register_driver(&console_driver)) + panic("Couldn't register console driver\n"); + + kbd_init(); + console_map_init(); + vcs_init(); + return 0; +} + +#ifndef VT_SINGLE_DRIVER + +static void clear_buffer_attributes(struct vc_data *vc) +{ + unsigned short *p = (unsigned short *) origin; + int count = screenbuf_size/2; + int mask = hi_font_mask | 0xff; + + for (; count > 0; count--, p++) { + scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p); + } +} - /* - * Fall through to normal (VT_AUTO) handling of the switch... +/* + * If we support more console drivers, this function is used + * when a driver wants to take over some existing consoles + * and become default driver for newly opened ones. + */ + +void take_over_console(const struct consw *csw, int first, int last, int deflt) +{ + struct vc_data *vc; + const char *desc; + int i, j = -1; + + desc = csw->con_startup(); + if (!desc) return; + if (deflt) + conswitchp = csw; + + for (i = first; i <= last; i++) { + int old_was_color; + + vc = vt_cons->vc_cons[i]; + con_driver_map[i] = csw; + + if (!vc || !sw) + continue; + + j = i; + if (IS_VISIBLE) + save_screen(vc); + old_was_color = can_do_color; + vc->display_fg->vt_sw->con_deinit(vc); + visual_init(vc, 0); + update_attr(vc); + + /* If the console changed between mono <-> color, then + * the attributes in the screenbuf will be wrong. The + * following resets all attributes to something sane. */ + if (old_was_color != can_do_color) + clear_buffer_attributes(vc); + + if (IS_VISIBLE) + update_screen(vc); } + printk("Console: switching "); + if (!deflt) + printk("consoles %d-%d ", first+1, last+1); + if (j >= 0) { + vc = vt_cons->vc_cons[j]; + printk("to %s %s %dx%d\n", can_do_color ? "colour" : "mono", + desc, video_num_columns, video_num_lines); + } else + printk("to %s\n", desc); +} - /* - * Ignore all switches in KD_GRAPHICS+VT_AUTO mode - */ - if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) - return; +void give_up_console(const struct consw *csw) +{ + int i; - complete_change_console(new_console); + for(i = 0; i < MAX_NR_CONSOLES; i++) + if (con_driver_map[i] == csw) + con_driver_map[i] = NULL; } +#endif + +/* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(color_table); +EXPORT_SYMBOL(default_red); +EXPORT_SYMBOL(default_grn); +EXPORT_SYMBOL(default_blu); +EXPORT_SYMBOL(video_font_height); +EXPORT_SYMBOL(video_scan_lines); +EXPORT_SYMBOL(vc_resize); +EXPORT_SYMBOL(fg_console); +EXPORT_SYMBOL(console_blank_hook); +#ifdef CONFIG_VT +EXPORT_SYMBOL(vt_cons); +#endif +#ifndef VT_SINGLE_DRIVER +EXPORT_SYMBOL(take_over_console); +EXPORT_SYMBOL(give_up_console); +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/vt_ioctl.c linux-2.5/drivers/char/vt_ioctl.c --- linux-2.5.5/drivers/char/vt_ioctl.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/char/vt_ioctl.c Sun Mar 3 23:50:42 2002 @@ -0,0 +1,1439 @@ +/* + * linux/drivers/char/vt_ioctl.c + * + * Copyright (C) 1992 obz under the linux copyright + * Copyright (C) 2001 James Simmons + * + * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 + * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 + * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 + * Some code moved for less code duplication - Andi Kleen - Mar 1997 + * Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_FB_COMPAT_XPMAC +#include +#endif /* CONFIG_FB_COMPAT_XPMAC */ + +char vt_dont_switch; +extern struct tty_driver console_driver; + +#define VT_IS_IN_USE(i) (console_driver.table[i] && console_driver.table[i]->count) +#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons) + +/* + * Console (vt and kd) routines, as defined by USL SVR4 manual, and by + * experimentation and study of X386 SYSV handling. + * + * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and + * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, + * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will + * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to + * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using + * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing + * to the current console is done by the main ioctl code. + */ + +struct vt_struct *vt_cons; + +/* Keyboard type: Default is KB_101, but can be set by machine + * specific code. + */ +unsigned char keyboard_type = KB_101; + +#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) +asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); +#endif + +unsigned int video_font_height; +unsigned int default_font_height; +unsigned int video_scan_lines; + +/* + * these are the valid i/o ports we're allowed to change. they map all the + * video ports + */ +#define GPFIRST 0x3b4 +#define GPLAST 0x3df +#define GPNUM (GPLAST - GPFIRST + 1) + +/* + * Generates sound of some frequency for some number of clock ticks + * + * If freq is 0, will turn off sound, else will turn it on for that time. + * If msec is 0, will return immediately, else will sleep for msec time, then + * turn sound off. + * + * We also return immediately, which is what was implied within the X + * comments - KDMKTONE doesn't put the process to sleep. + */ + +#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \ + || (defined(__mips__) && defined(CONFIG_ISA)) \ + || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) \ + || defined(__x86_64__) + +static void +kd_nosound(unsigned long ignored) +{ + /* disable counter 2 */ + outb(inb_p(0x61)&0xFC, 0x61); + return; +} + +void +_kd_mksound(unsigned int hz, unsigned int ticks) +{ + static struct timer_list sound_timer = { function: kd_nosound }; + unsigned int count = 0; + unsigned long flags; + + if (hz > 20 && hz < 32767) + count = 1193180 / hz; + + save_flags(flags); + cli(); + del_timer(&sound_timer); + if (count) { + /* enable counter 2 */ + outb_p(inb_p(0x61)|3, 0x61); + /* set command for counter 2, 2 byte write */ + outb_p(0xB6, 0x43); + /* select desired HZ */ + outb_p(count & 0xff, 0x42); + outb((count >> 8) & 0xff, 0x42); + + if (ticks) { + sound_timer.expires = jiffies+ticks; + add_timer(&sound_timer); + } + } else + kd_nosound(0); + restore_flags(flags); + return; +} + +#else + +void +_kd_mksound(unsigned int hz, unsigned int ticks) +{ +} + +#endif + +int _kbd_rate(struct kbd_repeat *rep) +{ + return -EINVAL; +} + +void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound; +int (*kbd_rate)(struct kbd_repeat *rep) = _kbd_rate; + +#define i (tmp.kb_index) +#define s (tmp.kb_table) +#define v (tmp.kb_value) +static inline int +do_kdsk_ioctl(int cmd, struct kbentry *user_kbe, int perm, struct kbd_struct *kbd) +{ + struct kbentry tmp; + ushort *key_map, val, ov; + + if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) + return -EFAULT; + if (i >= NR_KEYS || s >= MAX_NR_KEYMAPS) + return -EINVAL; + + switch (cmd) { + case KDGKBENT: + key_map = key_maps[s]; + if (key_map) { + val = U(key_map[i]); + if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) + val = K_HOLE; + } else + val = (i ? K_HOLE : K_NOSUCHMAP); + return put_user(val, &user_kbe->kb_value); + case KDSKBENT: + if (!perm) + return -EPERM; + if (!i && v == K_NOSUCHMAP) { + /* disallocate map */ + key_map = key_maps[s]; + if (s && key_map) { + key_maps[s] = 0; + if (key_map[0] == U(K_ALLOCATED)) { + kfree(key_map); + keymap_count--; + } + } + break; + } + + if (KTYP(v) < NR_TYPES) { + if (KVAL(v) > max_vals[KTYP(v)]) + return -EINVAL; + } else + if (kbd->kbdmode != VC_UNICODE) + return -EINVAL; + + /* ++Geert: non-PC keyboards may generate keycode zero */ +#if !defined(__mc68000__) && !defined(__powerpc__) + /* assignment to entry 0 only tests validity of args */ + if (!i) + break; +#endif + + if (!(key_map = key_maps[s])) { + int j; + + if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && + !capable(CAP_SYS_RESOURCE)) + return -EPERM; + + key_map = (ushort *) kmalloc(sizeof(plain_map), + GFP_KERNEL); + if (!key_map) + return -ENOMEM; + key_maps[s] = key_map; + key_map[0] = U(K_ALLOCATED); + for (j = 1; j < NR_KEYS; j++) + key_map[j] = U(K_HOLE); + keymap_count++; + } + ov = U(key_map[i]); + if (v == ov) + break; /* nothing to do */ + /* + * Attention Key. + */ + if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) + return -EPERM; + key_map[i] = U(v); + if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) + compute_shiftstate(); + break; + } + return 0; +} +#undef i +#undef s +#undef v + +static inline int +do_kbkeycode_ioctl(int cmd, struct kbkeycode *user_kbkc, int perm) +{ + struct kbkeycode tmp; + int kc = 0; + + if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) + return -EFAULT; + switch (cmd) { + case KDGETKEYCODE: + kc = getkeycode(tmp.scancode); + if (kc >= 0) + kc = put_user(kc, &user_kbkc->keycode); + break; + case KDSETKEYCODE: + if (!perm) + return -EPERM; + kc = setkeycode(tmp.scancode, tmp.keycode); + break; + } + return kc; +} + +static inline int +do_kdgkb_ioctl(int cmd, struct kbsentry *user_kdgkb, int perm) +{ + struct kbsentry tmp; + char *p; + u_char *q; + int sz; + int delta; + char *first_free, *fj, *fnw; + int i, j, k; + + /* we mostly copy too much here (512bytes), but who cares ;) */ + if (copy_from_user(&tmp, user_kdgkb, sizeof(struct kbsentry))) + return -EFAULT; + tmp.kb_string[sizeof(tmp.kb_string)-1] = '\0'; + if (tmp.kb_func >= MAX_NR_FUNC) + return -EINVAL; + i = tmp.kb_func; + + switch (cmd) { + case KDGKBSENT: + sz = sizeof(tmp.kb_string) - 1; /* sz should have been + a struct member */ + q = user_kdgkb->kb_string; + p = func_table[i]; + if(p) + for ( ; *p && sz; p++, sz--) + if (put_user(*p, q++)) + return -EFAULT; + if (put_user('\0', q)) + return -EFAULT; + return ((p && *p) ? -EOVERFLOW : 0); + case KDSKBSENT: + if (!perm) + return -EPERM; + + q = func_table[i]; + first_free = funcbufptr + (funcbufsize - funcbufleft); + for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) + ; + if (j < MAX_NR_FUNC) + fj = func_table[j]; + else + fj = first_free; + + delta = (q ? -strlen(q) : 1) + strlen(tmp.kb_string); + if (delta <= funcbufleft) { /* it fits in current buf */ + if (j < MAX_NR_FUNC) { + memmove(fj + delta, fj, first_free - fj); + for (k = j; k < MAX_NR_FUNC; k++) + if (func_table[k]) + func_table[k] += delta; + } + if (!q) + func_table[i] = fj; + funcbufleft -= delta; + } else { /* allocate a larger buffer */ + sz = 256; + while (sz < funcbufsize - funcbufleft + delta) + sz <<= 1; + fnw = (char *) kmalloc(sz, GFP_KERNEL); + if(!fnw) + return -ENOMEM; + + if (!q) + func_table[i] = fj; + if (fj > funcbufptr) + memmove(fnw, funcbufptr, fj - funcbufptr); + for (k = 0; k < j; k++) + if (func_table[k]) + func_table[k] = fnw + (func_table[k] - funcbufptr); + + if (first_free > fj) { + memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); + for (k = j; k < MAX_NR_FUNC; k++) + if (func_table[k]) + func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; + } + if (funcbufptr != func_buf) + kfree(funcbufptr); + funcbufptr = fnw; + funcbufleft = funcbufleft - delta + sz - funcbufsize; + funcbufsize = sz; + } + strcpy(func_table[i], tmp.kb_string); + break; + } + return 0; +} + +/* + * Font switching + * + * Currently we only support fonts up to 32 pixels wide, at a maximum height + * of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, + * depending on width) reserved for each character which is kinda wasty, but + * this is done in order to maintain compatibility with the EGA/VGA fonts. It + * is upto the actual low-level console-driver convert data into its favorite + * format (maybe we should add a `fontoffset' field to the `display' + * structure so we wont have to convert the fontdata all the time. + * /Jes + */ + +#define max_font_size 65536 + +int con_font_op(struct vc_data *vc, struct console_font_op *op) +{ + int rc = -EINVAL, size = max_font_size, set; + struct console_font_op old_op; + u8 *temp = NULL; + + if (vc->vc_mode != KD_TEXT) + goto quit; + memcpy(&old_op, op, sizeof(old_op)); + if (op->op == KD_FONT_OP_SET) { + if (!op->data) + return -EINVAL; + if (op->charcount > 512) + goto quit; + /* Need to guess font height [compact] */ + if (!op->height) { + u8 *charmap = op->data, tmp; + int h, i; + + /* + * If from KDFONTOP ioctl, don't allow things + * which can in userland, so that we can get + * rid of this soon + */ + if (!(op->flags & KD_FONT_FLAG_OLD)) + goto quit; + rc = -EFAULT; + for (h = 32; h > 0; h--) + for (i = 0; i < op->charcount; i++) { + if (get_user(tmp, &charmap[32*i+h-1])) + goto quit; + if (tmp) + goto nonzero; + } + rc = -EINVAL; + goto quit; + nonzero: + rc = -EINVAL; + op->height = h; + } + if (op->width > 32 || op->height > 32) + goto quit; + size = (op->width+7)/8 * 32 * op->charcount; + if (size > max_font_size) + return -ENOSPC; + set = 1; + } else if (op->op == KD_FONT_OP_GET) + set = 0; + else + return vc->display_fg->vt_sw->con_font_op(vc, op); + if (op->data) { + temp = kmalloc(size, GFP_KERNEL); + if (!temp) + return -ENOMEM; + if (set && copy_from_user(temp, op->data, size)) { + + rc = -EFAULT; + goto quit; + } + op->data = temp; + } + + acquire_console_sem(); + rc = vc->display_fg->vt_sw->con_font_op(vc, op); + release_console_sem(); + + op->data = old_op.data; + if (!rc && !set) { + int c = (op->width+7)/8 * 32 * op->charcount; + + if (op->data && op->charcount > old_op.charcount) + rc = -ENOSPC; + if (!(op->flags & KD_FONT_FLAG_OLD)) { + if (op->width > old_op.width || + op->height > old_op.height) + rc = -ENOSPC; + } else { + if (op->width != 8) + rc = -EIO; + else if ((old_op.height && op->height > old_op.height) || op->height > 32) + rc = -ENOSPC; + } + if (!rc && op->data && copy_to_user(op->data, temp, c)) + rc = -EFAULT; + } +quit: if (temp) + kfree(temp); + return rc; +} + +static inline int +do_fontx_ioctl(int cmd, struct consolefontdesc *user_cfd, int perm) +{ + struct vc_data *vc = vt_cons->vc_cons[fg_console]; + struct consolefontdesc cfdarg; + struct console_font_op op; + int i; + + if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) + return -EFAULT; + + switch (cmd) { + case PIO_FONTX: + if (!perm) + return -EPERM; + op.op = KD_FONT_OP_SET; + op.flags = KD_FONT_FLAG_OLD; + op.width = 8; + op.height = cfdarg.charheight; + op.charcount = cfdarg.charcount; + op.data = cfdarg.chardata; + return con_font_op(vc, &op); + case GIO_FONTX: { + op.op = KD_FONT_OP_GET; + op.flags = KD_FONT_FLAG_OLD; + op.width = 8; + op.height = cfdarg.charheight; + op.charcount = cfdarg.charcount; + op.data = cfdarg.chardata; + i = con_font_op(vc, &op); + if (i) + return i; + cfdarg.charheight = op.height; + cfdarg.charcount = op.charcount; + if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc))) + return -EFAULT; + return 0; + } + } + return -EINVAL; +} + +static inline int +do_unimap_ioctl(struct vc_data *vc, int cmd, struct unimapdesc *user_ud,int perm) +{ + struct unimapdesc tmp; + int i = 0; + + if (copy_from_user(&tmp, user_ud, sizeof tmp)) + return -EFAULT; + if (tmp.entries) { + i = verify_area(VERIFY_WRITE, tmp.entries, + tmp.entry_ct*sizeof(struct unipair)); + if (i) return i; + } + switch (cmd) { + case PIO_UNIMAP: + if (!perm) + return -EPERM; + return con_set_unimap(vc, tmp.entry_ct, tmp.entries); + case GIO_UNIMAP: + return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); + } + return 0; +} + +/* + * We handle the console-specific ioctl's here. We allow the + * capability to modify any console, not just the fg_console. + */ +int vt_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int i, perm; + unsigned int console; + unsigned char ucval; + struct vc_data *vc = (struct vc_data *) tty->driver_data; + struct kbd_struct *kbd; + + console = vc->vc_num; + + if (!vc) /* impossible? */ + return -ENOIOCTLCMD; + + /* + * To have permissions to do most of the vt ioctls, we either have + * to be the owner of the tty, or super-user. + */ + perm = 0; + if (current->tty == tty || suser()) + perm = 1; + + kbd = &vc->kbd_table; + switch (cmd) { + case KIOCSOUND: + if (!perm) + return -EPERM; + if (arg) + arg = 1193180 / arg; + kd_mksound(arg, 0); + return 0; + + case KDMKTONE: + if (!perm) + return -EPERM; + { + unsigned int ticks, count; + + /* + * Generate the tone for the appropriate number of ticks. + * If the time is zero, turn off sound ourselves. + */ + ticks = HZ * ((arg >> 16) & 0xffff) / 1000; + count = ticks ? (arg & 0xffff) : 0; + if (count) + count = 1193180 / count; + kd_mksound(count, ticks); + return 0; + } + + case KDGKBTYPE: + /* + * this is naive. + */ + ucval = keyboard_type; + goto setchar; + +#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) + /* + * These cannot be implemented on any machine that implements + * ioperm() in user level (such as Alpha PCs). + */ + case KDADDIO: + case KDDELIO: + /* + * KDADDIO and KDDELIO may be able to add ports beyond what + * we reject here, but to be safe... + */ + if (arg < GPFIRST || arg > GPLAST) + return -EINVAL; + return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; + + case KDENABIO: + case KDDISABIO: + return sys_ioperm(GPFIRST, GPNUM, + (cmd == KDENABIO)) ? -ENXIO : 0; +#endif + + /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */ + + case KDKBDREP: + { + struct kbd_repeat kbrep; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&kbrep, (void *)arg, + sizeof(struct kbd_repeat))) + return -EFAULT; + if ((i = kbd_rate( &kbrep ))) + return i; + if (copy_to_user((void *)arg, &kbrep, + sizeof(struct kbd_repeat))) + return -EFAULT; + return 0; + } + + case KDSETMODE: + /* + * currently, setting the mode from KD_TEXT to KD_GRAPHICS + * doesn't do a whole lot. i'm not sure if it should do any + * restoration of modes or what... + */ + if (!perm) + return -EPERM; + switch (arg) { + case KD_GRAPHICS: + break; + case KD_TEXT0: + case KD_TEXT1: + arg = KD_TEXT; + case KD_TEXT: + break; + default: + return -EINVAL; + } + if (vc->vc_mode == (unsigned char) arg) + return 0; + vc->vc_mode = (unsigned char) arg; + if (console != fg_console) + return 0; + /* + * explicitly blank/unblank the screen if switching modes + */ + if (arg == KD_TEXT) + unblank_screen(); + else + do_blank_screen(vc->display_fg, 1); + return 0; + + case KDGETMODE: + ucval = vc->vc_mode; + goto setint; + + case KDMAPDISP: + case KDUNMAPDISP: + /* + * these work like a combination of mmap and KDENABIO. + * this could be easily finished. + */ + return -EINVAL; + + case KDSKBMODE: + if (!perm) + return -EPERM; + switch(arg) { + case K_RAW: + kbd->kbdmode = VC_RAW; + break; + case K_MEDIUMRAW: + kbd->kbdmode = VC_MEDIUMRAW; + break; + case K_XLATE: + kbd->kbdmode = VC_XLATE; + compute_shiftstate(); + break; + case K_UNICODE: + kbd->kbdmode = VC_UNICODE; + compute_shiftstate(); + break; + default: + return -EINVAL; + } + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + return 0; + + case KDGKBMODE: + ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : + (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : + (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : + K_XLATE); + goto setint; + + /* this could be folded into KDSKBMODE, but for compatibility + reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ + case KDSKBMETA: + switch(arg) { + case K_METABIT: + clr_kbd_mode(kbd, VC_META); + break; + case K_ESCPREFIX: + set_kbd_mode(kbd, VC_META); + break; + default: + return -EINVAL; + } + return 0; + + case KDGKBMETA: + ucval = (get_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); + setint: + return put_user(ucval, (int *)arg); + + case KDGETKEYCODE: + case KDSETKEYCODE: + if(!capable(CAP_SYS_ADMIN)) + perm=0; + return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm); + + case KDGKBENT: + case KDSKBENT: + return do_kdsk_ioctl(cmd, (struct kbentry *)arg, perm, kbd); + + case KDGKBSENT: + case KDSKBSENT: + return do_kdgkb_ioctl(cmd, (struct kbsentry *)arg, perm); + + case KDGKBDIACR: + { + struct kbdiacrs *a = (struct kbdiacrs *)arg; + + if (put_user(accent_table_size, &a->kb_cnt)) + return -EFAULT; + if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr))) + return -EFAULT; + return 0; + } + + case KDSKBDIACR: + { + struct kbdiacrs *a = (struct kbdiacrs *)arg; + unsigned int ct; + + if (!perm) + return -EPERM; + if (get_user(ct,&a->kb_cnt)) + return -EFAULT; + if (ct >= MAX_DIACR) + return -EINVAL; + accent_table_size = ct; + if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr))) + return -EFAULT; + return 0; + } + + /* the ioctls below read/set the flags usually shown in the leds */ + /* don't use them - they will go away without warning */ + case KDGKBLED: + ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); + goto setchar; + + case KDSKBLED: + if (!perm) + return -EPERM; + if (arg & ~0x77) + return -EINVAL; + kbd->ledflagstate = (arg & 7); + kbd->default_ledflagstate = ((arg >> 4) & 7); + set_leds(); + return 0; + + /* the ioctls below only set the lights, not the functions */ + /* for those, see KDGKBLED and KDSKBLED above */ + case KDGETLED: + ucval = getledstate(); + setchar: + return put_user(ucval, (char*)arg); + + case KDSETLED: + if (!perm) + return -EPERM; + setledstate(kbd, arg); + return 0; + + /* + * A process can indicate its willingness to accept signals + * generated by pressing an appropriate key combination. + * Thus, one can have a daemon that e.g. spawns a new console + * upon a keypress and then changes to it. + * Probably init should be changed to do this (and have a + * field ks (`keyboard signal') in inittab describing the + * desired action), so that the number of background daemons + * does not increase. + */ + case KDSIGACCEPT: + { + extern int spawnpid, spawnsig; + if (!perm || !capable(CAP_KILL)) + return -EPERM; + if (arg < 1 || arg > _NSIG || arg == SIGKILL) + return -EINVAL; + spawnpid = current->pid; + spawnsig = arg; + return 0; + } + + case VT_SETMODE: + { + struct vt_mode tmp; + + if (!perm) + return -EPERM; + if (copy_from_user(&tmp, (void*)arg, sizeof(struct vt_mode))) + return -EFAULT; + if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) + return -EINVAL; + vc->vt_mode = tmp; + /* the frsig is ignored, so we set it to 0 */ + vc->vt_mode.frsig = 0; + vc->vt_pid = current->pid; + /* no switch is required -- saw@shade.msu.ru */ + vc->vt_newvt = -1; + return 0; + } + + case VT_GETMODE: + return copy_to_user((void*)arg, &(vc->vt_mode), + sizeof(struct vt_mode)) ? -EFAULT : 0; + + /* + * Returns global vt state. Note that VT 0 is always open, since + * it's an alias for the current VT, and people can't use it here. + * We cannot return state for more than 16 VTs, since v_state is short. + */ + case VT_GETSTATE: + { + struct vt_stat *vtstat = (struct vt_stat *)arg; + unsigned short state, mask; + + if (put_user(fg_console + 1, &vtstat->v_active)) + return -EFAULT; + state = 1; /* /dev/tty0 is always open */ + for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) + if (VT_IS_IN_USE(i)) + state |= mask; + return put_user(state, &vtstat->v_state); + } + + /* + * Returns the first available (non-opened) console. + */ + case VT_OPENQRY: + for (i = 0; i < MAX_NR_CONSOLES; ++i) + if (! VT_IS_IN_USE(i)) + break; + ucval = i < MAX_NR_CONSOLES ? (i+1) : -1; + goto setint; + + /* + * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, + * with num >= 1 (switches to vt 0, our console, are not allowed, just + * to preserve sanity). + */ + case VT_ACTIVATE: + if (!perm) + return -EPERM; + if (arg == 0 || arg > MAX_NR_CONSOLES) + return -ENXIO; + arg--; + i = vc_allocate(arg); + if (i) + return i; + set_console(arg); + return 0; + + /* + * wait until the specified VT has been activated + */ + case VT_WAITACTIVE: + if (!perm) + return -EPERM; + if (arg == 0 || arg > MAX_NR_CONSOLES) + return -ENXIO; + return vt_waitactive(arg-1); + + /* + * If a vt is under process control, the kernel will not switch to it + * immediately, but postpone the operation until the process calls this + * ioctl, allowing the switch to complete. + * + * According to the X sources this is the behavior: + * 0: pending switch-from not OK + * 1: pending switch-from OK + * 2: completed switch-to OK + */ + case VT_RELDISP: + if (!perm) + return -EPERM; + if (vc->vt_mode.mode != VT_PROCESS) + return -EINVAL; + + /* + * Switching-from response + */ + if (vc->vt_newvt >= 0) { + if (arg == 0) + /* + * Switch disallowed, so forget we were trying + * to do it. + */ + vc->vt_newvt = -1; + + else { + /* + * The current vt has been released, so + * complete the switch. + */ + struct vc_data *tmp; + + int newvt = vc->vt_newvt; + vc->vt_newvt = -1; + i = vc_allocate(newvt); + if (i) + return i; + + tmp = vc->display_fg->vc_cons[newvt]; + /* + * When we actually do the console switch, + * make sure we are atomic with respect to + * other console switches.. + */ + acquire_console_sem(); + complete_change_console(tmp, + vc->display_fg->vc_cons[fg_console]); + release_console_sem(); + } + } + + /* + * Switched-to response + */ + else + { + /* + * If it's just an ACK, ignore it + */ + if (arg != VT_ACKACQ) + return -EINVAL; + } + + return 0; + + /* + * Disallocate memory associated to VT (but leave VT1) + */ + case VT_DISALLOCATE: + if (arg > MAX_NR_CONSOLES) + return -ENXIO; + if (arg == 0) { + /* disallocate all unused consoles, but leave 0 */ + for (i=1; iv_rows) || + get_user(cc, &vtsizes->v_cols)) + return -EFAULT; + return vc_resize_all(ll, cc); + } + + case VT_RESIZEX: + { + struct vt_consize *vtconsize = (struct vt_consize *) arg; + ushort ll,cc,vlin,clin,vcol,ccol; + if (!perm) + return -EPERM; + if (verify_area(VERIFY_READ, (void *)vtconsize, + sizeof(struct vt_consize))) + return -EFAULT; + __get_user(ll, &vtconsize->v_rows); + __get_user(cc, &vtconsize->v_cols); + __get_user(vlin, &vtconsize->v_vlin); + __get_user(clin, &vtconsize->v_clin); + __get_user(vcol, &vtconsize->v_vcol); + __get_user(ccol, &vtconsize->v_ccol); + vlin = vlin ? vlin : video_scan_lines; + if ( clin ) + { + if ( ll ) + { + if ( ll != vlin/clin ) + return -EINVAL; /* Parameters don't add up */ + } + else + ll = vlin/clin; + } + if ( vcol && ccol ) + { + if ( cc ) + { + if ( cc != vcol/ccol ) + return -EINVAL; + } + else + cc = vcol/ccol; + } + + if ( clin > 32 ) + return -EINVAL; + + if ( vlin ) + video_scan_lines = vlin; + if ( clin ) + video_font_height = clin; + + return vc_resize_all(ll, cc); + } + + case PIO_FONT: { + struct console_font_op op; + if (!perm) + return -EPERM; + op.op = KD_FONT_OP_SET; + op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ + op.width = 8; + op.height = 0; + op.charcount = 256; + op.data = (char *) arg; + return con_font_op(vt_cons->vc_cons[fg_console], &op); + } + + case GIO_FONT: { + struct console_font_op op; + op.op = KD_FONT_OP_GET; + op.flags = KD_FONT_FLAG_OLD; + op.width = 8; + op.height = 32; + op.charcount = 256; + op.data = (char *) arg; + return con_font_op(vt_cons->vc_cons[fg_console], &op); + } + + case PIO_CMAP: + if (!perm) + return -EPERM; + return con_set_cmap((char *)arg); + + case GIO_CMAP: + return con_get_cmap((char *)arg); + + case PIO_FONTX: + case GIO_FONTX: + return do_fontx_ioctl(cmd, (struct consolefontdesc *)arg, perm); + + case PIO_FONTRESET: + { + if (!perm) + return -EPERM; + +#ifdef BROKEN_GRAPHICS_PROGRAMS + /* With BROKEN_GRAPHICS_PROGRAMS defined, the default + font is not saved. */ + return -ENOSYS; +#else + { + struct console_font_op op; + op.op = KD_FONT_OP_SET_DEFAULT; + op.data = NULL; + i = con_font_op(vt_cons->vc_cons[fg_console], &op); + if (i) return i; + con_set_default_unimap(vt_cons->vc_cons[fg_console]); + return 0; + } +#endif + } + + case KDFONTOP: { + struct console_font_op op; + if (copy_from_user(&op, (void *) arg, sizeof(op))) + return -EFAULT; + if (!perm && op.op != KD_FONT_OP_GET) + return -EPERM; + i = con_font_op(vc, &op); + if (i) return i; + if (copy_to_user((void *) arg, &op, sizeof(op))) + return -EFAULT; + return 0; + } + + case PIO_SCRNMAP: + if (!perm) + return -EPERM; + return con_set_trans_old((unsigned char *)arg); + + case GIO_SCRNMAP: + return con_get_trans_old((unsigned char *)arg); + + case PIO_UNISCRNMAP: + if (!perm) + return -EPERM; + return con_set_trans_new((unsigned short *)arg); + + case GIO_UNISCRNMAP: + return con_get_trans_new((unsigned short *)arg); + + case PIO_UNIMAPCLR: + { struct unimapinit ui; + if (!perm) + return -EPERM; + i = copy_from_user(&ui, (void *)arg, sizeof(struct unimapinit)); + if (i) return -EFAULT; + con_clear_unimap(vt_cons->vc_cons[fg_console], &ui); + return 0; + } + + case PIO_UNIMAP: + case GIO_UNIMAP: + return do_unimap_ioctl(vc, cmd, (struct unimapdesc *)arg, perm); + + case VT_LOCKSWITCH: + if (!suser()) + return -EPERM; + vt_dont_switch = 1; + return 0; + case VT_UNLOCKSWITCH: + if (!suser()) + return -EPERM; + vt_dont_switch = 0; + return 0; +#ifdef CONFIG_FB_COMPAT_XPMAC + case VC_GETMODE: + { + struct vc_mode mode; + + i = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct vc_mode)); + if (i == 0) + i = console_getmode(&mode); + if (i) + return i; + if (copy_to_user((void *) arg, &mode, sizeof(mode))) + return -EFAULT; + return 0; + } + case VC_SETMODE: + case VC_INQMODE: + { + struct vc_mode mode; + + if (!perm) + return -EPERM; + if (copy_from_user(&mode, (void *) arg, sizeof(mode))) + return -EFAULT; + return console_setmode(&mode, cmd == VC_SETMODE); + } + case VC_SETCMAP: + { + unsigned char cmap[3][256], *p; + int n_entries, cmap_size, i, j; + + if (!perm) + return -EPERM; + if (arg == (unsigned long) VC_POWERMODE_INQUIRY + || arg <= VESA_POWERDOWN) { + /* compatibility hack: VC_POWERMODE + was changed from 0x766a to 0x766c */ + return console_powermode((int) arg); + } + if (get_user(cmap_size, (int *) arg)) + return -EFAULT; + if (cmap_size % 3) + return -EINVAL; + n_entries = cmap_size / 3; + if ((unsigned) n_entries > 256) + return -EINVAL; + p = (unsigned char *) (arg + sizeof(int)); + for (j = 0; j < n_entries; ++j) + for (i = 0; i < 3; ++i) + if (get_user(cmap[i][j], p++)) + return -EFAULT; + return console_setcmap(n_entries, cmap[0], + cmap[1], cmap[2]); + } + case VC_GETCMAP: + /* not implemented yet */ + return -ENOIOCTLCMD; + case VC_POWERMODE: + if (!perm) + return -EPERM; + return console_powermode((int) arg); +#endif /* CONFIG_FB_COMPAT_XPMAC */ + default: + return -ENOIOCTLCMD; + } +} + +/* + * Sometimes we want to wait until a particular VT has been activated. We + * do it in a very simple manner. Everybody waits on a single queue and + * get woken up at once. Those that are satisfied go on with their business, + * while those not ready go back to sleep. Seems overkill to add a wait + * to each vt just for this - usually this does nothing! + */ +static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue); + +/* + * Sleeps until a vt is activated, or the task is interrupted. Returns + * 0 if activation, -EINTR if interrupted. + */ +int vt_waitactive(int vt) +{ + int retval; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&vt_activate_queue, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + retval = 0; + if (vt == fg_console) + break; + retval = -EINTR; + if (signal_pending(current)) + break; + schedule(); + } + remove_wait_queue(&vt_activate_queue, &wait); + current->state = TASK_RUNNING; + return retval; +} + +#define vt_wake_waitactive() wake_up(&vt_activate_queue) + +void reset_vc(struct vc_data *vc) +{ + vc->vc_mode = KD_TEXT; + vc->kbd_table.kbdmode = VC_XLATE; + vc->vt_mode.mode = VT_AUTO; + vc->vt_mode.waitv = 0; + vc->vt_mode.relsig = 0; + vc->vt_mode.acqsig = 0; + vc->vt_mode.frsig = 0; + vc->vt_pid = -1; + vc->vt_newvt = -1; + if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ + reset_palette(vc); +} + +inline void switch_screen(struct vc_data *new_vc, struct vc_data *old_vc) +{ + struct vt_struct *vt = new_vc->display_fg; + + if (!new_vc) + return; + + hide_cursor(old_vc); + if (old_vc->vc_num != new_vc->vc_num) { + int update; + + fg_console = new_vc->vc_num; + save_screen(old_vc); + set_origin(old_vc); + + set_origin(new_vc); + update = vt->vt_sw->con_switch(new_vc); + set_palette(new_vc); + if (update && new_vc->vc_mode != KD_GRAPHICS) + do_update_region(new_vc, new_vc->vc_origin, + new_vc->vc_screenbuf_size/2); + } + set_cursor(new_vc); + set_leds(); + compute_shiftstate(); +} + +/* + * Performs the front-end of a vt switch + */ +void change_console(struct vc_data *new_vc, struct vc_data *old_vc) +{ + /* + * If this vt is in process mode, then we need to handshake with + * that process before switching. Essentially, we store where that + * vt wants to switch to and wait for it to tell us when it's done + * (via VT_RELDISP ioctl). + * + * We also check to see if the controlling process still exists. + * If it doesn't, we reset this vt to auto mode and continue. + * This is a cheap way to track process control. The worst thing + * that can happen is: we send a signal to a process, it dies, and + * the switch gets "lost" waiting for a response; hopefully, the + * user will try again, we'll detect the process is gone (unless + * the user waits just the right amount of time :-) and revert the + * vt to auto control. + */ + if (old_vc->vt_mode.mode == VT_PROCESS) { + /* + * Send the signal as privileged - kill_proc() will + * tell us if the process has gone or something else + * is awry + */ + if (kill_proc(old_vc->vt_pid, old_vc->vt_mode.relsig,1) == 0) { + /* + * It worked. Mark the vt to switch to and + * return. The process needs to send us a + * VT_RELDISP ioctl to complete the switch. + */ + old_vc->vt_newvt = new_vc->vc_num; + return; + } + + /* + * The controlling process has died, so we revert back to + * normal operation. In this case, we'll also change back + * to KD_TEXT mode. I'm not sure if this is strictly correct + * but it saves the agony when the X server dies and the screen + * remains blanked due to KD_GRAPHICS! It would be nice to do + * this outside of VT_PROCESS but there is no single process + * to account for and tracking tty count may be undesirable. + */ + reset_vc(old_vc); + + /* + * Fall through to normal (VT_AUTO) handling of the switch... + */ + } + + /* + * Ignore all switches in KD_GRAPHICS+VT_AUTO mode + */ + if (old_vc->vc_mode == KD_GRAPHICS) + return; + + complete_change_console(new_vc, old_vc); +} + +/* + * Performs the back end of a vt switch + */ +void complete_change_console(struct vc_data *new_vc, struct vc_data *old_vc) +{ + unsigned char old_vc_mode; + + new_vc->display_fg->last_console = old_vc; + + /* + * If we're switching, we could be going from KD_GRAPHICS to + * KD_TEXT mode or vice versa, which means we need to blank or + * unblank the screen later. + */ + old_vc_mode = old_vc->vc_mode; + switch_screen(new_vc, old_vc); + + /* + * This can't appear below a successful kill_proc(). If it did, + * then the *blank_screen operation could occur while X, having + * received acqsig, is waking up on another processor. This + * condition can lead to overlapping accesses to the VGA range + * and the framebuffer (causing system lockups). + * + * To account for this we duplicate this code below only if the + * controlling process is gone and we've called reset_vc. + */ + if (old_vc_mode != new_vc->vc_mode) { + if (new_vc->vc_mode == KD_TEXT) + unblank_screen(); + else + do_blank_screen(new_vc->display_fg, 1); + } + + /* + * If this new console is under process control, send it a signal + * telling it that it has acquired. Also check if it has died and + * clean up (similar to logic employed in change_console()) + */ + if (new_vc->vt_mode.mode == VT_PROCESS) { + /* + * Send the signal as privileged - kill_proc() will + * tell us if the process has gone or something else + * is awry + */ + if (kill_proc(new_vc->vt_pid, new_vc->vt_mode.acqsig,1) != 0) { + /* + * The controlling process has died, so we revert back + * to normal operation. In this case, we'll also change + * back to KD_TEXT mode. I'm not sure if this is + * strictly correct but it saves the agony when the X + * server dies and the screen remains blanked due to + * KD_GRAPHICS! It would be nice to do this outside of + * VT_PROCESS but there is no single process to account + * for and tracking tty count may be undesirable. + */ + reset_vc(new_vc); + + if (old_vc_mode != new_vc->vc_mode) + { + if (new_vc->vc_mode == KD_TEXT) + unblank_screen(); + else + do_blank_screen(new_vc->display_fg, 1); + } + } + } + + /* + * Wake anyone waiting for their VT to activate + */ + vt_wake_waitactive(); + return; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/wdt.c linux-2.5/drivers/char/wdt.c --- linux-2.5.5/drivers/char/wdt.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/char/wdt.c Sun Jan 13 22:15:01 2002 @@ -15,7 +15,7 @@ * * (c) Copyright 1995 Alan Cox * - * Release 0.08. + * Release 0.09. * * Fixes * Dave Gregorich : Modularisation and minor bugs @@ -27,6 +27,7 @@ * Tim Hockin : Added insmod parameters, comment cleanup * Parameterized timeout * Tigran Aivazian : Restructured wdt_init() to handle failures + * Matt Domsch : added nowayout and timeout module options */ #include @@ -62,6 +63,26 @@ #define WD_TIMO (100*60) /* 1 minute */ +static int timeout_val = WD_TIMO; /* value passed to card */ +static int timeout = 60; /* in seconds */ +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +static void __init +wdt_validate_timeout(void) +{ + timeout_val = timeout * 100; +} + #ifndef MODULE /** @@ -216,7 +237,7 @@ /* Write a watchdog value */ inb_p(WDT_DC); wdt_ctr_mode(1,2); - wdt_ctr_load(1,WD_TIMO); /* Timeout */ + wdt_ctr_load(1,timeout_val); /* Timeout */ outb_p(0, WDT_DC); } @@ -339,6 +360,9 @@ case WATCHDOG_MINOR: if(test_and_set_bit(0, &wdt_is_open)) return -EBUSY; + if (nowayout) { + MOD_INC_USE_COUNT; + } /* * Activate */ @@ -348,7 +372,7 @@ wdt_ctr_mode(1,2); wdt_ctr_mode(2,0); wdt_ctr_load(0, 8948); /* count at 100Hz */ - wdt_ctr_load(1,WD_TIMO); /* Timeout 120 seconds */ + wdt_ctr_load(1,timeout_val); /* Timeout */ wdt_ctr_load(2,65535); outb_p(0, WDT_DC); /* Enable */ return 0; @@ -375,10 +399,10 @@ { if(minor(inode->i_rdev)==WATCHDOG_MINOR) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - inb_p(WDT_DC); /* Disable counters */ - wdt_ctr_load(2,0); /* 0 length reset pulses now */ -#endif + if (!nowayout) { + inb_p(WDT_DC); /* Disable counters */ + wdt_ctr_load(2,0); /* 0 length reset pulses now */ + } clear_bit(0, &wdt_is_open); } return 0; @@ -484,6 +508,7 @@ { int ret; + wdt_validate_timeout(); ret = misc_register(&wdt_miscdev); if (ret) { printk(KERN_ERR "wdt: can't misc_register on minor=%d\n", WATCHDOG_MINOR); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/wdt977.c linux-2.5/drivers/char/wdt977.c --- linux-2.5.5/drivers/char/wdt977.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/char/wdt977.c Sun Jan 13 22:15:01 2002 @@ -1,5 +1,5 @@ /* - * Wdt977 0.01: A Watchdog Device for Netwinder W83977AF chip + * Wdt977 0.02: A Watchdog Device for Netwinder W83977AF chip * * (c) Copyright 1998 Rebel.com (Woody Suwalski ) * @@ -11,8 +11,13 @@ * 2 of the License, or (at your option) any later version. * * ----------------------- + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * 19-Dec-2001 Woody Suwalski: Netwinder fixes, ioctl interface + * 06-Jan-2002 Woody Suwalski: For compatibility, convert all timeouts + * from minutes to seconds. */ - + #include #include #include @@ -21,56 +26,123 @@ #include #include #include +#include #include #include #include +#include #define WATCHDOG_MINOR 130 -static int timeout = 3; +#define DEFAULT_TIMEOUT 1 /* default timeout = 1 minute */ + +static int timeout = DEFAULT_TIMEOUT*60; /* TO in seconds from user */ +static int timeoutM = DEFAULT_TIMEOUT; /* timeout in minutes */ static int timer_alive; static int testmode; +MODULE_PARM(timeout, "i"); +MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=60"); +MODULE_PARM(testmode, "i"); +MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + + +/* This is kicking the watchdog by simply re-writing the timeout to reg. 0xF2 */ +int kick_wdog(void) +{ + /* + * Refresh the timer. + */ + + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and kicks watchdog reg F2 */ + /* F2 has the timeout in minutes */ + + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(timeoutM,0x371); + + /* lock the SuperIO chip */ + outb(0xAA,0x370); + + return 0; +} + + /* * Allow only one person to hold it open */ - + static int wdt977_open(struct inode *inode, struct file *file) { + if(timer_alive) return -EBUSY; -#ifdef CONFIG_WATCHDOG_NOWAYOUT - MOD_INC_USE_COUNT; -#endif + + /* convert seconds to minutes, rounding up */ + timeoutM = timeout + 59; + timeoutM /= 60; + + if (nowayout) + { + MOD_INC_USE_COUNT; + + /* do not permit disabling the watchdog by writing 0 to reg. 0xF2 */ + if (!timeoutM) timeoutM = DEFAULT_TIMEOUT; + } timer_alive++; - //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. - if (timeout>255) - timeout = 255; - - printk(KERN_INFO "Watchdog: active, current timeout %d min.\n",timeout); - - // unlock the SuperIO chip - outb(0x87,0x370); - outb(0x87,0x370); - - //select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 - //F2 has the timeout in minutes - //F3 could be set to the POWER LED blink (with GP17 set to PowerLed) - // at timeout, and to reset timer on kbd/mouse activity (not now) - //F4 is used to just clear the TIMEOUT'ed state (bit 0) - + if (machine_is_netwinder()) + { + /* we have a hw bug somewhere, so each 977 minute is actually only 30sec + * this limits the max timeout to half of device max of 255 minutes... + */ + timeoutM += timeoutM; + } + + /* max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. */ + if (timeoutM > 255) timeoutM = 255; + + /* convert seconds to minutes */ + printk(KERN_INFO "Wdt977 Watchdog activated: timeout = %d sec, nowayout = %i, testmode = %i.\n", + machine_is_netwinder() ? (timeoutM>>1)*60 : timeoutM*60, + nowayout, testmode); + + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 + * F2 has the timeout in minutes + * F3 could be set to the POWER LED blink (with GP17 set to PowerLed) + * at timeout, and to reset timer on kbd/mouse activity (not impl.) + * F4 is used to just clear the TIMEOUT'ed state (bit 0) + */ outb(0x07,0x370); outb(0x08,0x371); outb(0xF2,0x370); - outb(timeout,0x371); + outb(timeoutM,0x371); outb(0xF3,0x370); - outb(0x00,0x371); //another setting is 0E for kbd/mouse/LED + outb(0x00,0x371); /* another setting is 0E for kbd/mouse/LED */ outb(0xF4,0x370); outb(0x00,0x371); - - //at last select device Aux1 (dev=7) and set GP16 as a watchdog output + + /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ + /* in test mode watch the bit 1 on F4 to indicate "triggered" */ if (!testmode) { outb(0x07,0x370); @@ -78,9 +150,9 @@ outb(0xE6,0x370); outb(0x08,0x371); } - - // lock the SuperIO chip - outb(0xAA,0x370); + + /* lock the SuperIO chip */ + outb(0xAA,0x370); return 0; } @@ -89,84 +161,163 @@ { /* * Shut off the timer. - * Lock it in if it's a module and we defined ...NOWAYOUT + * Lock it in if it's a module and we set nowayout */ -#ifndef CONFIG_WATCHDOG_NOWAYOUT + if (!nowayout) + { + lock_kernel(); - // unlock the SuperIO chip - outb(0x87,0x370); - outb(0x87,0x370); - - //select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 - //F3 is reset to its default state - //F4 can clear the TIMEOUT'ed state (bit 0) - back to default - //We can not use GP17 as a PowerLed, as we use its usage as a RedLed - - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(0xFF,0x371); - outb(0xF3,0x370); - outb(0x00,0x371); - outb(0xF4,0x370); - outb(0x00,0x371); - outb(0xF2,0x370); - outb(0x00,0x371); - - //at last select device Aux1 (dev=7) and set GP16 as a watchdog output - outb(0x07,0x370); - outb(0x07,0x371); - outb(0xE6,0x370); - outb(0x08,0x371); - - // lock the SuperIO chip - outb(0xAA,0x370); + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 + * F3 is reset to its default state + * F4 can clear the TIMEOUT'ed state (bit 0) - back to default + * We can not use GP17 as a PowerLed, as we use its usage as a RedLed + */ + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(0xFF,0x371); + outb(0xF3,0x370); + outb(0x00,0x371); + outb(0xF4,0x370); + outb(0x00,0x371); + outb(0xF2,0x370); + outb(0x00,0x371); - timer_alive=0; + /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ + outb(0x07,0x370); + outb(0x07,0x371); + outb(0xE6,0x370); + outb(0x08,0x371); - printk(KERN_INFO "Watchdog: shutdown.\n"); -#endif + /* lock the SuperIO chip */ + outb(0xAA,0x370); + + timer_alive=0; + unlock_kernel(); + + printk(KERN_INFO "Wdt977 Watchdog: shutdown\n"); + } return 0; } -static ssize_t wdt977_write(struct file *file, const char *data, size_t len, loff_t *ppos) + +/* + * wdt977_write: + * @file: file handle to the watchdog + * @buf: buffer to write (unused as data does not matter here + * @count: count of bytes + * @ppos: pointer to the position to write. No seeks allowed + * + * A write to a watchdog device is defined as a keepalive signal. Any + * write of data will do, as we we don't define content meaning. + */ + +static ssize_t wdt977_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; - //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. - if (timeout>255) - timeout = 255; + if(count) + { + kick_wdog(); + return 1; + } + return 0; +} - /* - * Refresh the timer. - */ - - //we have a hw bug somewhere, so each 977 minute is actually only 30sec - //as such limit the max timeout to half of max of 255 minutes... -// if (timeout>126) -// timeout = 126; - - // unlock the SuperIO chip - outb(0x87,0x370); - outb(0x87,0x370); - - //select device Aux2 (device=8) and kicks watchdog reg F2 - //F2 has the timeout in minutes - - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(timeout,0x371); - - // lock the SuperIO chip - outb(0xAA,0x370); - - return 1; +/* + * wdt977_ioctl: + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + * The watchdog API defines a common set of functions for all watchdogs + * according to their available features. + */ + +static int wdt977_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ +static struct watchdog_info ident = { + identity : "Winbond 83977" +}; + +int temp; + + switch(cmd) + { + default: + return -ENOTTY; + + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, + sizeof(ident)) ? -EFAULT : 0; + + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *) arg); + + case WDIOC_GETSTATUS: + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and read watchdog reg F4 */ + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF4,0x370); + temp = inb(0x371); + + /* lock the SuperIO chip */ + outb(0xAA,0x370); + + /* return info if "expired" in test mode */ + return put_user(temp & 1, (int *) arg); + + case WDIOC_KEEPALIVE: + kick_wdog(); + return 0; + + case WDIOC_SETTIMEOUT: + if (copy_from_user(&temp, (int *) arg, sizeof(int))) + return -EFAULT; + + /* convert seconds to minutes, rounding up */ + temp += 59; + temp /= 60; + + /* we have a hw bug somewhere, so each 977 minute is actually only 30sec + * this limits the max timeout to half of device max of 255 minutes... + */ + if (machine_is_netwinder()) + { + temp += temp; + } + + /* Sanity check */ + if (temp < 0 || temp > 255) + return -EINVAL; + + if (!temp && nowayout) + return -EINVAL; + + timeoutM = temp; + kick_wdog(); + return 0; + } } + static struct file_operations wdt977_fops= { owner: THIS_MODULE, write: wdt977_write, + ioctl: wdt977_ioctl, open: wdt977_open, release: wdt977_release, }; @@ -184,9 +335,9 @@ return -ENODEV; misc_register(&wdt977_miscdev); - printk(KERN_INFO "NetWinder Watchdog sleeping.\n"); + printk(KERN_INFO "Wdt977 Watchdog sleeping.\n"); return 0; -} +} static void __exit nwwatchdog_exit(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/char/wdt_pci.c linux-2.5/drivers/char/wdt_pci.c --- linux-2.5.5/drivers/char/wdt_pci.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/char/wdt_pci.c Sun Jan 13 22:15:01 2002 @@ -15,7 +15,7 @@ * * (c) Copyright 1995 Alan Cox * - * Release 0.08. + * Release 0.09. * * Fixes * Dave Gregorich : Modularisation and minor bugs @@ -30,6 +30,7 @@ * Alan Cox : Split ISA and PCI cards into two drivers * Jeff Garzik : PCI cleanups * Tigran Aivazian : Restructured wdtpci_init_one() to handle failures + * Matt Domsch : added nowayout and timeout module options */ #include @@ -83,6 +84,26 @@ #define WD_TIMO (100*60) /* 1 minute */ +static int timeout_val = WD_TIMO; /* value passed to card */ +static int timeout = 60; /* in seconds */ +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +static void __init +wdtpci_validate_timeout(void) +{ + timeout_val = timeout * 100; +} + #ifndef MODULE /** @@ -232,7 +253,7 @@ /* Write a watchdog value */ inb_p(WDT_DC); wdtpci_ctr_mode(1,2); - wdtpci_ctr_load(1,WD_TIMO); /* Timeout */ + wdtpci_ctr_load(1,timeout_val); /* Timeout */ outb_p(0, WDT_DC); } @@ -357,9 +378,9 @@ { return -EBUSY; } -#ifdef CONFIG_WATCHDOG_NOWAYOUT - MOD_INC_USE_COUNT; -#endif + if (nowayout) { + MOD_INC_USE_COUNT; + } /* * Activate */ @@ -385,7 +406,7 @@ wdtpci_ctr_mode(1,2); wdtpci_ctr_mode(2,1); wdtpci_ctr_load(0,20833); /* count at 100Hz */ - wdtpci_ctr_load(1,WD_TIMO);/* Timeout 60 seconds */ + wdtpci_ctr_load(1,timeout_val); /* Timeout */ /* DO NOT LOAD CTR2 on PCI card! -- JPN */ outb_p(0, WDT_DC); /* Enable */ return 0; @@ -412,10 +433,10 @@ { if(minor(inode->i_rdev)==WATCHDOG_MINOR) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - inb_p(WDT_DC); /* Disable counters */ - wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ -#endif + if (!nowayout) { + inb_p(WDT_DC); /* Disable counters */ + wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ + } clear_bit(0, &wdt_is_open ); } return 0; @@ -558,7 +579,7 @@ } -static void __exit wdtpci_remove_one (struct pci_dev *pdev) +static void __devexit wdtpci_remove_one (struct pci_dev *pdev) { /* here we assume only one device will ever have * been picked up and registered by probe function */ @@ -583,7 +604,7 @@ name: "wdt-pci", id_table: wdtpci_pci_tbl, probe: wdtpci_init_one, - remove: wdtpci_remove_one, + remove: __devexit_p(wdtpci_remove_one), }; @@ -617,6 +638,8 @@ if (rc < 1) return -ENODEV; + + wdtpci_validate_timeout(); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/Config.help linux-2.5/drivers/hotplug/Config.help --- linux-2.5.5/drivers/hotplug/Config.help Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/hotplug/Config.help Fri Mar 1 15:07:37 2002 @@ -29,3 +29,14 @@ When in doubt, say N. +CONFIG_HOTPLUG_PCI_IBM + Say Y here if you have a motherboard with a IBM PCI Hotplug + controller. + + 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 cpqphp.o. If you want to compile it + as a module, say M here and read . + + When in doubt, say N. + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/Config.in linux-2.5/drivers/hotplug/Config.in --- linux-2.5.5/drivers/hotplug/Config.in Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/hotplug/Config.in Fri Mar 1 19:09:58 2002 @@ -4,9 +4,11 @@ mainmenu_option next_comment comment 'PCI Hotplug Support' -dep_tristate 'Support for PCI Hotplug (EXPERIMENTAL)' CONFIG_HOTPLUG_PCI $CONFIG_DDFS $CONFIG_EXPERIMENTAL +dep_tristate 'Support for PCI Hotplug (EXPERIMENTAL)' CONFIG_HOTPLUG_PCI $CONFIG_PCI $CONFIG_EXPERIMENTAL -dep_tristate ' Compaq PCI Hotplug driver' CONFIG_HOTPLUG_PCI_COMPAQ $CONFIG_HOTPLUG_PCI +dep_tristate ' Compaq PCI Hotplug driver' CONFIG_HOTPLUG_PCI_COMPAQ $CONFIG_HOTPLUG_PCI $CONFIG_X86 dep_mbool ' Save configuration into NVRAM on Compaq servers' CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM $CONFIG_HOTPLUG_PCI_COMPAQ +dep_tristate ' IBM PCI Hotplug driver' CONFIG_HOTPLUG_PCI_IBM $CONFIG_HOTPLUG_PCI $CONFIG_X86_IO_APIC $CONFIG_X86 +dep_tristate ' ACPI PCI Hotplug driver' CONFIG_HOTPLUG_PCI_ACPI $CONFIG_ACPI $CONFIG_HOTPLUG_PCI endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/Makefile linux-2.5/drivers/hotplug/Makefile --- linux-2.5.5/drivers/hotplug/Makefile Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/hotplug/Makefile Sun Mar 3 17:54:35 2002 @@ -4,12 +4,14 @@ O_TARGET := vmlinux-obj.o -list-multi := cpqphp.o pci_hotplug.o +list-multi := cpqphp.o pci_hotplug.o ibmphp.o pcihpacpi.o export-objs := pci_hotplug_core.o pci_hotplug_util.o obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o +obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o +obj-$(CONFIG_HOTPLUG_PCI_ACPI) += pcihpacpi.o pci_hotplug-objs := pci_hotplug_core.o \ pci_hotplug_util.o @@ -19,6 +21,28 @@ cpqphp_proc.o \ cpqphp_pci.o +ibmphp-objs := ibmphp_core.o \ + ibmphp_ebda.o \ + ibmphp_pci.o \ + ibmphp_res.o \ + ibmphp_hpc.o + +ibmphp-objs := ibmphp_core.o \ + ibmphp_ebda.o \ + ibmphp_pci.o \ + ibmphp_res.o \ + ibmphp_hpc.o + +ifdef CONFIG_HOTPLUG_PCI_ACPI + EXTRA_CFLAGS += -D_LINUX -I$(CURDIR)/../acpi + ifdef CONFIG_ACPI_DEBUG + EXTRA_CFLAGS += -DACPI_DEBUG -Wno-unused + endif +endif + +pcihp_acpi_objs := pcihp_acpi.o \ + pcihp_acpi_glue.o + ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y) cpqphp-objs += cpqphp_nvram.o endif @@ -32,3 +56,11 @@ cpqphp.o: $(cpqphp-objs) $(LD) -r -o $@ $(cpqphp-objs) +ibmphp.o: $(ibmphp-objs) + $(LD) -r -o $@ $(ibmphp-objs) + +ibmphp.o: $(ibmphp-objs) + $(LD) -r -o $@ $(ibmphp-objs) + +pcihpacpi.o: $(pcihp_acpi_objs) + $(LD) -r -o $@ $(pcihp_acpi_objs) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/cpqphp_ctrl.c linux-2.5/drivers/hotplug/cpqphp_ctrl.c --- linux-2.5.5/drivers/hotplug/cpqphp_ctrl.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/hotplug/cpqphp_ctrl.c Sun Mar 3 17:54:35 2002 @@ -1707,6 +1707,7 @@ struct controller *ctrl; lock_kernel(); daemonize(); + reparent_to_init(); // New name strcpy(current->comm, "phpd_event"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/cpqphp_proc.c linux-2.5/drivers/hotplug/cpqphp_proc.c --- linux-2.5.5/drivers/hotplug/cpqphp_proc.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/hotplug/cpqphp_proc.c Fri Mar 1 15:07:37 2002 @@ -177,7 +177,7 @@ int cpqhp_proc_init_ctrl (void) { - ctrl_proc_root = proc_mkdir("driver/hpc", NULL); + ctrl_proc_root = proc_mkdir("hpc", proc_root_driver); if (!ctrl_proc_root) return -ENOMEM; ctrl_proc_root->owner = THIS_MODULE; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/ibmphp.h linux-2.5/drivers/hotplug/ibmphp.h --- linux-2.5.5/drivers/hotplug/ibmphp.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/hotplug/ibmphp.h Fri Mar 1 15:07:37 2002 @@ -0,0 +1,745 @@ +#ifndef __IBMPHP_H +#define __IBMPHP_H + +/* + * IBM Hot Plug Controller Driver + * + * Written By: Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include "pci_hotplug.h" + +extern int ibmphp_debug; + +#if !defined(CONFIG_HOTPLUG_PCI_IBM_MODULE) + #define MY_NAME "ibmphpd" +#else + #define MY_NAME THIS_MODULE->name +#endif +#define debug(fmt, arg...) do { if (ibmphp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + +/* EBDA stuff */ + +/*********************************************************** +* SLOT CAPABILITY * +***********************************************************/ + +#define EBDA_SLOT_133_MAX 0x20 +#define EBDA_SLOT_100_MAX 0x10 +#define EBDA_SLOT_66_MAX 0x02 +#define EBDA_SLOT_PCIX_CAP 0x08 + + +/************************************************************ +* RESOURE TYPE * +************************************************************/ + +#define EBDA_RSRC_TYPE_MASK 0x03 +#define EBDA_IO_RSRC_TYPE 0x00 +#define EBDA_MEM_RSRC_TYPE 0x01 +#define EBDA_PFM_RSRC_TYPE 0x03 +#define EBDA_RES_RSRC_TYPE 0x02 + + +/************************************************************* +* IO RESTRICTION TYPE * +*************************************************************/ + +#define EBDA_IO_RESTRI_MASK 0x0c +#define EBDA_NO_RESTRI 0x00 +#define EBDA_AVO_VGA_ADDR 0x04 +#define EBDA_AVO_VGA_ADDR_AND_ALIA 0x08 +#define EBDA_AVO_ISA_ADDR 0x0c + + +/************************************************************** +* DEVICE TYPE DEF * +**************************************************************/ + +#define EBDA_DEV_TYPE_MASK 0x10 +#define EBDA_PCI_DEV 0x10 +#define EBDA_NON_PCI_DEV 0x00 + + +/*************************************************************** +* PRIMARY DEF DEFINITION * +***************************************************************/ + +#define EBDA_PRI_DEF_MASK 0x20 +#define EBDA_PRI_PCI_BUS_INFO 0x20 +#define EBDA_NORM_DEV_RSRC_INFO 0x00 + + +//-------------------------------------------------------------- +// RIO TABLE DATA STRUCTURE +//-------------------------------------------------------------- + +struct rio_table_hdr { + u8 ver_num; + u8 scal_count; + u8 riodev_count; + u16 offset; +}; + +//------------------------------------------------------------- +// SCALABILITY DETAIL +//------------------------------------------------------------- + +struct scal_detail { + u8 node_id; + u32 cbar; + u8 port0_node_connect; + u8 port0_port_connect; + u8 port1_node_connect; + u8 port1_port_connect; + u8 port2_node_connect; + u8 port2_port_connect; +// struct list_head scal_detail_list; +}; + +//-------------------------------------------------------------- +// RIO DETAIL +//-------------------------------------------------------------- + +struct rio_detail { + u8 rio_node_id; + u32 bbar; + u8 rio_type; + u8 owner_id; + u8 port0_node_connect; + u8 port0_port_connect; + u8 port1_node_connect; + u8 port1_port_connect; + u8 first_slot_num; + u8 status; +// struct list_head rio_detail_list; +}; + + +/**************************************************************** +* HPC DESCRIPTOR NODE * +****************************************************************/ + +struct ebda_hpc_list { + u8 format; + u16 num_ctlrs; + short phys_addr; +// struct list_head ebda_hpc_list; +}; + +/***************************************************************** +* IN HPC DATA STRUCTURE, THE ASSOCIATED SLOT AND BUS * +* STRUCTURE * +*****************************************************************/ + +struct ebda_hpc_slot { + u8 slot_num; + u32 slot_bus_num; + u8 ctl_index; + u8 slot_cap; +}; + +struct ebda_hpc_bus { + u32 bus_num; +/* + u8 slots_at_33_conv; + u8 slots_at_66_conv; + u8 slots_at_66_pcix; + u8 slots_at_100_pcix; + u8 slots_at_133_pcix; +*/ +}; + + +/******************************************************************** +* THREE TYPE OF HOT PLUG CONTROLER * +********************************************************************/ + +struct isa_ctlr_access { + u16 io_start; + u16 io_end; +}; + +struct pci_ctlr_access { + u8 bus; + u8 dev_fun; +}; + +struct wpeg_i2c_ctlr_access { + ulong wpegbbar; + u8 i2c_addr; +}; + +/************************************************************************* +* RSTC DESCRIPTOR NODE * +*************************************************************************/ + +struct ebda_rsrc_list { + u8 format; + u16 num_entries; + u16 phys_addr; + struct ebda_rsrc_list *next; +}; + + +/*************************************************************************** +* PCI RSRC NODE * +***************************************************************************/ + +struct ebda_pci_rsrc { + u8 rsrc_type; + u8 bus_num; + u8 dev_fun; + ulong start_addr; + ulong end_addr; + struct list_head ebda_pci_rsrc_list; +}; + + +/*********************************************************** +* BUS_INFO DATE STRUCTURE * +***********************************************************/ + +struct bus_info { + u8 slot_min; + u8 slot_max; + u8 slot_count; + u8 busno; + u8 current_speed; + u8 supported_speed; + u8 controller_id; + u8 supported_bus_mode; + u8 current_bus_mode; + u8 index; + struct list_head bus_info_list; +}; + + +/*********************************************************** +* GLOBAL VARIABLES * +***********************************************************/ +extern struct list_head ibmphp_ebda_pci_rsrc_head; +extern struct list_head ibmphp_slot_head; + +/*********************************************************** +* FUNCTION PROTOTYPES * +***********************************************************/ + +extern void ibmphp_free_ebda_hpc_queue (void); +extern int ibmphp_access_ebda (void); +extern struct slot *ibmphp_get_slot_from_physical_num (u8); +extern int ibmphp_get_total_hp_slots (void); +extern void ibmphp_free_ibm_slot (struct slot *); +extern void ibmphp_free_bus_info_queue (void); +extern void ibmphp_free_ebda_pci_rsrc_queue (void); +extern struct bus_info *ibmphp_find_same_bus_num (u32); +extern int ibmphp_get_bus_index (u8); +extern u16 ibmphp_get_total_controllers (void); + +/* passed parameters */ +#define MEM 0 +#define IO 1 +#define PFMEM 2 + +/* bit masks */ +#define RESTYPE 0x03 +#define IOMASK 0x00 /* will need to take its complement */ +#define MMASK 0x01 +#define PFMASK 0x03 +#define PCIDEVMASK 0x10 /* we should always have PCI devices */ +#define PRIMARYBUSMASK 0x20 + +/* pci specific defines */ +#define PCI_VENDOR_ID_NOTVALID 0xFFFF +#define PCI_HEADER_TYPE_MULTIDEVICE 0x80 +#define PCI_HEADER_TYPE_MULTIBRIDGE 0x81 + +#define LATENCY 0x64 +#define CACHE 64 +#define DEVICEENABLE 0x015F /* CPQ has 0x0157 */ + +#define IOBRIDGE 0x1000 /* 4k */ +#define MEMBRIDGE 0x100000 /* 1M */ + +/* irqs */ +#define SCSI_IRQ 0x09 +#define LAN_IRQ 0x0A +#define OTHER_IRQ 0x0B + +/* Data Structures */ + +/* type is of the form x x xx xx + * | | | |_ 00 - I/O, 01 - Memory, 11 - PFMemory + * | | - 00 - No Restrictions, 01 - Avoid VGA, 10 - Avoid + * | | VGA and their aliases, 11 - Avoid ISA + * | - 1 - PCI device, 0 - non pci device + * - 1 - Primary PCI Bus Information (0 if Normal device) + * the IO restrictions [2:3] are only for primary buses + */ + + +/* we need this struct because there could be several resource blocks + * allocated per primary bus in the EBDA + */ +struct range_node { + int rangeno; + u32 start; + u32 end; + struct range_node *next; +}; + +struct bus_node { + u8 busno; + int noIORanges; + struct range_node *rangeIO; + int noMemRanges; + struct range_node *rangeMem; + int noPFMemRanges; + struct range_node *rangePFMem; + int needIOUpdate; + int needMemUpdate; + int needPFMemUpdate; + struct resource_node *firstIO; /* first IO resource on the Bus */ + struct resource_node *firstMem; /* first memory resource on the Bus */ + struct resource_node *firstPFMem; /* first prefetchable memory resource on the Bus */ + struct resource_node *firstPFMemFromMem; /* when run out of pfmem available, taking from Mem */ + struct list_head bus_list; +}; + +struct resource_node { + int rangeno; + u8 busno; + u8 devfunc; + u32 start; + u32 end; + u32 len; + int type; /* MEM, IO, PFMEM */ + u8 fromMem; /* this is to indicate that the range is from + * from the Memory bucket rather than from PFMem */ + struct resource_node *next; + struct resource_node *nextRange; /* for the other mem range on bus */ +}; + +struct res_needed { + u32 mem; + u32 pfmem; + u32 io; + u8 not_correct; /* needed for return */ + int devices[32]; /* for device numbers behind this bridge */ +}; + +/* functions */ + +extern int ibmphp_rsrc_init (void); +extern int ibmphp_add_resource (struct resource_node *); +extern int ibmphp_remove_resource (struct resource_node *); +extern int ibmphp_find_resource (struct bus_node *, u32, struct resource_node **, int); +extern int ibmphp_check_resource (struct resource_node *, u8); +extern int ibmphp_remove_bus (struct bus_node *, u8); +extern void ibmphp_free_resources (void); +extern int ibmphp_add_pfmem_from_mem (struct resource_node *); +extern struct bus_node *ibmphp_find_res_bus (u8); +extern void ibmphp_print_test (void); /* for debugging purposes */ + +extern void ibmphp_hpc_initvars (void); +extern int ibmphp_hpc_readslot (struct slot *, u8, u8 *); +extern int ibmphp_hpc_writeslot (struct slot *, u8); +extern void ibmphp_lock_operations (void); +extern void ibmphp_unlock_operations (void); +extern int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *); +extern int ibmphp_hpc_start_poll_thread (void); +extern void ibmphp_hpc_stop_poll_thread (void); + +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +// HPC return codes +//---------------------------------------------------------------------------- +#define FALSE 0x00 +#define TRUE 0x01 +#define HPC_ERROR 0xFF + +//----------------------------------------------------------------------------- +// BUS INFO +//----------------------------------------------------------------------------- +#define BUS_SPEED 0x30 +#define BUS_MODE 0x40 +#define BUS_MODE_PCIX 0x01 +#define BUS_MODE_PCI 0x00 +#define BUS_SPEED_2 0x20 +#define BUS_SPEED_1 0x10 +#define BUS_SPEED_33 0x00 +#define BUS_SPEED_66 0x01 +#define BUS_SPEED_100 0x02 +#define BUS_SPEED_133 0x03 +#define BUS_SPEED_66PCIX 0x04 +#define BUS_SPEED_66UNKNOWN 0x05 +#define BUS_STATUS_AVAILABLE 0x01 +#define BUS_CONTROL_AVAILABLE 0x02 +#define SLOT_LATCH_REGS_SUPPORTED 0x10 + +#define PRGM_MODEL_REV_LEVEL 0xF0 +#define MAX_ADAPTER_NONE 0x09 + +//---------------------------------------------------------------------------- +// HPC 'write' operations/commands +//---------------------------------------------------------------------------- +// Command Code State Write to reg +// Machine at index +//------------------------- ---- ------- ------------ +#define HPC_CTLR_ENABLEIRQ 0x00 // N 15 +#define HPC_CTLR_DISABLEIRQ 0x01 // N 15 +#define HPC_SLOT_OFF 0x02 // Y 0-14 +#define HPC_SLOT_ON 0x03 // Y 0-14 +#define HPC_SLOT_ATTNOFF 0x04 // N 0-14 +#define HPC_SLOT_ATTNON 0x05 // N 0-14 +#define HPC_CTLR_CLEARIRQ 0x06 // N 15 +#define HPC_CTLR_RESET 0x07 // Y 15 +#define HPC_CTLR_IRQSTEER 0x08 // N 15 +#define HPC_BUS_33CONVMODE 0x09 // Y 31-34 +#define HPC_BUS_66CONVMODE 0x0A // Y 31-34 +#define HPC_BUS_66PCIXMODE 0x0B // Y 31-34 +#define HPC_BUS_100PCIXMODE 0x0C // Y 31-34 +#define HPC_BUS_133PCIXMODE 0x0D // Y 31-34 +#define HPC_ALLSLOT_OFF 0x11 // Y 15 +#define HPC_ALLSLOT_ON 0x12 // Y 15 +#define HPC_SLOT_BLINKLED 0x13 // N 0-14 + +//---------------------------------------------------------------------------- +// read commands +//---------------------------------------------------------------------------- +#define READ_SLOTSTATUS 0x01 +#define READ_EXTSLOTSTATUS 0x02 +#define READ_BUSSTATUS 0x03 +#define READ_CTLRSTATUS 0x04 +#define READ_ALLSTAT 0x05 +#define READ_ALLSLOT 0x06 +#define READ_SLOTLATCHLOWREG 0x07 +#define READ_REVLEVEL 0x08 +#define READ_HPCOPTIONS 0x09 +//---------------------------------------------------------------------------- +// slot status +//---------------------------------------------------------------------------- +#define HPC_SLOT_POWER 0x01 +#define HPC_SLOT_CONNECT 0x02 +#define HPC_SLOT_ATTN 0x04 +#define HPC_SLOT_PRSNT2 0x08 +#define HPC_SLOT_PRSNT1 0x10 +#define HPC_SLOT_PWRGD 0x20 +#define HPC_SLOT_BUS_SPEED 0x40 +#define HPC_SLOT_LATCH 0x80 + +//---------------------------------------------------------------------------- +// HPC_SLOT_POWER status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_POWER_OFF 0x00 +#define HPC_SLOT_POWER_ON 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_CONNECT status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_CONNECTED 0x00 +#define HPC_SLOT_DISCONNECTED 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_ATTN status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_ATTN_OFF 0x00 +#define HPC_SLOT_ATTN_ON 0x01 +#define HPC_SLOT_ATTN_BLINK 0x02 + +//---------------------------------------------------------------------------- +// HPC_SLOT_PRSNT status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_EMPTY 0x00 +#define HPC_SLOT_PRSNT_7 0x01 +#define HPC_SLOT_PRSNT_15 0x02 +#define HPC_SLOT_PRSNT_25 0x03 + +//---------------------------------------------------------------------------- +// HPC_SLOT_PWRGD status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_PWRGD_FAULT_NONE 0x00 +#define HPC_SLOT_PWRGD_GOOD 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_BUS_SPEED status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_BUS_SPEED_OK 0x00 +#define HPC_SLOT_BUS_SPEED_MISM 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_LATCH status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_LATCH_OPEN 0x01 // NOTE : in PCI spec bit off = open +#define HPC_SLOT_LATCH_CLOSED 0x00 // NOTE : in PCI spec bit on = closed + + +//---------------------------------------------------------------------------- +// extended slot status +//---------------------------------------------------------------------------- +#define HPC_SLOT_PCIX 0x01 +#define HPC_SLOT_SPEED1 0x02 +#define HPC_SLOT_SPEED2 0x04 +#define HPC_SLOT_BLINK_ATTN 0x08 +#define HPC_SLOT_RSRVD1 0x10 +#define HPC_SLOT_RSRVD2 0x20 +#define HPC_SLOT_BUS_MODE 0x40 +#define HPC_SLOT_RSRVD3 0x80 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_PCIX_CAP status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_PCIX_NO 0x00 +#define HPC_SLOT_PCIX_YES 0x01 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_SPEED status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_SPEED_33 0x00 +#define HPC_SLOT_SPEED_66 0x01 +#define HPC_SLOT_SPEED_133 0x02 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_ATTN_BLINK status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_ATTN_BLINK_OFF 0x00 +#define HPC_SLOT_ATTN_BLINK_ON 0x01 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_BUS_MODE status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_BUS_MODE_OK 0x00 +#define HPC_SLOT_BUS_MODE_MISM 0x01 + +//---------------------------------------------------------------------------- +// Controller status +//---------------------------------------------------------------------------- +#define HPC_CTLR_WORKING 0x01 +#define HPC_CTLR_FINISHED 0x02 +#define HPC_CTLR_RESULT0 0x04 +#define HPC_CTLR_RESULT1 0x08 +#define HPC_CTLR_RESULE2 0x10 +#define HPC_CTLR_RESULT3 0x20 +#define HPC_CTLR_IRQ_ROUTG 0x40 +#define HPC_CTLR_IRQ_PENDG 0x80 + +//---------------------------------------------------------------------------- +// HPC_CTLR_WROKING status return codes +//---------------------------------------------------------------------------- +#define HPC_CTLR_WORKING_NO 0x00 +#define HPC_CTLR_WORKING_YES 0x01 + +//---------------------------------------------------------------------------- +// HPC_CTLR_FINISHED status return codes +//---------------------------------------------------------------------------- +#define HPC_CTLR_FINISHED_NO 0x00 +#define HPC_CTLR_FINISHED_YES 0x01 + +//---------------------------------------------------------------------------- +// HPC_CTLR_RESULT status return codes +//---------------------------------------------------------------------------- +#define HPC_CTLR_RESULT_SUCCESS 0x00 +#define HPC_CTLR_RESULT_FAILED 0x01 +#define HPC_CTLR_RESULT_RSVD 0x02 +#define HPC_CTLR_RESULT_NORESP 0x03 + + +//---------------------------------------------------------------------------- +// macro for slot info +//---------------------------------------------------------------------------- +#define SLOT_POWER(s) ((u8) ((s & HPC_SLOT_POWER) \ + ? HPC_SLOT_POWER_ON : HPC_SLOT_POWER_OFF)) + +#define SLOT_CONNECT(s) ((u8) ((s & HPC_SLOT_CONNECT) \ + ? HPC_SLOT_DISCONNECTED : HPC_SLOT_CONNECTED)) + +#define SLOT_ATTN(s,es) ((u8) ((es & HPC_SLOT_BLINK_ATTN) \ + ? HPC_SLOT_ATTN_BLINK \ + : ((s & HPC_SLOT_ATTN) ? HPC_SLOT_ATTN_ON : HPC_SLOT_ATTN_OFF))) + +#define SLOT_PRESENT(s) ((u8) ((s & HPC_SLOT_PRSNT1) \ + ? ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_EMPTY : HPC_SLOT_PRSNT_15) \ + : ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_PRSNT_25 : HPC_SLOT_PRSNT_7))) + +#define SLOT_PWRGD(s) ((u8) ((s & HPC_SLOT_PWRGD) \ + ? HPC_SLOT_PWRGD_GOOD : HPC_SLOT_PWRGD_FAULT_NONE)) + +#define SLOT_BUS_SPEED(s) ((u8) ((s & HPC_SLOT_BUS_SPEED) \ + ? HPC_SLOT_BUS_SPEED_MISM : HPC_SLOT_BUS_SPEED_OK)) + +#define SLOT_LATCH(s) ((u8) ((s & HPC_SLOT_LATCH) \ + ? HPC_SLOT_LATCH_CLOSED : HPC_SLOT_LATCH_OPEN)) + +#define SLOT_PCIX(es) ((u8) ((es & HPC_SLOT_PCIX) \ + ? HPC_SLOT_PCIX_YES : HPC_SLOT_PCIX_NO)) + +#define SLOT_SPEED(es) ((u8) ((es & HPC_SLOT_SPEED2) \ + ? ((es & HPC_SLOT_SPEED1) ? HPC_SLOT_SPEED_133 \ + : HPC_SLOT_SPEED_66) \ + : HPC_SLOT_SPEED_33)) + +#define SLOT_BUS_MODE(es) ((u8) ((es & HPC_SLOT_BUS_MODE) \ + ? HPC_SLOT_BUS_MODE_MISM : HPC_SLOT_BUS_MODE_OK)) + +//-------------------------------------------------------------------------- +// macro for bus info +//--------------------------------------------------------------------------- +#define CURRENT_BUS_SPEED(s) ((u8) (s & BUS_SPEED_2) \ + ? ((s & BUS_SPEED_1) ? BUS_SPEED_133 : BUS_SPEED_100) \ + : ((s & BUS_SPEED_1) ? BUS_SPEED_66 : BUS_SPEED_33)) + +#define CURRENT_BUS_MODE(s) ((u8) (s & BUS_MODE) ? BUS_MODE_PCIX : BUS_MODE_PCI) + +#define READ_BUS_STATUS(s) ((u8) (s->options & BUS_STATUS_AVAILABLE)) + +#define READ_BUS_MODE(s) ((s->revision & PRGM_MODEL_REV_LEVEL) >= 0x20) + +#define SET_BUS_STATUS(s) ((u8) (s->options & BUS_CONTROL_AVAILABLE)) + +#define READ_SLOT_LATCH(s) ((u8) (s->options & SLOT_LATCH_REGS_SUPPORTED)) + +//---------------------------------------------------------------------------- +// macro for controller info +//---------------------------------------------------------------------------- +#define CTLR_WORKING(c) ((u8) ((c & HPC_CTLR_WORKING) \ + ? HPC_CTLR_WORKING_YES : HPC_CTLR_WORKING_NO)) +#define CTLR_FINISHED(c) ((u8) ((c & HPC_CTLR_FINISHED) \ + ? HPC_CTLR_FINISHED_YES : HPC_CTLR_FINISHED_NO)) +#define CTLR_RESULT(c) ((u8) ((c & HPC_CTLR_RESULT1) \ + ? ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_NORESP \ + : HPC_CTLR_RESULT_RSVD) \ + : ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_FAILED \ + : HPC_CTLR_RESULT_SUCCESS))) + +// command that affect the state machine of HPC +#define NEEDTOCHECK_CMDSTATUS(c) ((c == HPC_SLOT_OFF) || \ + (c == HPC_SLOT_ON) || \ + (c == HPC_CTLR_RESET) || \ + (c == HPC_BUS_33CONVMODE) || \ + (c == HPC_BUS_66CONVMODE) || \ + (c == HPC_BUS_66PCIXMODE) || \ + (c == HPC_BUS_100PCIXMODE) || \ + (c == HPC_BUS_133PCIXMODE) || \ + (c == HPC_ALLSLOT_OFF) || \ + (c == HPC_ALLSLOT_ON)) + + +/* Core part of the driver */ + +#define ENABLE 1 +#define DISABLE 0 + +#define ADD 0 +#define REMOVE 1 +#define DETAIL 2 + +#define MAX_OPS 3 +#define CARD_INFO 0x07 +#define PCIX133 0x07 +#define PCIX66 0x05 +#define PCI66 0x04 + +extern struct pci_ops *ibmphp_pci_root_ops; + +/* Variables */ + +struct pci_func { + struct pci_dev *dev; /* from the OS */ + u8 busno; + u8 device; + u8 function; + struct resource_node *io[6]; + struct resource_node *mem[6]; + struct resource_node *pfmem[6]; + struct pci_func *next; + int devices[32]; /* for bridge config */ + u8 irq[4]; /* for interrupt config */ + u8 bus; /* flag for unconfiguring, to say if PPB */ +}; + +struct slot { + u8 bus; + u8 device; + u8 number; + char name[100]; + u32 capabilities; + struct hotplug_slot *hotplug_slot; + struct controller *ctrl; + struct pci_func *func; + u8 irq[4]; + u8 flag; /* this is for disable slot and polling */ + int bit_mode; /* 0 = 32, 1 = 64 */ + u8 ctlr_index; + struct bus_info *bus_on; + struct list_head ibm_slot_list; + u8 status; + u8 ext_status; + u8 busstatus; +}; + +struct controller { + struct ebda_hpc_slot *slots; + struct ebda_hpc_bus *buses; + u8 revision; + u8 options; /* which options HPC supports */ + u8 status; + u8 ctlr_id; /* TONI */ + u8 slot_count; + u8 bus_count; + u8 ctlr_relative_id; + u32 irq; + union { + struct isa_ctlr_access isa_ctlr; + struct pci_ctlr_access pci_ctlr; + struct wpeg_i2c_ctlr_access wpeg_ctlr; + } u; + u8 ctlr_type; + struct list_head ebda_hpc_list; +}; + +/* Functions */ + +extern int ibmphp_init_devno (struct slot **); /* This function is called from EBDA, so we need it not be static */ +extern int ibmphp_disable_slot (struct hotplug_slot *); /* This function is called from HPC, so we need it to not be static */ +extern int ibmphp_update_slot_info (struct slot *); /* This function is called from HPC, so we need it to not be be static */ +extern int ibmphp_configure_card (struct pci_func *, u8); +extern int ibmphp_unconfigure_card (struct slot **, int); +extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops; + +static inline void long_delay (int delay) +{ + set_current_state (TASK_INTERRUPTIBLE); + schedule_timeout (delay); +} + +#endif //__IBMPHP_H + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/ibmphp_core.c linux-2.5/drivers/hotplug/ibmphp_core.c --- linux-2.5.5/drivers/hotplug/ibmphp_core.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/hotplug/ibmphp_core.c Fri Mar 1 15:07:37 2002 @@ -0,0 +1,1480 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Chuck Cole, Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../arch/i386/kernel/pci-i386.h" /* for struct irq_routing_table */ +#include "ibmphp.h" + +#define attn_on(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON) +#define attn_off(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNOFF) +#define attn_LED_blink(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_BLINKLED) +#define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev) +#define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt) + +#define DRIVER_VERSION "0.1" +#define DRIVER_DESC "IBM Hot Plug PCI Controller Driver" + +int ibmphp_debug; + +static int debug; +MODULE_PARM (debug, "i"); +MODULE_PARM_DESC (debug, "Debugging mode enabled or not"); +MODULE_LICENSE ("GPL"); +MODULE_DESCRIPTION (DRIVER_DESC); + +static int *ops[MAX_OPS + 1]; +static struct pci_ops *ibmphp_pci_root_ops; +static int max_slots; + +static int irqs[16]; /* PIC mode IRQ's we're using so far (in case MPS tables don't provide default info for empty slots */ + +static int init_flag; + +/* +static int get_max_adapter_speed_1 (struct hotplug_slot *, u8 *, u8); + +static inline int get_max_adapter_speed (struct hotplug_slot *hs, u8 *value) +{ + return get_max_adapter_speed_1 (hs, value, 1); +} +*/ +static inline int get_cur_bus_info (struct slot **sl) +{ + int rc = 1; + struct slot * slot_cur = *sl; + + debug ("options = %x\n", slot_cur->ctrl->options); + debug ("revision = %x\n", slot_cur->ctrl->revision); + + if (READ_BUS_STATUS (slot_cur->ctrl)) + rc = ibmphp_hpc_readslot (slot_cur, READ_BUSSTATUS, NULL); + + if (rc) + return rc; + + slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED (slot_cur->busstatus); + if (READ_BUS_MODE (slot_cur->ctrl)) + slot_cur->bus_on->current_bus_mode = CURRENT_BUS_MODE (slot_cur->busstatus); + + debug ("busstatus = %x, bus_speed = %x, bus_mode = %x\n", slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode); + + *sl = slot_cur; + return 0; +} + +static inline int slot_update (struct slot **sl) +{ + int rc; + rc = ibmphp_hpc_readslot (*sl, READ_ALLSTAT, NULL); + if (rc) + return rc; + if (!init_flag) + return get_cur_bus_info (sl); + return rc; +} + +static int get_max_slots (void) +{ + struct list_head * tmp; + int slot_count = 0; + + list_for_each (tmp, &ibmphp_slot_head) + ++slot_count; + return slot_count; +} + +/* This routine will put the correct slot->device information per slot. It's + * called from initialization of the slot structures. It will also assign + * interrupt numbers per each slot. + * Parameters: struct slot + * Returns 0 or errors + */ +int ibmphp_init_devno (struct slot **cur_slot) +{ + struct irq_routing_table *rtable; + int len; + int loop; + int i; + + rtable = pcibios_get_irq_routing_table (); + if (!rtable) { + err ("no BIOS routing table...\n"); + return -ENOMEM; + } + + len = (rtable->size - sizeof (struct irq_routing_table)) / sizeof (struct irq_info); + + if (!len) + return -1; + for (loop = 0; loop < len; loop++) { + if ((*cur_slot)->number == rtable->slots[loop].slot) { + if ((*cur_slot)->bus == rtable->slots[loop].bus) { + (*cur_slot)->device = PCI_SLOT (rtable->slots[loop].devfn); + for (i = 0; i < 4; i++) + (*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector ((int) (*cur_slot)->bus, (int) (*cur_slot)->device, i); + + debug ("(*cur_slot)->irq[0] = %x\n", (*cur_slot)->irq[0]); + debug ("(*cur_slot)->irq[1] = %x\n", (*cur_slot)->irq[1]); + debug ("(*cur_slot)->irq[2] = %x\n", (*cur_slot)->irq[2]); + debug ("(*cur_slot)->irq[3] = %x\n", (*cur_slot)->irq[3]); + + debug ("rtable->exlusive_irqs = %x\n", rtable->exclusive_irqs); + debug ("rtable->slots[loop].irq[0].bitmap = %x\n", rtable->slots[loop].irq[0].bitmap); + debug ("rtable->slots[loop].irq[1].bitmap = %x\n", rtable->slots[loop].irq[1].bitmap); + debug ("rtable->slots[loop].irq[2].bitmap = %x\n", rtable->slots[loop].irq[2].bitmap); + debug ("rtable->slots[loop].irq[3].bitmap = %x\n", rtable->slots[loop].irq[3].bitmap); + + debug ("rtable->slots[loop].irq[0].link= %x\n", rtable->slots[loop].irq[0].link); + debug ("rtable->slots[loop].irq[1].link = %x\n", rtable->slots[loop].irq[1].link); + debug ("rtable->slots[loop].irq[2].link = %x\n", rtable->slots[loop].irq[2].link); + debug ("rtable->slots[loop].irq[3].link = %x\n", rtable->slots[loop].irq[3].link); + debug ("end of init_devno\n"); + return 0; + } + } + } + + return -1; +} + +static inline int power_on (struct slot *slot_cur) +{ + u8 cmd = HPC_SLOT_ON; + int retval; + + retval = ibmphp_hpc_writeslot (slot_cur, cmd); + if (retval) { + err ("power on failed\n"); + return retval; + } + if (CTLR_RESULT (slot_cur->ctrl->status)) { + err ("command not completed successfully in power_on \n"); + return -EIO; + } + long_delay (3 * HZ); /* For ServeRAID cards, and some 66 PCI */ + return 0; +} + +static inline int power_off (struct slot *slot_cur) +{ + u8 cmd = HPC_SLOT_OFF; + int retval; + + retval = ibmphp_hpc_writeslot (slot_cur, cmd); + if (retval) { + err ("power off failed \n"); + return retval; + } + if (CTLR_RESULT (slot_cur->ctrl->status)) { + err ("command not completed successfully in power_off \n"); + return -EIO; + } + return 0; +} + +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value) +{ + int rc = 0; + struct slot *pslot; + u8 cmd; + int hpcrc = 0; + + debug ("set_attention_status - Entry hotplug_slot[%lx] value[%x]\n", (ulong) hotplug_slot, value); + ibmphp_lock_operations (); + cmd = 0x00; // avoid compiler warning + + if (hotplug_slot) { + switch (value) { + case HPC_SLOT_ATTN_OFF: + cmd = HPC_SLOT_ATTNOFF; + break; + case HPC_SLOT_ATTN_ON: + cmd = HPC_SLOT_ATTNON; + break; + case HPC_SLOT_ATTN_BLINK: + cmd = HPC_SLOT_BLINKLED; + break; + default: + rc = -ENODEV; + err ("set_attention_status - Error : invalid input [%x]\n", value); + break; + } + if (rc == 0) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) + hpcrc = ibmphp_hpc_writeslot (pslot, cmd); + else + rc = -ENODEV; + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + + debug ("set_attention_status - Exit rc[%d]\n", rc); + return rc; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_attention_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) + hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status)); + if (!hpcrc) { + *value = SLOT_ATTN (myslot.status, myslot.ext_status); + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_attention_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) { + *value = SLOT_LATCH (myslot.status); + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_latch_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) { + *value = SLOT_POWER (myslot.status); + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_power_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_adapter_present (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + u8 present; + int hpcrc = 0; + struct slot myslot; + + debug ("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) { + present = SLOT_PRESENT (myslot.status); + if (present == HPC_SLOT_EMPTY) + *value = 0; + else + *value = 1; + rc = 0; + } + } + } else + rc = -ENODEV; + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} +/* +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + u8 mode = 0; + + debug ("get_max_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value); + + ibmphp_lock_operations (); + + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + rc = 0; + mode = pslot->bus_on->supported_bus_mode; + *value = pslot->bus_on->supported_speed; + *value &= 0x0f; + + if (mode == BUS_MODE_PCIX) + *value |= 0x80; + else if (mode == BUS_MODE_PCI) + *value |= 0x40; + else + *value |= 0x20; + } + } else + rc = -ENODEV; + + ibmphp_unlock_operations (); + debug ("get_max_bus_speed - Exit rc[%d] value[%x]\n", rc, *value); + return rc; +} + +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + u8 mode = 0; + + debug ("get_cur_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value); + + ibmphp_lock_operations (); + + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + rc = get_cur_bus_info (&pslot); + if (!rc) { + mode = pslot->bus_on->current_bus_mode; + *value = pslot->bus_on->current_speed; + *value &= 0x0f; + + if (mode == BUS_MODE_PCIX) + *value |= 0x80; + else if (mode == BUS_MODE_PCI) + *value |= 0x40; + else + *value |= 0x20; + } + } + } else + rc = -ENODEV; + + ibmphp_unlock_operations (); + debug ("get_cur_bus_speed - Exit rc[%d] value[%x]\n", rc, *value); + return rc; +} + +static int get_max_adapter_speed_1 (struct hotplug_slot *hotplug_slot, u8 * value, u8 flag) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_max_adapter_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value); + + if (flag) + ibmphp_lock_operations (); + + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + + if (!(SLOT_LATCH (myslot.status)) && (SLOT_PRESENT (myslot.status))) { + hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status)); + if (!hpcrc) { + *value = SLOT_SPEED (myslot.ext_status); + rc = 0; + } + } else { + *value = MAX_ADAPTER_NONE; + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + if (flag) + ibmphp_unlock_operations (); + + debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_card_bus_names (struct hotplug_slot *hotplug_slot, char * value) +{ + int rc = -ENODEV; + struct slot *pslot = NULL; + struct pci_dev * dev = NULL; + + debug ("get_card_bus_names - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot); + + ibmphp_lock_operations (); + + if (hotplug_slot) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + rc = 0; + if (pslot->func) + dev = pslot->func->dev; + else + dev = pci_find_slot (pslot->bus, (pslot->device << 3) | (0x00 & 0x7)); + if (dev) + snprintf (value, 100, "Bus %d : %s", pslot->bus,dev->name); + else + snprintf (value, 100, "Bus %d", pslot->bus); + + + } + } else + rc = -ENODEV; + + ibmphp_unlock_operations (); + debug ("get_card_bus_names - Exit rc[%d] value[%x]\n", rc, *value); + return rc; +} + +*/ +/******************************************************************************* + * This routine will initialize the ops data structure used in the validate + * function. It will also power off empty slots that are powered on since BIOS + * leaves those on, albeit disconnected + ******************************************************************************/ +static int init_ops (void) +{ + struct slot *slot_cur; + int retval; + int j; + int rc; + + for (j = 0; j < MAX_OPS; j++) { + ops[j] = (int *) kmalloc ((max_slots + 1) * sizeof (int), GFP_KERNEL); + if (!ops[j]) { + err ("out of system memory \n"); + return -ENOMEM; + } + } + + ops[ADD][0] = 0; + ops[REMOVE][0] = 0; + ops[DETAIL][0] = 0; + + for (j = 1; j <= max_slots; j++) { + + slot_cur = ibmphp_get_slot_from_physical_num (j); + + debug ("BEFORE GETTING SLOT STATUS, slot # %x\n", slot_cur->number); + + if (slot_cur->ctrl->revision == 0xFF) + if (get_ctrl_revision (slot_cur, &slot_cur->ctrl->revision)) + return -1; + + if (slot_cur->bus_on->current_speed == 0xFF) + if (get_cur_bus_info (&slot_cur)) + return -1; + + if (slot_cur->ctrl->options == 0xFF) + if (get_hpc_options (slot_cur, &slot_cur->ctrl->options)) + return -1; + + retval = slot_update (&slot_cur); + if (retval) + return retval; + + debug ("status = %x, ext_status = %x\n", slot_cur->status, slot_cur->ext_status); + debug ("SLOT_POWER = %x, SLOT_PRESENT = %x, SLOT_LATCH = %x\n", SLOT_POWER (slot_cur->status), SLOT_PRESENT (slot_cur->status), SLOT_LATCH (slot_cur->status)); + + if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status))) + /* No power, adapter, and latch closed */ + ops[ADD][j] = 1; + else + ops[ADD][j] = 0; + + ops[DETAIL][j] = 1; + + if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status))) + /*Power,adapter,latch closed */ + ops[REMOVE][j] = 1; + else + ops[REMOVE][j] = 0; + + if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status))) { + debug ("BEFORE POWER OFF COMMAND\n"); + rc = power_off (slot_cur); + if (rc) + return rc; + + /* retval = slot_update (&slot_cur); + * if (retval) + * return retval; + * ibmphp_update_slot_info (slot_cur); + */ + } + } + init_flag = 0; + return 0; +} + +/* This operation will check whether the slot is within the bounds and + * the operation is valid to perform on that slot + * Parameters: slot, operation + * Returns: 0 or error codes + */ +static int validate (struct slot *slot_cur, int opn) +{ + int number; + int retval; + + if (!slot_cur) + return -ENODEV; + number = slot_cur->number; + if ((number > max_slots) || (number < 0)) + return -EBADSLT; + debug ("slot_number in validate is %d\n", slot_cur->number); + + retval = slot_update (&slot_cur); + if (retval) + return retval; + + if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) + && !(SLOT_LATCH (slot_cur->status))) + ops[ADD][number] = 1; + else + ops[ADD][number] = 0; + + ops[DETAIL][number] = 1; + + if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) + && !(SLOT_LATCH (slot_cur->status))) + ops[REMOVE][number] = 1; + else + ops[REMOVE][number] = 0; + + switch (opn) { + case ENABLE: + if (ops[ADD][number]) + return 0; + break; + case DISABLE: + if (ops[REMOVE][number]) + return 0; + break; + case DETAIL: + if (ops[DETAIL][number]) + return 0; + break; + default: + return -EINVAL; + break; + } + err ("validate failed....\n"); + return -EINVAL; +} + +/******************************************************************************** + * This routine is for updating the data structures in the hotplug core + * Parameters: struct slot + * Returns: 0 or error + *******************************************************************************/ +int ibmphp_update_slot_info (struct slot *slot_cur) +{ + struct hotplug_slot_info *info; + char buffer[10]; + int rc; +// u8 bus_speed; + + info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!info) { + err ("out of system memory \n"); + return -ENOMEM; + } + + snprintf (buffer, 10, "%d", slot_cur->number); + info->power_status = SLOT_POWER (slot_cur->status); + info->attention_status = SLOT_ATTN (slot_cur->status, slot_cur->ext_status); + info->latch_status = SLOT_LATCH (slot_cur->status); + if (!SLOT_PRESENT (slot_cur->status)) { + info->adapter_status = 0; +// info->max_adapter_speed_status = MAX_ADAPTER_NONE; + } else { + info->adapter_status = 1; +// get_max_adapter_speed_1 (slot_cur->hotplug_slot, &info->max_adapter_speed_status, 0); + } +/* + bus_speed = slot_cur->bus_on->current_speed; + bus_speed &= 0x0f; + + if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX) + bus_speed |= 0x80; + else if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCI) + bus_speed |= 0x40; + else + bus_speed |= 0x20; + + info->cur_bus_speed_status = bus_speed; + info->max_bus_speed_status = slot_cur->hotplug_slot->info->max_bus_speed_status; + // To do: card_bus_names +*/ + rc = pci_hp_change_slot_info (buffer, info); + kfree (info); + return rc; +} + + +/****************************************************************************** + * This function will return the pci_func, given bus and devfunc, or NULL. It + * is called from visit routines + ******************************************************************************/ + +static struct pci_func *ibm_slot_find (u8 busno, u8 device, u8 function) +{ + struct pci_func *func_cur; + struct slot *slot_cur; + struct list_head * tmp; + list_for_each (tmp, &ibmphp_slot_head) { + slot_cur = list_entry (tmp, struct slot, ibm_slot_list); + if (slot_cur->func) { + func_cur = slot_cur->func; + while (func_cur) { + if ((func_cur->busno == busno) && (func_cur->device == device) && (func_cur->function == function)) + return func_cur; + func_cur = func_cur->next; + } + } + } + return NULL; +} + +/* This routine is to find the pci_bus from kernel structures. + * Parameters: bus number + * Returns : pci_bus * or NULL if not found + */ +static struct pci_bus *find_bus (u8 busno) +{ + const struct list_head *tmp; + struct pci_bus *bus; + debug ("inside find_bus, busno = %x \n", busno); + + list_for_each (tmp, &pci_root_buses) { + bus = (struct pci_bus *) pci_bus_b (tmp); + if (bus) + if (bus->number == busno) + return bus; + } + return NULL; +} + +/****************************************************************** + * This function is here because we can no longer use pci_root_ops + ******************************************************************/ +static struct pci_ops *get_root_pci_ops (void) +{ + struct pci_bus * bus; + + if ((bus = find_bus (0))) + return bus->ops; + return NULL; +} + +/************************************************************* + * This routine frees up memory used by struct slot, including + * the pointers to pci_func, bus, hotplug_slot, controller, + * and deregistering from the hotplug core + *************************************************************/ +static void free_slots (void) +{ + struct slot *slot_cur; + struct list_head * tmp; + struct list_head * next; + + list_for_each_safe (tmp, next, &ibmphp_slot_head) { + + slot_cur = list_entry (tmp, struct slot, ibm_slot_list); + + pci_hp_deregister (slot_cur->hotplug_slot); + + if (slot_cur->hotplug_slot) { + kfree (slot_cur->hotplug_slot); + slot_cur->hotplug_slot = NULL; + } + + if (slot_cur->ctrl) + slot_cur->ctrl = NULL; + + if (slot_cur->bus_on) + slot_cur->bus_on = NULL; + + ibmphp_unconfigure_card (&slot_cur, -1); /* we don't want to actually remove the resources, since free_resources will do just that */ + + kfree (slot_cur); + } +} + +static int ibm_is_pci_dev_in_use (struct pci_dev *dev) +{ + int i = 0; + int inuse = 0; + + if (dev->driver) + return 1; + + for (i = 0; !dev->driver && !inuse && (i < 6); i++) { + + if (!pci_resource_start (dev, i)) + continue; + + if (pci_resource_flags (dev, i) & IORESOURCE_IO) + inuse = check_region (pci_resource_start (dev, i), pci_resource_len (dev, i)); + + else if (pci_resource_flags (dev, i) & IORESOURCE_MEM) + inuse = check_mem_region (pci_resource_start (dev, i), pci_resource_len (dev, i)); + } + + return inuse; +} + +static int ibm_pci_hp_remove_device (struct pci_dev *dev) +{ + if (ibm_is_pci_dev_in_use (dev)) { + err ("***Cannot safely power down device -- it appears to be in use***\n"); + return -EBUSY; + } + pci_remove_device (dev); + return 0; +} + +static int ibm_unconfigure_visit_pci_dev_phase2 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev *dev = wrapped_dev->dev; + struct pci_func *temp_func; + int i = 0; + + do { + temp_func = ibm_slot_find (dev->bus->number, dev->devfn >> 3, i++); + } while (temp_func && (temp_func->function != (dev->devfn & 0x07))); + + if (dev) { + if (ibm_pci_hp_remove_device (dev) == 0) + kfree (dev); /* Now, remove */ + else + return -1; + } + + if (temp_func) + temp_func->dev = NULL; + else + err ("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn); + + return 0; +} + +static int ibm_unconfigure_visit_pci_bus_phase2 (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev) +{ + struct pci_bus *bus = wrapped_bus->bus; + + pci_proc_detach_bus (bus); + /* The cleanup code should live in the kernel... */ + bus->self->subordinate = NULL; + /* unlink from parent bus */ + list_del (&bus->node); + + /* Now, remove */ + if (bus) + kfree (bus); + + return 0; +} + +static int ibm_unconfigure_visit_pci_dev_phase1 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev *dev = wrapped_dev->dev; + + debug ("attempting removal of driver for device (%x, %x, %x)\n", dev->bus->number, PCI_SLOT (dev->devfn), PCI_FUNC (dev->devfn)); + + /* Now, remove the Linux Driver Representation */ + if (dev->driver) { + debug ("is there a driver?\n"); + if (dev->driver->remove) { + dev->driver->remove (dev); + debug ("driver was properly removed\n"); + } + dev->driver = NULL; + } + + return ibm_is_pci_dev_in_use (dev); +} + +static struct pci_visit ibm_unconfigure_functions_phase1 = { + post_visit_pci_dev: ibm_unconfigure_visit_pci_dev_phase1, +}; + +static struct pci_visit ibm_unconfigure_functions_phase2 = { + post_visit_pci_bus: ibm_unconfigure_visit_pci_bus_phase2, + post_visit_pci_dev: ibm_unconfigure_visit_pci_dev_phase2, +}; + +static int ibm_unconfigure_device (struct pci_func *func) +{ + int rc = 0; + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + struct pci_dev *temp; + u8 j; + + memset (&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); + memset (&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); + + debug ("inside ibm_unconfigure_device\n"); + debug ("func->device = %x, func->function = %x\n", func->device, func->function); + debug ("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0); + + for (j = 0; j < 0x08; j++) { + temp = pci_find_slot (func->busno, (func->device << 3) | j); + if (temp) { + wrapped_dev.dev = temp; + wrapped_bus.bus = temp->bus; + rc = pci_visit_dev (&ibm_unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus); + if (rc) + break; + + rc = pci_visit_dev (&ibm_unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus); + if (rc) + break; + } + } + debug ("rc in ibm_unconfigure_device b4 returning is %d \n", rc); + return rc; +} + +static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + // struct pci_bus *bus = wrapped_bus->bus; /* We don't need this, since we don't create in the else statement */ + struct pci_dev *dev = wrapped_dev->dev; + struct pci_func *temp_func; + int i = 0; + + do { + temp_func = ibm_slot_find (dev->bus->number, dev->devfn >> 3, i++); + } while (temp_func && (temp_func->function != (dev->devfn & 0x07))); + + if (temp_func) + temp_func->dev = dev; + else { + /* This should not really happen, since we create functions + first and then call to configure */ + debug (" We shouldn't come here \n"); + } + + if (temp_func->dev) { + pci_proc_attach_device (temp_func->dev); + pci_announce_device_to_drivers (temp_func->dev); + } + + return 0; +} + +static struct pci_visit configure_functions = { + visit_pci_dev: configure_visit_pci_dev, +}; + +static int ibm_configure_device (struct pci_func *func) +{ + unsigned char bus; + struct pci_dev dev0; + struct pci_bus *child; + struct pci_dev *temp; + int rc = 0; + + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + + memset (&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); + memset (&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); + memset (&dev0, 0, sizeof (struct pci_dev)); + + if (func->dev == NULL) + func->dev = pci_find_slot (func->busno, (func->device << 3) | (func->function & 0x7)); + + if (func->dev == NULL) { + dev0.bus = find_bus (func->busno); + dev0.devfn = ((func->device << 3) + (func->function & 0x7)); + dev0.sysdata = dev0.bus->sysdata; + + func->dev = pci_scan_slot (&dev0); + + if (func->dev == NULL) { + err ("ERROR... : pci_dev still NULL \n"); + return 0; + } + } + if (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte (func->dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus *) pci_add_new_bus (func->dev->bus, (func->dev), bus); + pci_do_scan_bus (child); + } + + temp = func->dev; + if (temp) { + wrapped_dev.dev = temp; + wrapped_bus.bus = temp->bus; + rc = pci_visit_dev (&configure_functions, &wrapped_dev, &wrapped_bus); + } + return rc; +} +/******************************************************* + * Returns whether the bus is empty or not + *******************************************************/ +static int is_bus_empty (struct slot * slot_cur) +{ + int rc; + struct slot * tmp_slot; + u8 i = slot_cur->bus_on->slot_min; + + while (i <= slot_cur->bus_on->slot_max) { + if (i == slot_cur->number) { + i++; + continue; + } + tmp_slot = ibmphp_get_slot_from_physical_num (i); + rc = slot_update (&tmp_slot); + if (rc) + return 0; + if (SLOT_PRESENT (tmp_slot->status) && SLOT_POWER (tmp_slot->status)) + return 0; + i++; + } + return 1; +} + +/*********************************************************** + * If the HPC permits and the bus currently empty, tries to set the + * bus speed and mode at the maximum card capability + ***********************************************************/ +static int set_bus (struct slot * slot_cur) +{ + int rc; + u8 speed; + u8 cmd = 0x0; + + debug ("%s - entry slot # %d \n", __FUNCTION__, slot_cur->number); + if (SET_BUS_STATUS (slot_cur->ctrl) && is_bus_empty (slot_cur)) { + rc = slot_update (&slot_cur); + if (rc) + return rc; + speed = SLOT_SPEED (slot_cur->ext_status); + debug ("ext_status = %x, speed = %x\n", slot_cur->ext_status, speed); + switch (speed) { + case HPC_SLOT_SPEED_33: + cmd = HPC_BUS_33CONVMODE; + break; + case HPC_SLOT_SPEED_66: + if (SLOT_PCIX (slot_cur->ext_status)) + cmd = HPC_BUS_66PCIXMODE; + else + cmd = HPC_BUS_66CONVMODE; + break; + case HPC_SLOT_SPEED_133: + if (slot_cur->bus_on->slot_count > 1) + cmd = HPC_BUS_100PCIXMODE; + else + cmd = HPC_BUS_133PCIXMODE; + break; + default: + err ("wrong slot speed \n"); + return -ENODEV; + } + debug ("setting bus speed for slot %d, cmd %x\n", slot_cur->number, cmd); + rc = ibmphp_hpc_writeslot (slot_cur, cmd); + if (rc) + return rc; + } + debug ("%s -Exit \n", __FUNCTION__); + return 0; +} + +static inline void print_card_capability (struct slot *slot_cur) +{ + info ("capability of the card is "); + if ((slot_cur->ext_status & CARD_INFO) == PCIX133) + info (" 133 MHz PCI-X \n"); + else if ((slot_cur->ext_status & CARD_INFO) == PCIX66) + info (" 66 MHz PCI-X \n"); + else if ((slot_cur->ext_status & CARD_INFO) == PCI66) + info (" 66 MHz PCI \n"); + else + info (" 33 MHz PCI \n"); + +} + +/* This routine will power on the slot, configure the device(s) and find the + * drivers for them. + * Parameters: hotplug_slot + * Returns: 0 or failure codes + */ +static int enable_slot (struct hotplug_slot *hs) +{ + int rc, i, rcpr; + struct slot *slot_cur; + u8 function; + u8 faulted = 0; + struct pci_func *tmp_func; + + ibmphp_lock_operations (); + + debug ("ENABLING SLOT........ \n"); + slot_cur = (struct slot *) hs->private; + + if ((rc = validate (slot_cur, ENABLE))) { + err ("validate function failed \n"); + attn_off (slot_cur); /* need to turn off if was blinking b4 */ + attn_on (slot_cur); + rc = slot_update (&slot_cur); + if (rc) { + ibmphp_unlock_operations(); + return rc; + } + ibmphp_update_slot_info (slot_cur); + ibmphp_unlock_operations (); + return rc; + } + + attn_LED_blink (slot_cur); + + rc = set_bus (slot_cur); + if (rc) { + err ("was not able to set the bus \n"); + attn_off (slot_cur); + attn_on (slot_cur); + ibmphp_unlock_operations (); + return -ENODEV; + } + + rc = power_on (slot_cur); + + if (rc) { + err ("something wrong when powering up... please see below for details\n"); + /* need to turn off before on, otherwise, blinking overwrites */ + attn_off(slot_cur); + attn_on (slot_cur); + if (slot_update (&slot_cur)) { + attn_off (slot_cur); + attn_on (slot_cur); + ibmphp_unlock_operations (); + return -ENODEV; + } + /* Check to see the error of why it failed */ + if (!(SLOT_PWRGD (slot_cur->status))) + err ("power fault occured trying to power up \n"); + else if (SLOT_BUS_SPEED (slot_cur->status)) { + err ("bus speed mismatch occured. please check current bus speed and card capability \n"); + print_card_capability (slot_cur); + } else if (SLOT_BUS_MODE (slot_cur->ext_status)) + err ("bus mode mismatch occured. please check current bus mode and card capability \n"); + + ibmphp_update_slot_info (slot_cur); + ibmphp_unlock_operations (); + return rc; + } + debug ("after power_on\n"); + + rc = slot_update (&slot_cur); + if (rc) { + attn_off (slot_cur); + attn_on (slot_cur); + rcpr = power_off (slot_cur); + if (rcpr) { + ibmphp_unlock_operations (); + return rcpr; + } + ibmphp_unlock_operations (); + return rc; + } + + if (SLOT_POWER (slot_cur->status) && !(SLOT_PWRGD (slot_cur->status))) { + faulted = 1; + err ("power fault occured trying to power up...\n"); + } else if (SLOT_POWER (slot_cur->status) && (SLOT_BUS_SPEED (slot_cur->status))) { + faulted = 1; + err ("bus speed mismatch occured. please check current bus speed and card capability \n"); + print_card_capability (slot_cur); + } + /* Don't think this case will happen after above checks... but just in case, for paranoia sake */ + else if (!(SLOT_POWER (slot_cur->status))) { + err ("power on failed... \n"); + faulted = 1; + } + if (faulted) { + attn_off (slot_cur); /* need to turn off b4 on */ + attn_on (slot_cur); + rcpr = power_off (slot_cur); + if (rcpr) { + ibmphp_unlock_operations (); + return rcpr; + } + + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations (); + return -ENODEV; + } + ibmphp_update_slot_info (slot_cur); + ibmphp_unlock_operations (); + return -EINVAL; + } + + slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!slot_cur->func) { /* We cannot do update_slot_info here, since no memory for kmalloc n.e.ways, and update_slot_info allocates some */ + err ("out of system memory \n"); + attn_off (slot_cur); + attn_on (slot_cur); + rcpr = power_off (slot_cur); + if (rcpr) { + ibmphp_unlock_operations (); + return rcpr; + } + ibmphp_unlock_operations (); + return -ENOMEM; + } + memset (slot_cur->func, 0, sizeof (struct pci_func)); + slot_cur->func->busno = slot_cur->bus; + slot_cur->func->device = slot_cur->device; + for (i = 0; i < 4; i++) + slot_cur->func->irq[i] = slot_cur->irq[i]; + + debug ("b4 configure_card, slot_cur->bus = %x, slot_cur->device = %x\n", slot_cur->bus, slot_cur->device); + + if (ibmphp_configure_card (slot_cur->func, slot_cur->number)) { + err ("configure_card was unsuccessful... \n"); + ibmphp_unconfigure_card (&slot_cur, 1); /* true because don't need to actually deallocate resources, just remove references */ + debug ("after unconfigure_card\n"); + slot_cur->func = NULL; + attn_off (slot_cur); /* need to turn off in case was blinking */ + attn_on (slot_cur); + rcpr = power_off (slot_cur); + if (rcpr) { + ibmphp_unlock_operations (); + return rcpr; + } + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations(); + return -ENODEV; + } + ibmphp_update_slot_info (slot_cur); + ibmphp_unlock_operations (); + return -ENOMEM; + } + function = 0x00; + do { + tmp_func = ibm_slot_find (slot_cur->bus, slot_cur->func->device, function++); + if (tmp_func && !(tmp_func->dev)) + ibm_configure_device (tmp_func); + } while (tmp_func); + + attn_off (slot_cur); + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations (); + return -EFAULT; + } + ibmphp_print_test (); + rc = ibmphp_update_slot_info (slot_cur); + ibmphp_unlock_operations(); + return rc; +} + +/************************************************************** +* HOT REMOVING ADAPTER CARD * +* INPUT: POINTER TO THE HOTPLUG SLOT STRUCTURE * +* OUTPUT: SUCCESS 0 ; FAILURE: UNCONFIGURE , VALIDATE * + DISABLE POWER , * +**************************************************************/ +int ibmphp_disable_slot (struct hotplug_slot *hotplug_slot) +{ + int rc; + struct slot *slot_cur = (struct slot *) hotplug_slot->private; + u8 flag = slot_cur->flag; + + slot_cur->flag = TRUE; + debug ("DISABLING SLOT... \n"); + + ibmphp_lock_operations (); + if (slot_cur == NULL) { + ibmphp_unlock_operations (); + return -ENODEV; + } + if (slot_cur->ctrl == NULL) { + ibmphp_unlock_operations (); + return -ENODEV; + } + if (flag == TRUE) { + rc = validate (slot_cur, DISABLE); /* checking if powered off already & valid slot # */ + if (rc) { + /* Need to turn off if was blinking b4 */ + attn_off (slot_cur); + attn_on (slot_cur); + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations (); + return -EFAULT; + } + + ibmphp_update_slot_info (slot_cur); + ibmphp_unlock_operations (); + return rc; + } + } + attn_LED_blink (slot_cur); + + if (slot_cur->func == NULL) { + /* We need this for fncs's that were there on bootup */ + slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!slot_cur->func) { + err ("out of system memory \n"); + attn_off (slot_cur); + attn_on (slot_cur); + ibmphp_unlock_operations (); + return -ENOMEM; + } + memset (slot_cur->func, 0, sizeof (struct pci_func)); + slot_cur->func->busno = slot_cur->bus; + slot_cur->func->device = slot_cur->device; + } + + if ((rc = ibm_unconfigure_device (slot_cur->func))) { + err ("removing from kernel failed... \n"); + err ("Please check to see if it was statically linked or is in use otherwise. (perhaps the driver is not 'hot-removable')\n"); + attn_off (slot_cur); + attn_on (slot_cur); + ibmphp_unlock_operations (); + return rc; + } + + rc = ibmphp_unconfigure_card (&slot_cur, 0); + slot_cur->func = NULL; + debug ("in disable_slot. after unconfigure_card \n"); + if (rc) { + err ("could not unconfigure card.\n"); + attn_off (slot_cur); /* need to turn off if was blinking b4 */ + attn_on (slot_cur); + + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations (); + return -EFAULT; + } + + if (flag) + ibmphp_update_slot_info (slot_cur); + + ibmphp_unlock_operations (); + return -EFAULT; + } + + rc = ibmphp_hpc_writeslot (hotplug_slot->private, HPC_SLOT_OFF); + if (rc) { + attn_off (slot_cur); + attn_on (slot_cur); + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations (); + return -EFAULT; + } + + if (flag) + ibmphp_update_slot_info (slot_cur); + + ibmphp_unlock_operations (); + return rc; + } + + attn_off (slot_cur); + if (slot_update (&slot_cur)) { + ibmphp_unlock_operations (); + return -EFAULT; + } + if (flag) + rc = ibmphp_update_slot_info (slot_cur); + else + rc = 0; + + ibmphp_print_test (); + ibmphp_unlock_operations(); + return rc; +} + +struct hotplug_slot_ops ibmphp_hotplug_slot_ops = { + owner: THIS_MODULE, + set_attention_status: set_attention_status, + enable_slot: enable_slot, + disable_slot: ibmphp_disable_slot, + hardware_test: NULL, + get_power_status: get_power_status, + get_attention_status: get_attention_status, + get_latch_status: get_latch_status, + get_adapter_status: get_adapter_present, +/* get_max_bus_speed_status: get_max_bus_speed, + get_max_adapter_speed_status: get_max_adapter_speed, + get_cur_bus_speed_status: get_cur_bus_speed, + get_card_bus_names_status: get_card_bus_names, +*/ +}; + +static void ibmphp_unload (void) +{ + free_slots (); + debug ("after slots \n"); + ibmphp_free_resources (); + debug ("after resources \n"); + ibmphp_free_bus_info_queue (); + debug ("after bus info \n"); + ibmphp_free_ebda_hpc_queue (); + debug ("after ebda hpc \n"); + ibmphp_free_ebda_pci_rsrc_queue (); + debug ("after ebda pci rsrc \n"); +} + +static int __init ibmphp_init (void) +{ + int i = 0; + int rc = 0; + + init_flag = 1; + ibmphp_pci_root_ops = get_root_pci_ops (); + if (ibmphp_pci_root_ops == NULL) { + err ("cannot read bus operations... will not be able to read the cards. Please check your system \n"); + return -ENODEV; + } + + ibmphp_debug = debug; + + ibmphp_hpc_initvars (); + + for (i = 0; i < 16; i++) + irqs[i] = 0; + + if ((rc = ibmphp_access_ebda ())) { + ibmphp_unload (); + return rc; + } + debug ("after ibmphp_access_ebda () \n"); + + if ((rc = ibmphp_rsrc_init ())) { + ibmphp_unload (); + return rc; + } + debug ("AFTER Resource & EBDA INITIALIZATIONS \n"); + + max_slots = get_max_slots (); + + if (init_ops ()) { + ibmphp_unload (); + return -ENODEV; + } + ibmphp_print_test (); + if ((rc = ibmphp_hpc_start_poll_thread ())) { + ibmphp_unload (); + return -ENODEV; + } + + /* lock ourselves into memory with a module count of -1 + * so that no one can unload us. */ + MOD_DEC_USE_COUNT; + + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + + return 0; +} + +static void __exit ibmphp_exit (void) +{ + ibmphp_hpc_stop_poll_thread (); + debug ("after polling \n"); + ibmphp_unload (); + debug ("done \n"); +} + +module_init (ibmphp_init); +module_exit (ibmphp_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/ibmphp_ebda.c linux-2.5/drivers/hotplug/ibmphp_ebda.c --- linux-2.5.5/drivers/hotplug/ibmphp_ebda.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/hotplug/ibmphp_ebda.c Fri Mar 1 15:07:37 2002 @@ -0,0 +1,851 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Tong Yu, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ibmphp.h" + +/* + * POST builds data blocks(in this data block definition, a char-1 + * byte, short(or word)-2 byte, long(dword)-4 byte) in the Extended + * BIOS Data Area which describe the configuration of the hot-plug + * controllers and resources used by the PCI Hot-Plug devices. + * + * This file walks EBDA, maps data block from physical addr, + * reconstruct linked lists about all system resource(MEM, PFM, IO) + * already assigned by POST, as well as linked lists about hot plug + * controllers (ctlr#, slot#, bus&slot features...) + */ + +/* Global lists */ +LIST_HEAD (ibmphp_ebda_pci_rsrc_head); +LIST_HEAD (ibmphp_slot_head); + +/* Local variables */ +static struct ebda_hpc_list *hpc_list_ptr; +static struct ebda_rsrc_list *rsrc_list_ptr; +static struct rio_table_hdr *rio_table_ptr; +static LIST_HEAD (ebda_hpc_head); +static LIST_HEAD (bus_info_head); +static void *io_mem; + +/* Local functions */ +static int ebda_rsrc_controller (void); +static int ebda_rsrc_rsrc (void); +static int ebda_rio_table (void); + +static struct slot *alloc_ibm_slot (void) +{ + struct slot *slot; + + slot = kmalloc (sizeof (struct slot), GFP_KERNEL); + if (!slot) + return NULL; + memset (slot, 0, sizeof (*slot)); + return slot; +} + +static struct ebda_hpc_list *alloc_ebda_hpc_list (void) +{ + struct ebda_hpc_list *list; + + list = kmalloc (sizeof (struct ebda_hpc_list), GFP_KERNEL); + if (!list) + return NULL; + memset (list, 0, sizeof (*list)); + return list; +} + +static struct controller *alloc_ebda_hpc (u32 slot_count, u32 bus_count) +{ + struct controller *controller; + struct ebda_hpc_slot *slots; + struct ebda_hpc_bus *buses; + + controller = kmalloc (sizeof (struct controller), GFP_KERNEL); + if (!controller) + return NULL; + memset (controller, 0, sizeof (*controller)); + + slots = kmalloc (sizeof (struct ebda_hpc_slot) * slot_count, GFP_KERNEL); + if (!slots) { + kfree (controller); + return NULL; + } + memset (slots, 0, sizeof (*slots) * slot_count); + controller->slots = slots; + + buses = kmalloc (sizeof (struct ebda_hpc_bus) * bus_count, GFP_KERNEL); + if (!buses) { + kfree (controller->slots); + kfree (controller); + return NULL; + } + memset (buses, 0, sizeof (*buses) * bus_count); + controller->buses = buses; + + return controller; +} + +static void free_ebda_hpc (struct controller *controller) +{ + kfree (controller->slots); + controller->slots = NULL; + kfree (controller->buses); + controller->buses = NULL; + kfree (controller); +} + +static struct ebda_rsrc_list *alloc_ebda_rsrc_list (void) +{ + struct ebda_rsrc_list *list; + + list = kmalloc (sizeof (struct ebda_rsrc_list), GFP_KERNEL); + if (!list) + return NULL; + memset (list, 0, sizeof (*list)); + return list; +} + +static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void) +{ + struct ebda_pci_rsrc *resource; + + resource = kmalloc (sizeof (struct ebda_pci_rsrc), GFP_KERNEL); + if (!resource) + return NULL; + memset (resource, 0, sizeof (*resource)); + return resource; +} + +static void print_bus_info (void) +{ + struct bus_info *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &bus_info_head) { + ptr = list_entry (ptr1, struct bus_info, bus_info_list); + debug ("%s - slot_min = %x\n", __FUNCTION__, ptr->slot_min); + debug ("%s - slot_max = %x\n", __FUNCTION__, ptr->slot_max); + debug ("%s - slot_count = %x\n", __FUNCTION__, ptr->slot_count); + debug ("%s - bus# = %x\n", __FUNCTION__, ptr->busno); + debug ("%s - current_speed = %x\n", __FUNCTION__, ptr->current_speed); + debug ("%s - supported_speed = %x\n", __FUNCTION__, ptr->supported_speed); + debug ("%s - controller_id = %x\n", __FUNCTION__, ptr->controller_id); + debug ("%s - bus_mode = %x\n", __FUNCTION__, ptr->supported_bus_mode); + } +} + +static void print_ebda_pci_rsrc (void) +{ + struct ebda_pci_rsrc *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &ibmphp_ebda_pci_rsrc_head) { + ptr = list_entry (ptr1, struct ebda_pci_rsrc, ebda_pci_rsrc_list); + debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n", + __FUNCTION__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr); + } +} + +static void print_ebda_hpc (void) +{ + struct controller *hpc_ptr; + struct list_head *ptr1; + u16 index; + + list_for_each (ptr1, &ebda_hpc_head) { + + hpc_ptr = list_entry (ptr1, struct controller, ebda_hpc_list); + + for (index = 0; index < hpc_ptr->slot_count; index++) { + debug ("%s - physical slot#: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_num); + debug ("%s - pci bus# of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_bus_num); + debug ("%s - index into ctlr addr: %x\n", __FUNCTION__, hpc_ptr->slots[index].ctl_index); + debug ("%s - cap of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_cap); + } + + for (index = 0; index < hpc_ptr->bus_count; index++) { + debug ("%s - bus# of each bus controlled by this ctlr: %x\n", __FUNCTION__, hpc_ptr->buses[index].bus_num); + } + + debug ("%s - type of hpc: %x\n", __FUNCTION__, hpc_ptr->ctlr_type); + switch (hpc_ptr->ctlr_type) { + case 1: + debug ("%s - bus: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.bus); + debug ("%s - dev_fun: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.dev_fun); + debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + break; + + case 0: + debug ("%s - io_start: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_start); + debug ("%s - io_end: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_end); + debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + break; + + case 2: + debug ("%s - wpegbbar: %lx\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.wpegbbar); + debug ("%s - i2c_addr: %x\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.i2c_addr); + debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + break; + } + } +} + +int ibmphp_access_ebda (void) +{ + u8 format, num_ctlrs, rio_complete, hs_complete; + u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, rc, re, rc_id, re_id, base; + + + rio_complete = 0; + hs_complete = 0; + + io_mem = ioremap ((0x40 << 4) + 0x0e, 2); + if (!io_mem ) + return -ENOMEM; + ebda_seg = readw (io_mem); + iounmap (io_mem); + debug ("returned ebda segment: %x\n", ebda_seg); + + io_mem = ioremap (ebda_seg<<4, 65000); + if (!io_mem ) + return -ENOMEM; + next_offset = 0x180; + + for (;;) { + offset = next_offset; + next_offset = readw (io_mem + offset); /* offset of next blk */ + + offset += 2; + if (next_offset == 0) /* 0 indicate it's last blk */ + break; + blk_id = readw (io_mem + offset); /* this blk id */ + + offset += 2; + /* check if it is hot swap block or rio block */ + if (blk_id != 0x4853 && blk_id != 0x4752) + continue; + /* found hs table */ + if (blk_id == 0x4853) { + debug ("now enter hot swap block---\n"); + debug ("hot blk id: %x\n", blk_id); + format = readb (io_mem + offset); + + offset += 1; + if (format != 4) { + iounmap (io_mem); + return -ENODEV; + } + debug ("hot blk format: %x\n", format); + /* hot swap sub blk */ + base = offset; + + sub_addr = base; + re = readw (io_mem + sub_addr); /* next sub blk */ + + sub_addr += 2; + rc_id = readw (io_mem + sub_addr); /* sub blk id */ + + sub_addr += 2; + if (rc_id != 0x5243) { + iounmap (io_mem); + return -ENODEV; + } + /* rc sub blk signature */ + num_ctlrs = readb (io_mem + sub_addr); + + sub_addr += 1; + hpc_list_ptr = alloc_ebda_hpc_list (); + if (!hpc_list_ptr) { + iounmap (io_mem); + return -ENOMEM; + } + hpc_list_ptr->format = format; + hpc_list_ptr->num_ctlrs = num_ctlrs; + hpc_list_ptr->phys_addr = sub_addr; /* offset of RSRC_CONTROLLER blk */ + debug ("info about hpc descriptor---\n"); + debug ("hot blk format: %x\n", format); + debug ("num of controller: %x\n", num_ctlrs); + debug ("offset of hpc data structure enteries: %x\n ", sub_addr); + + sub_addr = base + re; /* re sub blk */ + rc = readw (io_mem + sub_addr); /* next sub blk */ + + sub_addr += 2; + re_id = readw (io_mem + sub_addr); /* sub blk id */ + + sub_addr += 2; + if (re_id != 0x5245) { + iounmap (io_mem); + return -ENODEV; + } + + /* signature of re */ + num_entries = readw (io_mem + sub_addr); + + sub_addr += 2; /* offset of RSRC_ENTRIES blk */ + rsrc_list_ptr = alloc_ebda_rsrc_list (); + if (!rsrc_list_ptr ) { + iounmap (io_mem); + return -ENOMEM; + } + rsrc_list_ptr->format = format; + rsrc_list_ptr->num_entries = num_entries; + rsrc_list_ptr->phys_addr = sub_addr; + + debug ("info about rsrc descriptor---\n"); + debug ("format: %x\n", format); + debug ("num of rsrc: %x\n", num_entries); + debug ("offset of rsrc data structure enteries: %x\n ", sub_addr); + + hs_complete = 1; + } + /* found rio table */ + else if (blk_id == 0x4752) { + debug ("now enter io table ---\n"); + debug ("rio blk id: %x\n", blk_id); + + rio_table_ptr = kmalloc (sizeof (struct rio_table_hdr), GFP_KERNEL); + if (!rio_table_ptr) + return -ENOMEM; + memset (rio_table_ptr, 0, sizeof (struct rio_table_hdr) ); + rio_table_ptr->ver_num = readb (io_mem + offset); + rio_table_ptr->scal_count = readb (io_mem + offset + 1); + rio_table_ptr->riodev_count = readb (io_mem + offset + 2); + rio_table_ptr->offset = offset +3 ; + + debug ("info about rio table hdr ---\n"); + debug ("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ", rio_table_ptr->ver_num, rio_table_ptr->scal_count, rio_table_ptr->riodev_count, rio_table_ptr->offset); + + rio_complete = 1; + } + + if (hs_complete && rio_complete) { + rc = ebda_rsrc_controller (); + if (rc) { + iounmap(io_mem); + return rc; + } + rc = ebda_rsrc_rsrc (); + if (rc) { + iounmap(io_mem); + return rc; + } + rc = ebda_rio_table (); + if (rc) { + iounmap(io_mem); + return rc; + } + iounmap (io_mem); + return 0; + } + } + iounmap (io_mem); + return -ENODEV; +} + + +/* + * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of + * each hpc from physical address to a list of hot plug controllers based on + * hpc descriptors. + */ +static int ebda_rsrc_controller (void) +{ + u16 addr, addr_slot, addr_bus; + u8 ctlr_id, temp, bus_index; + u16 ctlr, slot, bus; + u16 slot_num, bus_num, index; + struct hotplug_slot *hp_slot_ptr; + struct controller *hpc_ptr; + struct ebda_hpc_bus *bus_ptr; + struct ebda_hpc_slot *slot_ptr; + struct bus_info *bus_info_ptr1, *bus_info_ptr2; + int rc; + + addr = hpc_list_ptr->phys_addr; + for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) { + bus_index = 1; + ctlr_id = readb (io_mem + addr); + addr += 1; + slot_num = readb (io_mem + addr); + + addr += 1; + addr_slot = addr; /* offset of slot structure */ + addr += (slot_num * 4); + + bus_num = readb (io_mem + addr); + + addr += 1; + addr_bus = addr; /* offset of bus */ + addr += (bus_num * 9); /* offset of ctlr_type */ + temp = readb (io_mem + addr); + + addr += 1; + /* init hpc structure */ + hpc_ptr = alloc_ebda_hpc (slot_num, bus_num); + if (!hpc_ptr ) { + iounmap (io_mem); + return -ENOMEM; + } + hpc_ptr->ctlr_id = ctlr_id; + hpc_ptr->ctlr_relative_id = ctlr; + hpc_ptr->slot_count = slot_num; + hpc_ptr->bus_count = bus_num; + debug ("now enter ctlr data struture ---\n"); + debug ("ctlr id: %x\n", ctlr_id); + debug ("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id); + debug ("count of slots controlled by this ctlr: %x\n", slot_num); + debug ("count of buses controlled by this ctlr: %x\n", bus_num); + + /* init slot structure, fetch slot, bus, cap... */ + slot_ptr = hpc_ptr->slots; + for (slot = 0; slot < slot_num; slot++) { + slot_ptr->slot_num = readb (io_mem + addr_slot); + slot_ptr->slot_bus_num = readb (io_mem + addr_slot + slot_num); + slot_ptr->ctl_index = readb (io_mem + addr_slot + 2*slot_num); + slot_ptr->slot_cap = readb (io_mem + addr_slot + 3*slot_num); + + // create bus_info lined list --- if only one slot per bus: slot_min = slot_max + + bus_info_ptr2 = ibmphp_find_same_bus_num (slot_ptr->slot_bus_num); + if (!bus_info_ptr2) { + bus_info_ptr1 = (struct bus_info *) kmalloc (sizeof (struct bus_info), GFP_KERNEL); + if (!bus_info_ptr1) { + iounmap (io_mem); + return -ENOMEM; + } + memset (bus_info_ptr1, 0, sizeof (struct bus_info)); + bus_info_ptr1->slot_min = slot_ptr->slot_num; + bus_info_ptr1->slot_max = slot_ptr->slot_num; + bus_info_ptr1->slot_count += 1; + bus_info_ptr1->busno = slot_ptr->slot_bus_num; + bus_info_ptr1->index = bus_index++; + bus_info_ptr1->current_speed = 0xff; + bus_info_ptr1->current_bus_mode = 0xff; + if ( ((slot_ptr->slot_cap) & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX ) + bus_info_ptr1->supported_speed = 3; + else if ( ((slot_ptr->slot_cap) & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX ) + bus_info_ptr1->supported_speed = 2; + else if ( ((slot_ptr->slot_cap) & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX ) + bus_info_ptr1->supported_speed = 1; + bus_info_ptr1->controller_id = hpc_ptr->ctlr_id; + if ( ((slot_ptr->slot_cap) & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP ) + bus_info_ptr1->supported_bus_mode = 1; + else + bus_info_ptr1->supported_bus_mode =0; + + + list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head); + + } else { + bus_info_ptr2->slot_min = min (bus_info_ptr2->slot_min, slot_ptr->slot_num); + bus_info_ptr2->slot_max = max (bus_info_ptr2->slot_max, slot_ptr->slot_num); + bus_info_ptr2->slot_count += 1; + + } + + // end of creating the bus_info linked list + + slot_ptr++; + addr_slot += 1; + } + + /* init bus structure */ + bus_ptr = hpc_ptr->buses; + for (bus = 0; bus < bus_num; bus++) { + bus_ptr->bus_num = readb (io_mem + addr_bus); + bus_ptr++; + addr_bus += 1; + } + + hpc_ptr->ctlr_type = temp; + + switch (hpc_ptr->ctlr_type) { + case 1: + hpc_ptr->u.pci_ctlr.bus = readb (io_mem + addr); + hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1); + hpc_ptr->irq = readb (io_mem + addr + 2); + addr += 3; + break; + + case 0: + hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr); + hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2); + hpc_ptr->irq = readb (io_mem + addr + 4); + addr += 5; + break; + + case 2: + hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr); + hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4); + /* following 2 lines for testing purpose */ + if (hpc_ptr->u.wpeg_ctlr.i2c_addr == 0) + hpc_ptr->ctlr_type = 4; + + + hpc_ptr->irq = readb (io_mem + addr + 5); + addr += 6; + break; + case 4: + hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr); + hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4); + hpc_ptr->irq = readb (io_mem + addr + 5); + addr += 6; + break; + default: + iounmap (io_mem); + return -ENODEV; + } + /* following 3 line: Now our driver only supports I2c ctlrType */ + if ((hpc_ptr->ctlr_type != 2) && (hpc_ptr->ctlr_type != 4)) { + err ("Please run this driver on ibm xseries440\n "); + return -ENODEV; + } + + hpc_ptr->revision = 0xff; + hpc_ptr->options = 0xff; + + // register slots with hpc core as well as create linked list of ibm slot + for (index = 0; index < hpc_ptr->slot_count; index++) { + + hp_slot_ptr = (struct hotplug_slot *) kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!hp_slot_ptr) { + iounmap (io_mem); + return -ENOMEM; + } + memset (hp_slot_ptr, 0, sizeof (struct hotplug_slot)); + + hp_slot_ptr->info = (struct hotplug_slot_info *) kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!hp_slot_ptr->info) { + iounmap (io_mem); + kfree (hp_slot_ptr); + return -ENOMEM; + } + memset (hp_slot_ptr->info, 0, sizeof (struct hotplug_slot_info)); + + hp_slot_ptr->name = (char *) kmalloc (10, GFP_KERNEL); + if (!hp_slot_ptr->name) { + iounmap (io_mem); + kfree (hp_slot_ptr->info); + kfree (hp_slot_ptr); + return -ENOMEM; + } + + hp_slot_ptr->private = alloc_ibm_slot (); + if (!hp_slot_ptr->private) { + iounmap (io_mem); + kfree (hp_slot_ptr->name); + kfree (hp_slot_ptr->info); + kfree (hp_slot_ptr); + return -ENOMEM; + } + + ((struct slot *)hp_slot_ptr->private)->flag = TRUE; + snprintf (hp_slot_ptr->name, 10, "%d", hpc_ptr->slots[index].slot_num); + + ((struct slot *) hp_slot_ptr->private)->capabilities = hpc_ptr->slots[index].slot_cap; + ((struct slot *) hp_slot_ptr->private)->bus = hpc_ptr->slots[index].slot_bus_num; + + bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num); + if (!bus_info_ptr1) { + iounmap (io_mem); + return -ENODEV; + } + ((struct slot *) hp_slot_ptr->private)->bus_on = bus_info_ptr1; + bus_info_ptr1 = NULL; + ((struct slot *) hp_slot_ptr->private)->ctrl = hpc_ptr; + + + ((struct slot *) hp_slot_ptr->private)->ctlr_index = hpc_ptr->slots[index].ctl_index; + ((struct slot *) hp_slot_ptr->private)->number = hpc_ptr->slots[index].slot_num; + + ((struct slot *) hp_slot_ptr->private)->hotplug_slot = hp_slot_ptr; + + rc = ibmphp_hpc_fillhpslotinfo (hp_slot_ptr); + if (rc) { + iounmap (io_mem); + return rc; + } + + rc = ibmphp_init_devno ((struct slot **) &hp_slot_ptr->private); + if (rc) { + iounmap (io_mem); + return rc; + } + hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops; + + pci_hp_register (hp_slot_ptr); + + // end of registering ibm slot with hotplug core + + list_add (& ((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head); + } + + print_bus_info (); + list_add (&hpc_ptr->ebda_hpc_list, &ebda_hpc_head ); + + } /* each hpc */ + print_ebda_hpc (); + return 0; +} + +/* + * map info (bus, devfun, start addr, end addr..) of i/o, memory, + * pfm from the physical addr to a list of resource. + */ +static int ebda_rsrc_rsrc (void) +{ + u16 addr; + short rsrc; + u8 type, rsrc_type; + struct ebda_pci_rsrc *rsrc_ptr; + + addr = rsrc_list_ptr->phys_addr; + debug ("now entering rsrc land\n"); + debug ("offset of rsrc: %x\n", rsrc_list_ptr->phys_addr); + + for (rsrc = 0; rsrc < rsrc_list_ptr->num_entries; rsrc++) { + type = readb (io_mem + addr); + + addr += 1; + rsrc_type = type & EBDA_RSRC_TYPE_MASK; + + if (rsrc_type == EBDA_IO_RSRC_TYPE) { + rsrc_ptr = alloc_ebda_pci_rsrc (); + if (!rsrc_ptr) { + iounmap (io_mem); + return -ENOMEM; + } + rsrc_ptr->rsrc_type = type; + + rsrc_ptr->bus_num = readb (io_mem + addr); + rsrc_ptr->dev_fun = readb (io_mem + addr + 1); + rsrc_ptr->start_addr = readw (io_mem + addr + 2); + rsrc_ptr->end_addr = readw (io_mem + addr + 4); + addr += 6; + + debug ("rsrc from io type ----\n"); + debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n", + rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr); + + list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head); + } + + if (rsrc_type == EBDA_MEM_RSRC_TYPE || rsrc_type == EBDA_PFM_RSRC_TYPE) { + rsrc_ptr = alloc_ebda_pci_rsrc (); + if (!rsrc_ptr ) { + iounmap (io_mem); + return -ENOMEM; + } + rsrc_ptr->rsrc_type = type; + + rsrc_ptr->bus_num = readb (io_mem + addr); + rsrc_ptr->dev_fun = readb (io_mem + addr + 1); + rsrc_ptr->start_addr = readl (io_mem + addr + 2); + rsrc_ptr->end_addr = readl (io_mem + addr + 6); + addr += 10; + + debug ("rsrc from mem or pfm ---\n"); + debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n", + rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr); + + list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head); + } + } + kfree (rsrc_list_ptr); + rsrc_list_ptr = NULL; + print_ebda_pci_rsrc (); + return 0; +} + +/* + * map info of scalability details and rio details from physical address + */ +static int ebda_rio_table(void) +{ + u16 offset; + u8 i; + struct scal_detail *scal_detail_ptr; + struct rio_detail *rio_detail_ptr; + + offset = rio_table_ptr->offset; + for (i = 0; i < rio_table_ptr->scal_count; i++) { + + scal_detail_ptr = kmalloc (sizeof (struct scal_detail), GFP_KERNEL ); + if (!scal_detail_ptr ) + return -ENOMEM; + memset (scal_detail_ptr, 0, sizeof (struct scal_detail) ); + scal_detail_ptr->node_id = readb (io_mem + offset); + scal_detail_ptr->cbar = readl (io_mem+ offset + 1); + scal_detail_ptr->port0_node_connect = readb (io_mem + 5); + scal_detail_ptr->port0_port_connect = readb (io_mem + 6); + scal_detail_ptr->port1_node_connect = readb (io_mem + 7); + scal_detail_ptr->port1_port_connect = readb (io_mem + 8); + scal_detail_ptr->port2_node_connect = readb (io_mem + 9); + scal_detail_ptr->port2_port_connect = readb (io_mem + 10); + debug ("node_id: %x\ncbar: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nport2_node: %x\nport2_port: %x\n", scal_detail_ptr->node_id, scal_detail_ptr->cbar, scal_detail_ptr->port0_node_connect, scal_detail_ptr->port0_port_connect, scal_detail_ptr->port1_node_connect, scal_detail_ptr->port1_port_connect, scal_detail_ptr->port2_node_connect, scal_detail_ptr->port2_port_connect); +// list_add (&scal_detail_ptr->scal_detail_list, &scal_detail_head); + offset += 11; + } + for (i=0; i < rio_table_ptr->riodev_count; i++) { + rio_detail_ptr = kmalloc (sizeof (struct rio_detail), GFP_KERNEL ); + if (!rio_detail_ptr ) + return -ENOMEM; + memset (rio_detail_ptr, 0, sizeof (struct rio_detail) ); + rio_detail_ptr->rio_node_id = readb (io_mem + offset ); + rio_detail_ptr->bbar = readl (io_mem + offset + 1); + rio_detail_ptr->rio_type = readb (io_mem + offset + 5); + rio_detail_ptr->owner_id = readb (io_mem + offset + 6); + rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7); + rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8); + rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9); + rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10); + rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11); + rio_detail_ptr->status = readb (io_mem + offset + 12); + debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status); + offset += 13; + } + return 0; +} + +u16 ibmphp_get_total_controllers (void) +{ + return hpc_list_ptr->num_ctlrs; +} + +struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num) +{ + struct slot *slot; + struct list_head *list; + + list_for_each (list, &ibmphp_slot_head) { + slot = list_entry (list, struct slot, ibm_slot_list); + if (slot->number == physical_num) + return slot; + } + return NULL; +} + +/* To find: + * - the smallest slot number + * - the largest slot number + * - the total number of the slots based on each bus + * (if only one slot per bus slot_min = slot_max ) + */ +struct bus_info *ibmphp_find_same_bus_num (u32 num) +{ + struct bus_info *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &bus_info_head) { + ptr = list_entry (ptr1, struct bus_info, bus_info_list); + if (ptr->busno == num) + return ptr; + } + return NULL; +} + +/* Finding relative bus number, in order to map corresponding + * bus register + */ +int ibmphp_get_bus_index (u8 num) +{ + struct bus_info *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &bus_info_head) { + ptr = list_entry (ptr1, struct bus_info, bus_info_list); + if (ptr->busno == num) + return ptr->index; + } + return -ENODEV; +} + +void ibmphp_free_bus_info_queue (void) +{ + struct bus_info *bus_info; + struct list_head *list; + struct list_head *next; + + list_for_each_safe (list, next, &bus_info_head ) { + bus_info = list_entry (list, struct bus_info, bus_info_list); + kfree (bus_info); + } +} + +/* + * Calculate the total hot pluggable slots controlled by total hpcs + */ +/* +int ibmphp_get_total_hp_slots (void) +{ + struct ebda_hpc *ptr; + int slot_num = 0; + + ptr = ebda_hpc_head; + while (ptr != NULL) { + slot_num += ptr->slot_count; + ptr = ptr->next; + } + return slot_num; +} +*/ + +void ibmphp_free_ebda_hpc_queue (void) +{ + struct controller *controller; + struct list_head *list; + struct list_head *next; + + list_for_each_safe (list, next, &ebda_hpc_head) { + controller = list_entry (list, struct controller, ebda_hpc_list); + free_ebda_hpc (controller); + } +} + +void ibmphp_free_ebda_pci_rsrc_queue (void) +{ + struct ebda_pci_rsrc *resource; + struct list_head *list; + struct list_head *next; + + list_for_each_safe (list, next, &ibmphp_ebda_pci_rsrc_head) { + resource = list_entry (list, struct ebda_pci_rsrc, ebda_pci_rsrc_list); + kfree (resource); + resource = NULL; + } +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/ibmphp_hpc.c linux-2.5/drivers/hotplug/ibmphp_hpc.c --- linux-2.5.5/drivers/hotplug/ibmphp_hpc.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/hotplug/ibmphp_hpc.c Fri Mar 1 15:07:37 2002 @@ -0,0 +1,1135 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Jyoti Shah, IBM Corporation + * + * Copyright (c) 2001,2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + * + */ + +//#include +#include +#include +#include +#include +#include +#include "ibmphp.h" + +#define POLL_NO 0x01 +#define POLL_YES 0x00 + +static int to_debug = FALSE; +#define debug_polling(fmt, arg...) do { if (to_debug) debug (fmt, arg); } while (0) + +//---------------------------------------------------------------------------- +// timeout values +//---------------------------------------------------------------------------- +#define CMD_COMPLETE_TOUT_SEC 60 // give HPC 60 sec to finish cmd +#define HPC_CTLR_WORKING_TOUT 60 // give HPC 60 sec to finish cmd +#define HPC_GETACCESS_TIMEOUT 60 // seconds +#define POLL_INTERVAL_SEC 2 // poll HPC every 2 seconds +#define POLL_LATCH_CNT 5 // poll latch 5 times, then poll slots + +//---------------------------------------------------------------------------- +// Winnipeg Architected Register Offsets +//---------------------------------------------------------------------------- +#define WPG_I2CMBUFL_OFFSET 0x08 // I2C Message Buffer Low +#define WPG_I2CMOSUP_OFFSET 0x10 // I2C Master Operation Setup Reg +#define WPG_I2CMCNTL_OFFSET 0x20 // I2C Master Control Register +#define WPG_I2CPARM_OFFSET 0x40 // I2C Parameter Register +#define WPG_I2CSTAT_OFFSET 0x70 // I2C Status Register + +//---------------------------------------------------------------------------- +// Winnipeg Store Type commands (Add this commands to the register offset) +//---------------------------------------------------------------------------- +#define WPG_I2C_AND 0x1000 // I2C AND operation +#define WPG_I2C_OR 0x2000 // I2C OR operation + +//---------------------------------------------------------------------------- +// Command set for I2C Master Operation Setup Regisetr +//---------------------------------------------------------------------------- +#define WPG_READATADDR_MASK 0x00010000 // read,bytes,I2C shifted,index +#define WPG_WRITEATADDR_MASK 0x40010000 // write,bytes,I2C shifted,index +#define WPG_READDIRECT_MASK 0x10010000 +#define WPG_WRITEDIRECT_MASK 0x60010000 + + +//---------------------------------------------------------------------------- +// bit masks for I2C Master Control Register +//---------------------------------------------------------------------------- +#define WPG_I2CMCNTL_STARTOP_MASK 0x00000002 // Start the Operation + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- +#define WPG_I2C_IOREMAP_SIZE 0x2044 // size of linear address interval +#define WPG_CTLR_MAX 0x01 // max controllers +#define WPG_SLOT_MAX 0x06 // max slots +#define WPG_CTLR_SLOT_MAX 0x06 // max slots per controller +#define WPG_FIRST_CTLR 0x00 // index of the controller + +//---------------------------------------------------------------------------- +// command index +//---------------------------------------------------------------------------- +#define WPG_1ST_SLOT_INDEX 0x01 // index - 1st slot for ctlr +#define WPG_CTLR_INDEX 0x0F // index - ctlr +#define WPG_1ST_EXTSLOT_INDEX 0x10 // index - 1st ext slot for ctlr +#define WPG_1ST_BUS_INDEX 0x1F // index - 1st bus for ctlr + +//---------------------------------------------------------------------------- +// macro utilities +//---------------------------------------------------------------------------- +// if bits 20,22,25,26,27,29,30 are OFF return TRUE +#define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? FALSE : TRUE)) + +// return code 0:poll slots, 1-POLL_LATCH_CNT:poll latch register +#define INCREMENT_POLLCNT(i) ((i < POLL_LATCH_CNT) ? i++ : (i=0)) +//---------------------------------------------------------------------------- +// global variables +//---------------------------------------------------------------------------- +static int ibmphp_shutdown; +static int tid_poll; +static int stop_polling; // 2 values: poll, don't poll +static struct semaphore sem_hpcaccess; // lock access to HPC +static struct semaphore semOperations; // lock all operations and + // access to data structures +static struct semaphore sem_exit; // make sure polling thread goes away +static struct semaphore sem_poll; // make sure poll is idle +//---------------------------------------------------------------------------- +// local function prototypes +//---------------------------------------------------------------------------- +static u8 ctrl_read (struct controller *, void *, u8); +static u8 ctrl_write (struct controller *, void *, u8, u8); +static u8 hpc_writecmdtoindex (u8, u8); +static u8 hpc_readcmdtoindex (u8, u8); +static void get_hpc_access (void); +static void free_hpc_access (void); +static void poll_hpc (void); +static int update_slot (struct slot *, u8); +static int process_changeinstatus (struct slot *, struct slot *); +static int process_changeinlatch (u8, u8); +static int hpc_poll_thread (void *); +static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *); +//---------------------------------------------------------------------------- + + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_initvars +* +* Action: initialize semaphores and variables +*---------------------------------------------------------------------*/ +void ibmphp_hpc_initvars (void) +{ + debug ("%s - Entry\n", __FUNCTION__); + + init_MUTEX (&sem_hpcaccess); + init_MUTEX (&semOperations); + init_MUTEX_LOCKED (&sem_exit); + init_MUTEX_LOCKED (&sem_poll); + stop_polling = POLL_YES; + to_debug = FALSE; + ibmphp_shutdown = FALSE; + tid_poll = 0; + + debug ("%s - Exit\n", __FUNCTION__); +} + +/*---------------------------------------------------------------------- +* Name: ctrl_read +* +* Action: read from HPC over I2C +* +*---------------------------------------------------------------------*/ +static u8 ctrl_read (struct controller *ctlr_ptr, void *WPGBbar, u8 index) +{ + u8 status; + int i; + void *wpg_addr; // base addr + offset + ulong wpg_data, // data to/from WPG LOHI format + ultemp, data; // actual data HILO format + + + debug_polling ("%s - Entry WPGBbar[%lx] index[%x] \n", __FUNCTION__, (ulong) WPGBbar, index); + + //-------------------------------------------------------------------- + // READ - step 1 + // read at address, byte length, I2C address (shifted), index + // or read direct, byte length, index + if (ctlr_ptr->ctlr_type == 0x02) { + data = WPG_READATADDR_MASK; + // fill in I2C address + ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr; + ultemp = ultemp >> 1; + data |= (ultemp << 8); + + // fill in index + data |= (ulong) index; + } else if (ctlr_ptr->ctlr_type == 0x04) { + data = WPG_READDIRECT_MASK; + + // fill in index + ultemp = (ulong) index; + ultemp = ultemp << 8; + data |= ultemp; + } else { + err ("this controller type is not supported \n"); + return HPC_ERROR; + } + + wpg_data = swab32 (data); // swap data before writing + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // READ - step 2 : clear the message buffer + data = 0x00000000; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // READ - step 3 : issue start operation, I2C master control bit 30:ON + // 2020 : [20] OR operation at [20] offset 0x20 + data = WPG_I2CMCNTL_STARTOP_MASK; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // READ - step 4 : wait until start operation bit clears + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) + break; + i--; + } + if (i == 0) { + debug ("%s - Error : WPG timeout\n", __FUNCTION__); + return HPC_ERROR; + } + //-------------------------------------------------------------------- + // READ - step 5 : read I2C status register + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (HPC_I2CSTATUS_CHECK (data)) + break; + i--; + } + if (i == 0) { + debug ("ctrl_read - Exit Error:I2C timeout\n"); + return HPC_ERROR; + } + + //-------------------------------------------------------------------- + // READ - step 6 : get DATA + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + + status = (u8) data; + + debug_polling ("%s - Exit index[%x] status[%x]\n", __FUNCTION__, index, status); + + return (status); +} + +/*---------------------------------------------------------------------- +* Name: ctrl_write +* +* Action: write to HPC over I2C +* +* Return 0 or error codes +*---------------------------------------------------------------------*/ +static u8 ctrl_write (struct controller *ctlr_ptr, void *WPGBbar, u8 index, u8 cmd) +{ + u8 rc; + void *wpg_addr; // base addr + offset + ulong wpg_data, // data to/from WPG LOHI format + ultemp, data; // actual data HILO format + int i; + + + debug_polling ("%s - Entry WPGBbar[%lx] index[%x] cmd[%x]\n", + __FUNCTION__, (ulong) WPGBbar, index, cmd); + + rc = 0; + //-------------------------------------------------------------------- + // WRITE - step 1 + // write at address, byte length, I2C address (shifted), index + // or write direct, byte length, index + data = 0x00000000; + + if (ctlr_ptr->ctlr_type == 0x02) { + data = WPG_WRITEATADDR_MASK; + // fill in I2C address + ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr; + ultemp = ultemp >> 1; + data |= (ultemp << 8); + + // fill in index + data |= (ulong) index; + } else if (ctlr_ptr->ctlr_type == 0x04) { + data = WPG_WRITEDIRECT_MASK; + + // fill in index + ultemp = (ulong) index; + ultemp = ultemp << 8; + data |= ultemp; + } else { + err ("this controller type is not supported \n"); + return HPC_ERROR; + } + + wpg_data = swab32 (data); // swap data before writing + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // WRITE - step 2 : clear the message buffer + data = 0x00000000 | (ulong) cmd; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // WRITE - step 3 : issue start operation,I2C master control bit 30:ON + // 2020 : [20] OR operation at [20] offset 0x20 + data = WPG_I2CMCNTL_STARTOP_MASK; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // WRITE - step 4 : wait until start operation bit clears + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) + break; + i--; + } + if (i == 0) { + debug ("%s - Exit Error:WPG timeout\n", __FUNCTION__); + rc = HPC_ERROR; + } + + //-------------------------------------------------------------------- + // WRITE - step 5 : read I2C status register + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (HPC_I2CSTATUS_CHECK (data)) + break; + i--; + } + if (i == 0) { + debug ("ctrl_read - Error : I2C timeout\n"); + rc = HPC_ERROR; + } + + debug_polling ("%s Exit rc[%x]\n", __FUNCTION__, rc); + return (rc); +} + +/*---------------------------------------------------------------------- +* Name: hpc_writecmdtoindex() +* +* Action: convert a write command to proper index within a controller +* +* Return index, HPC_ERROR +*---------------------------------------------------------------------*/ +static u8 hpc_writecmdtoindex (u8 cmd, u8 index) +{ + u8 rc; + + switch (cmd) { + case HPC_CTLR_ENABLEIRQ: // 0x00.N.15 + case HPC_CTLR_CLEARIRQ: // 0x06.N.15 + case HPC_CTLR_RESET: // 0x07.N.15 + case HPC_CTLR_IRQSTEER: // 0x08.N.15 + case HPC_CTLR_DISABLEIRQ: // 0x01.N.15 + case HPC_ALLSLOT_ON: // 0x11.N.15 + case HPC_ALLSLOT_OFF: // 0x12.N.15 + rc = 0x0F; + break; + + case HPC_SLOT_OFF: // 0x02.Y.0-14 + case HPC_SLOT_ON: // 0x03.Y.0-14 + case HPC_SLOT_ATTNOFF: // 0x04.N.0-14 + case HPC_SLOT_ATTNON: // 0x05.N.0-14 + case HPC_SLOT_BLINKLED: // 0x13.N.0-14 + rc = index; + break; + + case HPC_BUS_33CONVMODE: + case HPC_BUS_66CONVMODE: + case HPC_BUS_66PCIXMODE: + case HPC_BUS_100PCIXMODE: + case HPC_BUS_133PCIXMODE: + rc = index + WPG_1ST_BUS_INDEX - 1; + break; + + default: + err ("hpc_writecmdtoindex - Error invalid cmd[%x]\n", cmd); + rc = HPC_ERROR; + } + + return rc; +} + +/*---------------------------------------------------------------------- +* Name: hpc_readcmdtoindex() +* +* Action: convert a read command to proper index within a controller +* +* Return index, HPC_ERROR +*---------------------------------------------------------------------*/ +static u8 hpc_readcmdtoindex (u8 cmd, u8 index) +{ + u8 rc; + + switch (cmd) { + case READ_CTLRSTATUS: + rc = 0x0F; + break; + case READ_SLOTSTATUS: + case READ_ALLSTAT: + rc = index; + break; + case READ_EXTSLOTSTATUS: + rc = index + WPG_1ST_EXTSLOT_INDEX; + break; + case READ_BUSSTATUS: + rc = index + WPG_1ST_BUS_INDEX - 1; + break; + case READ_SLOTLATCHLOWREG: + rc = 0x28; + break; + case READ_REVLEVEL: + rc = 0x25; + break; + case READ_HPCOPTIONS: + rc = 0x27; + break; + default: + rc = HPC_ERROR; + } + return rc; +} + +/*---------------------------------------------------------------------- +* Name: HPCreadslot() +* +* Action: issue a READ command to HPC +* +* Input: pslot - can not be NULL for READ_ALLSTAT +* pstatus - can be NULL for READ_ALLSTAT +* +* Return 0 or error codes +*---------------------------------------------------------------------*/ +int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) +{ + void *wpg_bbar; + struct controller *ctlr_ptr; + struct list_head *pslotlist; + u8 index, status; + int rc = 0; + int busindex; + + debug_polling ("%s - Entry pslot[%lx] cmd[%x] pstatus[%lx]\n", + __FUNCTION__, (ulong) pslot, cmd, (ulong) pstatus); + + if ((pslot == NULL) + || ((pstatus == NULL) && (cmd != READ_ALLSTAT) && (cmd != READ_BUSSTATUS))) { + rc = -EINVAL; + err ("%s - Error invalid pointer, rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + if (cmd == READ_BUSSTATUS) { + busindex = ibmphp_get_bus_index (pslot->bus); + if (busindex < 0) { + rc = -EINVAL; + err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); + return rc; + } else + index = (u8) busindex; + } else + index = pslot->ctlr_index; + + index = hpc_readcmdtoindex (cmd, index); + + if (index == HPC_ERROR) { + rc = -EINVAL; + err ("%s - Exit Error:invalid index, rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + ctlr_ptr = pslot->ctrl; + + get_hpc_access (); + + //-------------------------------------------------------------------- + // map physical address to logical address + //-------------------------------------------------------------------- + wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); + + //-------------------------------------------------------------------- + // check controller status before reading + //-------------------------------------------------------------------- + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); + if (!rc) { + switch (cmd) { + case READ_ALLSTAT: + // update the slot structure + pslot->ctrl->status = status; + pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index); + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, + &status); + if (!rc) + pslot->ext_status = ctrl_read (ctlr_ptr, wpg_bbar, index + WPG_1ST_EXTSLOT_INDEX); + + break; + + case READ_SLOTSTATUS: + // DO NOT update the slot structure + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + + case READ_EXTSLOTSTATUS: + // DO NOT update the slot structure + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + + case READ_CTLRSTATUS: + // DO NOT update the slot structure + *pstatus = status; + break; + + case READ_BUSSTATUS: + pslot->busstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + case READ_REVLEVEL: + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + case READ_HPCOPTIONS: + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + case READ_SLOTLATCHLOWREG: + // DO NOT update the slot structure + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + + // Not used + case READ_ALLSLOT: + list_for_each (pslotlist, &ibmphp_slot_head) { + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + index = pslot->ctlr_index; + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, + wpg_bbar, &status); + if (!rc) { + pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index); + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, + ctlr_ptr, wpg_bbar, &status); + if (!rc) + pslot->ext_status = + ctrl_read (ctlr_ptr, wpg_bbar, + index + WPG_1ST_EXTSLOT_INDEX); + } else { + err ("%s - Error ctrl_read failed\n", __FUNCTION__); + rc = -EINVAL; + break; + } + } + break; + default: + rc = -EINVAL; + break; + } + } + //-------------------------------------------------------------------- + // cleanup + //-------------------------------------------------------------------- + iounmap (wpg_bbar); // remove physical to logical address mapping + free_hpc_access (); + + debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_writeslot() +* +* Action: issue a WRITE command to HPC +*---------------------------------------------------------------------*/ +int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) +{ + void *wpg_bbar; + struct controller *ctlr_ptr; + u8 index, status; + int busindex; + u8 done; + int rc = 0; + int timeout; + + debug_polling ("%s - Entry pslot[%lx] cmd[%x]\n", __FUNCTION__, (ulong) pslot, cmd); + if (pslot == NULL) { + rc = -EINVAL; + err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + if ((cmd == HPC_BUS_33CONVMODE) || (cmd == HPC_BUS_66CONVMODE) || + (cmd == HPC_BUS_66PCIXMODE) || (cmd == HPC_BUS_100PCIXMODE) || + (cmd == HPC_BUS_133PCIXMODE)) { + busindex = ibmphp_get_bus_index (pslot->bus); + if (busindex < 0) { + rc = -EINVAL; + err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); + return rc; + } else + index = (u8) busindex; + } else + index = pslot->ctlr_index; + + index = hpc_writecmdtoindex (cmd, index); + + if (index == HPC_ERROR) { + rc = -EINVAL; + err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + ctlr_ptr = pslot->ctrl; + + get_hpc_access (); + + //-------------------------------------------------------------------- + // map physical address to logical address + //-------------------------------------------------------------------- + wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); + + debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __FUNCTION__, + ctlr_ptr->ctlr_id, (ulong) (ctlr_ptr->u.wpeg_ctlr.wpegbbar), (ulong) wpg_bbar, + ctlr_ptr->u.wpeg_ctlr.i2c_addr); + + //-------------------------------------------------------------------- + // check controller status before writing + //-------------------------------------------------------------------- + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); + if (!rc) { + + ctrl_write (ctlr_ptr, wpg_bbar, index, cmd); + + //-------------------------------------------------------------------- + // check controller is still not working on the command + //-------------------------------------------------------------------- + timeout = CMD_COMPLETE_TOUT_SEC; + done = FALSE; + while (!done) { + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, + &status); + if (!rc) { + if (NEEDTOCHECK_CMDSTATUS (cmd)) { + if (CTLR_FINISHED (status) == HPC_CTLR_FINISHED_YES) + done = TRUE; + } else + done = TRUE; + } + if (!done) { + long_delay (1 * HZ); + if (timeout < 1) { + done = TRUE; + err ("%s - Error command complete timeout\n", __FUNCTION__); + rc = -EFAULT; + } else + timeout--; + } + } + ctlr_ptr->status = status; + } + // cleanup + iounmap (wpg_bbar); // remove physical to logical address mapping + free_hpc_access (); + + debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: get_hpc_access() +* +* Action: make sure only one process can access HPC at one time +*---------------------------------------------------------------------*/ +static void get_hpc_access (void) +{ + down (&sem_hpcaccess); +} + +/*---------------------------------------------------------------------- +* Name: free_hpc_access() +*---------------------------------------------------------------------*/ +void free_hpc_access (void) +{ + up (&sem_hpcaccess); +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_lock_operations() +* +* Action: make sure only one process can change the data structure +*---------------------------------------------------------------------*/ +void ibmphp_lock_operations (void) +{ + down (&semOperations); + stop_polling = POLL_NO; + to_debug = TRUE; + + /* waiting for polling to actually stop */ + down (&sem_poll); +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_unlock_operations() +*---------------------------------------------------------------------*/ +void ibmphp_unlock_operations (void) +{ + debug ("%s - Entry\n", __FUNCTION__); + stop_polling = POLL_YES; + to_debug = FALSE; + up (&semOperations); + debug ("%s - Exit\n", __FUNCTION__); +} + +/*---------------------------------------------------------------------- +* Name: poll_hpc() +*---------------------------------------------------------------------*/ +static void poll_hpc (void) +{ + struct slot myslot, *pslot = NULL; + struct list_head *pslotlist; + int rc; + u8 oldlatchlow = 0x00; + u8 curlatchlow = 0x00; + int pollcnt = 0; + u8 ctrl_count = 0x00; + + debug ("poll_hpc - Entry\n"); + + while (!ibmphp_shutdown) { + if (stop_polling) { + debug ("poll_hpc - stop_polling\n"); + up (&sem_poll); + /* to prevent deadlock */ + if (ibmphp_shutdown) + break; + /* to make the thread sleep */ + down (&semOperations); + up (&semOperations); + debug ("poll_hpc - after stop_polling sleep\n"); + } else { + if (pollcnt) { + // only poll the latch register + oldlatchlow = curlatchlow; + + ctrl_count = 0x00; + list_for_each (pslotlist, &ibmphp_slot_head) { + if (ctrl_count >= ibmphp_get_total_controllers()) + break; + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + if (pslot->ctrl->ctlr_relative_id == ctrl_count) { + ctrl_count++; + if (READ_SLOT_LATCH (pslot->ctrl)) { + rc = ibmphp_hpc_readslot (pslot, + READ_SLOTLATCHLOWREG, + &curlatchlow); + if (oldlatchlow != curlatchlow) + process_changeinlatch (oldlatchlow, + curlatchlow); + } + } + } + } else { + list_for_each (pslotlist, &ibmphp_slot_head) { + if (stop_polling) + break; + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + // make a copy of the old status + memcpy ((void *) &myslot, (void *) pslot, + sizeof (struct slot)); + rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); + if ((myslot.status != pslot->status) + || (myslot.ext_status != pslot->ext_status)) + process_changeinstatus (pslot, &myslot); + } + + if (!stop_polling) { + ctrl_count = 0x00; + list_for_each (pslotlist, &ibmphp_slot_head) { + if (ctrl_count >= ibmphp_get_total_controllers()) + break; + pslot = + list_entry (pslotlist, struct slot, + ibm_slot_list); + if (pslot->ctrl->ctlr_relative_id == ctrl_count) { + ctrl_count++; + if (READ_SLOT_LATCH (pslot->ctrl)) + rc = ibmphp_hpc_readslot (pslot, + READ_SLOTLATCHLOWREG, + &curlatchlow); + } + } + } + } + INCREMENT_POLLCNT (pollcnt); + long_delay (POLL_INTERVAL_SEC * HZ); // snooze + } + } + up (&sem_poll); + up (&sem_exit); + debug ("poll_hpc - Exit\n"); +} + + +/* ---------------------------------------------------------------------- + * Name: ibmphp_hpc_fillhpslotinfo(hotplug_slot * phpslot) + * + * Action: fill out the hotplug_slot info + * + * Input: pointer to hotplug_slot + * + * Return + * Value: 0 or error codes + *-----------------------------------------------------------------------*/ +int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *phpslot) +{ + int rc = 0; + struct slot *pslot; + + if (phpslot && phpslot->private) { + pslot = (struct slot *) phpslot->private; + rc = update_slot (pslot, (u8) TRUE); + if (!rc) { + + // power - enabled:1 not:0 + phpslot->info->power_status = SLOT_POWER (pslot->status); + + // attention - off:0, on:1, blinking:2 + phpslot->info->attention_status = SLOT_ATTN (pslot->status, pslot->ext_status); + + // latch - open:1 closed:0 + phpslot->info->latch_status = SLOT_LATCH (pslot->status); + + // pci board - present:1 not:0 + if (SLOT_PRESENT (pslot->status)) + phpslot->info->adapter_status = 1; + else + phpslot->info->adapter_status = 0; +/* + if (pslot->bus_on->supported_bus_mode + && (pslot->bus_on->supported_speed == BUS_SPEED_66)) + phpslot->info->max_bus_speed_status = BUS_SPEED_66PCIX; + else + phpslot->info->max_bus_speed_status = pslot->bus_on->supported_speed; +*/ } else + rc = -EINVAL; + } else + rc = -EINVAL; + + return rc; +} + +/*---------------------------------------------------------------------- +* Name: update_slot +* +* Action: fill out slot status and extended status, controller status +* +* Input: pointer to slot struct +*---------------------------------------------------------------------*/ +static int update_slot (struct slot *pslot, u8 update) +{ + int rc = 0; + + debug ("%s - Entry pslot[%lx]\n", __FUNCTION__, (ulong) pslot); + rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); + debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: process_changeinstatus +* +* Action: compare old and new slot status, process the change in status +* +* Input: pointer to slot struct, old slot struct +* +* Return 0 or error codes +* Value: +* +* Side +* Effects: None. +* +* Notes: +*---------------------------------------------------------------------*/ +static int process_changeinstatus (struct slot *pslot, struct slot *poldslot) +{ + u8 status; + int rc = 0; + u8 disable = FALSE; + u8 update = FALSE; + + debug ("process_changeinstatus - Entry pslot[%lx], poldslot[%lx]\n", (ulong) pslot, + (ulong) poldslot); + + // bit 0 - HPC_SLOT_POWER + if ((pslot->status & 0x01) != (poldslot->status & 0x01)) + /* ????????? DO WE NEED TO UPDATE BUS SPEED INFO HERE ??? */ + update = TRUE; + + // bit 1 - HPC_SLOT_CONNECT + // ignore + + // bit 2 - HPC_SLOT_ATTN + if ((pslot->status & 0x04) != (poldslot->status & 0x04)) + update = TRUE; + + // bit 3 - HPC_SLOT_PRSNT2 + // bit 4 - HPC_SLOT_PRSNT1 + if (((pslot->status & 0x08) != (poldslot->status & 0x08)) + || ((pslot->status & 0x10) != (poldslot->status & 0x10))) + update = TRUE; + + // bit 5 - HPC_SLOT_PWRGD + if ((pslot->status & 0x20) != (poldslot->status & 0x20)) + // OFF -> ON: ignore, ON -> OFF: disable slot + if (poldslot->status & 0x20) + disable = TRUE; + + // bit 6 - HPC_SLOT_BUS_SPEED + // ignore + + // bit 7 - HPC_SLOT_LATCH + if ((pslot->status & 0x80) != (poldslot->status & 0x80)) { + update = TRUE; + // OPEN -> CLOSE + if (pslot->status & 0x80) { + if (SLOT_POWER (pslot->status)) { + // power goes on and off after closing latch + // check again to make sure power is still ON + long_delay (1 * HZ); + rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status); + if (SLOT_POWER (status)) + update = TRUE; + else // overwrite power in pslot to OFF + pslot->status &= ~HPC_SLOT_POWER; + } + } + // CLOSE -> OPEN + else if ((SLOT_POWER (poldslot->status) == HPC_SLOT_POWER_ON) + || (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED)) { + disable = TRUE; + } + // else - ignore + } + // bit 4 - HPC_SLOT_BLINK_ATTN + if ((pslot->ext_status & 0x08) != (poldslot->ext_status & 0x08)) + update = TRUE; + + if (disable) { + debug ("process_changeinstatus - disable slot\n"); + pslot->flag = FALSE; + rc = ibmphp_disable_slot (pslot->hotplug_slot); + } + + if (update || disable) { + ibmphp_update_slot_info (pslot); + } + + debug ("%s - Exit rc[%d] disable[%x] update[%x]\n", __FUNCTION__, rc, disable, update); + + return rc; +} + +/*---------------------------------------------------------------------- +* Name: process_changeinlatch +* +* Action: compare old and new latch reg status, process the change +* +* Input: old and current latch register status +* +* Return 0 or error codes +* Value: +*---------------------------------------------------------------------*/ +static int process_changeinlatch (u8 old, u8 new) +{ + struct slot myslot, *pslot; + u8 i; + u8 mask; + int rc = 0; + + debug ("%s - Entry old[%x], new[%x]\n", __FUNCTION__, old, new); + // bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots + + for (i = 1; i <= 6; i++) { + mask = 0x01 << i; + if ((mask & old) != (mask & new)) { + pslot = ibmphp_get_slot_from_physical_num (i); + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); + debug ("%s - call process_changeinstatus for slot[%d]\n", __FUNCTION__, i); + process_changeinstatus (pslot, &myslot); + } else { + rc = -EINVAL; + err ("%s - Error bad pointer for slot[%d]\n", __FUNCTION__, i); + } + } + } + debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: hpc_poll_thread +* +* Action: polling +* +* Return 0 +* Value: +*---------------------------------------------------------------------*/ +static int hpc_poll_thread (void *data) +{ + debug ("%s - Entry\n", __FUNCTION__); + lock_kernel (); + daemonize (); + reparent_to_init (); + + // New name + strcpy (current->comm, "hpc_poll"); + + unlock_kernel (); + + poll_hpc (); + + tid_poll = 0; + debug ("%s - Exit\n", __FUNCTION__); + return 0; +} + + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_start_poll_thread +* +* Action: start polling thread +*---------------------------------------------------------------------*/ +int ibmphp_hpc_start_poll_thread (void) +{ + int rc = 0; + + debug ("ibmphp_hpc_start_poll_thread - Entry\n"); + + tid_poll = kernel_thread (hpc_poll_thread, 0, 0); + if (tid_poll < 0) { + err ("ibmphp_hpc_start_poll_thread - Error, thread not started\n"); + rc = -1; + } + + debug ("ibmphp_hpc_start_poll_thread - Exit tid_poll[%d] rc[%d]\n", tid_poll, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_stop_poll_thread +* +* Action: stop polling thread and cleanup +*---------------------------------------------------------------------*/ +void ibmphp_hpc_stop_poll_thread (void) +{ + debug ("ibmphp_hpc_stop_poll_thread - Entry\n"); + + ibmphp_shutdown = TRUE; + ibmphp_lock_operations (); + + // wait for poll thread to exit + down (&sem_exit); + + // cleanup + free_hpc_access (); + ibmphp_unlock_operations (); + up (&sem_poll); + up (&sem_exit); + + debug ("ibmphp_hpc_stop_poll_thread - Exit\n"); +} + +/*---------------------------------------------------------------------- +* Name: hpc_wait_ctlr_notworking +* +* Action: wait until the controller is in a not working state +* +* Return 0, HPC_ERROR +* Value: +*---------------------------------------------------------------------*/ +static int hpc_wait_ctlr_notworking (int timeout, struct controller *ctlr_ptr, void *wpg_bbar, + u8 * pstatus) +{ + int rc = 0; + u8 done = FALSE; + + debug_polling ("hpc_wait_ctlr_notworking - Entry timeout[%d]\n", timeout); + + while (!done) { + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, WPG_CTLR_INDEX); + if (*pstatus == HPC_ERROR) { + rc = HPC_ERROR; + done = TRUE; + } + if (CTLR_WORKING (*pstatus) == HPC_CTLR_WORKING_NO) + done = TRUE; + if (!done) { + long_delay (1 * HZ); + if (timeout < 1) { + done = TRUE; + err ("HPCreadslot - Error ctlr timeout\n"); + rc = HPC_ERROR; + } else + timeout--; + } + } + debug_polling ("hpc_wait_ctlr_notworking - Exit rc[%x] status[%x]\n", rc, *pstatus); + return rc; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/ibmphp_pci.c linux-2.5/drivers/hotplug/ibmphp_pci.c --- linux-2.5.5/drivers/hotplug/ibmphp_pci.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/hotplug/ibmphp_pci.c Fri Mar 1 15:07:37 2002 @@ -0,0 +1,1719 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include "ibmphp.h" + + +static int configure_device(struct pci_func *); +static int configure_bridge(struct pci_func **, u8); +static struct res_needed *scan_behind_bridge(struct pci_func *, u8); +static int add_new_bus (struct bus_node *, struct resource_node *, struct resource_node *, struct resource_node *, u8); +static u8 find_sec_number (u8 primary_busno, u8 slotno); + +/* + * NOTE..... If BIOS doesn't provide default routing, we assign: + * 9 for SCSI, 10 for LAN adapters, and 11 for everything else. + * If adapter is bridged, then we assign 11 to it and devices behind it. + * We also assign the same irq numbers for multi function devices. + * These are PIC mode, so shouldn't matter n.e.ways (hopefully) + */ +static void assign_alt_irq (struct pci_func * cur_func, u8 class_code) +{ + int j = 0; + for (j = 0; j < 4; j++) { + if (cur_func->irq[j] == 0xff) { + switch (class_code) { + case PCI_BASE_CLASS_STORAGE: + cur_func->irq[j] = SCSI_IRQ; + break; + case PCI_BASE_CLASS_NETWORK: + cur_func->irq[j] = LAN_IRQ; + break; + default: + cur_func->irq[j] = OTHER_IRQ; + break; + } + } + } +} + +/* + * Configures the device to be added (will allocate needed resources if it + * can), the device can be a bridge or a regular pci device, can also be + * multi-functional + * + * Input: function to be added + * + * TO DO: The error case with Multifunction device or multi function bridge, + * if there is an error, will need to go through all previous functions and + * unconfigure....or can add some code into unconfigure_card.... + */ +int ibmphp_configure_card (struct pci_func *func, u8 slotno) +{ + u16 vendor_id; + u32 class; + u8 class_code; + u8 hdr_type, device, sec_number; + u8 function; + struct pci_func *newfunc; /* for multi devices */ + struct pci_func *cur_func, *prev_func; + int rc, i, j; + int cleanup_count; + u8 flag; + u8 valid_device = 0x00; /* to see if we are able to read from card any device info at all */ + + debug ("inside configure_card, func->busno = %x \n", func->busno); + + device = func->device; + cur_func = func; + + /* We only get bus and device from IRQ routing table. So at this point, + * func->busno is correct, and func->device contains only device (at the 5 + * highest bits) + */ + + /* For every function on the card */ + for (function = 0x00; function < 0x08; function++) { + cur_func->function = function; + + debug ("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->funcion = %x\n", cur_func->busno, device, function); + + pci_read_config_word_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_VENDOR_ID, &vendor_id); + + debug ("vendor_id is %x\n", vendor_id); + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + debug ("found valid device, vendor_id = %x\n", vendor_id); + + ++valid_device; + + /* header: x x x x x x x x + * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge + * |_=> 0 = single function device, 1 = multi-function device + */ + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_HEADER_TYPE, &hdr_type); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_CLASS_REVISION, &class); + + class_code = class >> 24; + debug ("hrd_type = %x, class = %x, class_code %x \n", hdr_type, class, class_code); + class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ + if (class == PCI_CLASS_NOT_DEFINED_VGA) { + err ("The device %x is VGA compatible and as is not supported for hot plugging. " + "Please choose another device.\n", cur_func->device); + return -ENODEV; + } else if (class == PCI_CLASS_DISPLAY_VGA) { + err ("The device %x is not supported for hot plugging. " + "Please choose another device.\n", cur_func->device); + return -ENODEV; + } + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + debug ("single device case.... vendor id = %x, hdr_type = %x, class = %x\n", vendor_id, hdr_type, class); + assign_alt_irq (cur_func, class_code); + if ((rc = configure_device (cur_func)) < 0) { + /* We need to do this in case some other BARs were properly inserted */ + err ("was not able to configure devfunc %x on bus %x. \n", + cur_func->device, cur_func->busno); + cleanup_count = 6; + goto error; + } + cur_func->next = NULL; + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIDEVICE: + assign_alt_irq (cur_func, class_code); + if ((rc = configure_device (cur_func)) < 0) { + /* We need to do this in case some other BARs were properly inserted */ + err ("was not able to configure devfunc %x on bus %x...bailing out\n", + cur_func->device, cur_func->busno); + cleanup_count = 6; + goto error; + } + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = cur_func->busno; + newfunc->device = device; + cur_func->next = newfunc; + cur_func = newfunc; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + break; + case PCI_HEADER_TYPE_MULTIBRIDGE: + class >>= 8; + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " + "Please insert another card.\n", cur_func->device); + return -ENODEV; + } + assign_alt_irq (cur_func, class_code); + rc = configure_bridge (&cur_func, slotno); + if (rc == -ENODEV) { + err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); + err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device); + return rc; + } + if (rc) { + /* We need to do this in case some other BARs were properly inserted */ + err ("was not able to hot-add PPB properly.\n"); + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + cleanup_count = 2; + goto error; + } + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_SECONDARY_BUS, &sec_number); + flag = FALSE; + for (i = 0; i < 32; i++) { + if (func->devices[i]) { + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = sec_number; + newfunc->device = (u8) i; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + + if (flag) { + for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; + prev_func->next = newfunc; + } else + cur_func->next = newfunc; + + rc = ibmphp_configure_card (newfunc, slotno); + /* This could only happen if kmalloc failed */ + if (rc) { + /* We need to do this in case bridge itself got configured properly, but devices behind it failed */ + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + cleanup_count = 2; + goto error; + } + flag = TRUE; + } + } + + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = cur_func->busno; + newfunc->device = device; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; + prev_func->next = newfunc; + cur_func = newfunc; + break; + case PCI_HEADER_TYPE_BRIDGE: + class >>= 8; + debug ("class now is %x\n", class); + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " + "Please insert another card.\n", cur_func->device); + return -ENODEV; + } + + assign_alt_irq (cur_func, class_code); + + debug ("cur_func->busno b4 configure_bridge is %x\n", cur_func->busno); + rc = configure_bridge (&cur_func, slotno); + if (rc == -ENODEV) { + err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); + err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device); + return rc; + } + if (rc) { + /* We need to do this in case some other BARs were properly inserted */ + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + err ("was not able to hot-add PPB properly.\n"); + cleanup_count = 2; + goto error; + } + debug ("cur_func->busno = %x, device = %x, function = %x\n", cur_func->busno, device, function); + pci_read_config_byte_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_SECONDARY_BUS, &sec_number); + debug ("after configuring bridge..., sec_number = %x\n", sec_number); + flag = FALSE; + for (i = 0; i < 32; i++) { + if (func->devices[i]) { + debug ("inside for loop, device is %x\n", i); + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err (" out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = sec_number; + newfunc->device = (u8) i; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + + if (flag) { + for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; + prev_func->next = newfunc; + } else + cur_func->next = newfunc; + + rc = ibmphp_configure_card (newfunc, slotno); + + /* Again, this case should not happen... For complete paranoia, will need to call remove_bus */ + if (rc) { + /* We need to do this in case some other BARs were properly inserted */ + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + cleanup_count = 2; + goto error; + } + flag = TRUE; + } + } + + function = 0x8; + break; + default: + err ("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type); + return -ENXIO; + break; + } /* end of switch */ + } /* end of valid device */ + } /* end of for */ + + if (!valid_device) { + err ("Cannot find any valid devices on the card. Or unable to read from card.\n"); + return -ENODEV; + } + + return 0; + +error: + for (i = 0; i < cleanup_count; i++) { + if (cur_func->io[i]) { + ibmphp_remove_resource (cur_func->io[i]); + cur_func->io[i] = NULL; + } else if (cur_func->pfmem[i]) { + ibmphp_remove_resource (cur_func->pfmem[i]); + cur_func->pfmem[i] = NULL; + } else if (cur_func->mem[i]) { + ibmphp_remove_resource (cur_func->mem[i]); + cur_func->mem[i] = NULL; + } + } + return rc; +} + +/* + * This function configures the pci BARs of a single device. + * Input: pointer to the pci_func + * Output: configured PCI, 0, or error + */ +static int configure_device (struct pci_func *func) +{ + u32 bar[6]; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + u8 irq; + int count; + int len[6]; + struct resource_node *io[6]; + struct resource_node *mem[6]; + struct resource_node *mem_tmp; + struct resource_node *pfmem[6]; + u8 device; + u8 function; + + debug ("%s - inside\n", __FUNCTION__); + + device = func->device; + function = func->function; + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + + /* not sure if i need this. per scott, said maybe need smth like this + if devices don't adhere 100% to the spec, so don't want to write + to the reserved bits + + pcibios_read_config_byte(cur_func->busno, cur_func->device, + PCI_BASE_ADDRESS_0 + 4 * count, &tmp); + if (tmp & 0x01) // IO + pcibios_write_config_dword(cur_func->busno, cur_func->device, + PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFD); + else // Memory + pcibios_write_config_dword(cur_func->busno, cur_func->device, + PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF); + */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0xFFFFFFFF); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]); + + if (!bar[count]) /* This BAR is not implemented */ + continue; + + debug ("Device %x BAR %d wants %x\n", func->device, count, bar[count]); + + if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + debug ("inside IO SPACE\n"); + + len[count] = bar[count] & 0xFFFFFFFC; + len[count] = ~len[count] + 1; + + debug ("len[count] in IO %x, count %d\n", len[count], count); + + io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + + if (!io[count]) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (io[count], 0, sizeof (struct resource_node)); + io[count]->type = IO; + io[count]->busno = func->busno; + io[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + io[count]->len = len[count]; + if (ibmphp_check_resource(io[count], 0) == 0) { + ibmphp_add_resource (io[count]); + func->io[count] = io[count]; + } else { + err ("cannot allocate requested io for bus %x device %x function %x len %x\n", + func->busno, func->device, func->function, len[count]); + kfree (io[count]); + return -EIO; + } + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->io[count]->start); + + /* _______________This is for debugging purposes only_____________________ */ + debug ("b4 writing, the IO address is %x\n", func->io[count]->start); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]); + debug ("after writing.... the start address is %x\n", bar[count]); + /* _________________________________________________________________________*/ + + } else { + /* This is Memory */ + if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + debug ("PFMEM SPACE\n"); + + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in PFMEM %x, count %d\n", len[count], count); + + pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!pfmem[count]) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (pfmem[count], 0, sizeof (struct resource_node)); + pfmem[count]->type = PFMEM; + pfmem[count]->busno = func->busno; + pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + pfmem[count]->len = len[count]; + pfmem[count]->fromMem = FALSE; + if (ibmphp_check_resource (pfmem[count], 0) == 0) { + ibmphp_add_resource (pfmem[count]); + func->pfmem[count] = pfmem[count]; + } else { + mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem_tmp) { + err ("out of system memory \n"); + kfree (pfmem[count]); + return -ENOMEM; + } + memset (mem_tmp, 0, sizeof (struct resource_node)); + mem_tmp->type = MEM; + mem_tmp->busno = pfmem[count]->busno; + mem_tmp->devfunc = pfmem[count]->devfunc; + mem_tmp->len = pfmem[count]->len; + debug ("there's no pfmem... going into mem.\n"); + if (ibmphp_check_resource (mem_tmp, 0) == 0) { + ibmphp_add_resource (mem_tmp); + pfmem[count]->fromMem = TRUE; + pfmem[count]->rangeno = mem_tmp->rangeno; + pfmem[count]->start = mem_tmp->start; + pfmem[count]->end = mem_tmp->end; + ibmphp_add_pfmem_from_mem (pfmem[count]); + func->pfmem[count] = pfmem[count]; + } else { + err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (mem_tmp); + kfree (pfmem[count]); + return -EIO; + } + } + + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->pfmem[count]->start); + + /*_______________This if for debugging purposes only______________________________*/ + debug ("b4 writing, start addres is %x\n", func->pfmem[count]->start); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]); + debug ("after writing, start address is %x\n", bar[count]); + /*_________________________________________________________________________________*/ + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ + debug ("inside the mem 64 case, count %d\n", count); + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000); + } + } else { + /* regular memory */ + debug ("REGULAR MEM SPACE\n"); + + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in Mem %x, count %d\n", len[count], count); + + mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem[count]) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem[count], 0, sizeof (struct resource_node)); + mem[count]->type = MEM; + mem[count]->busno = func->busno; + mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + mem[count]->len = len[count]; + if (ibmphp_check_resource (mem[count], 0) == 0) { + ibmphp_add_resource (mem[count]); + func->mem[count] = mem[count]; + } else { + err ("cannot allocate requested mem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (mem[count]); + return -EIO; + } + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->mem[count]->start); + /* _______________________This is for debugging purposes only _______________________*/ + debug ("b4 writing, start address is %x\n", func->mem[count]->start); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]); + debug ("after writing, the address is %x\n", bar[count]); + /* __________________________________________________________________________________*/ + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + debug ("inside mem 64 case, reg. mem, count %d\n", count); + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000); + } + } + } /* end of mem */ + } /* end of for */ + + func->bus = 0; /* To indicate that this is not a PPB */ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_PIN, &irq); + if ((irq > 0x00) && (irq < 0x05)) + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_LINE, func->irq[irq - 1]); + + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_CACHE_LINE_SIZE, CACHE); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_LATENCY_TIMER, LATENCY); + + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_ROM_ADDRESS, 0x00L); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_COMMAND, DEVICEENABLE); + + return 0; +} + +/****************************************************************************** + * This routine configures a PCI-2-PCI bridge and the functions behind it + * Parameters: pci_func + * Returns: + ******************************************************************************/ +static int configure_bridge (struct pci_func **func_passed, u8 slotno) +{ + int count; + int i; + int rc; + u8 sec_number; + u8 io_base; + u16 pfmem_base; + u32 bar[2]; + u32 len[2]; + u8 flag_io = FALSE; + u8 flag_mem = FALSE; + u8 flag_pfmem = FALSE; + u8 need_io_upper = FALSE; + u8 need_pfmem_upper = FALSE; + struct res_needed *amount_needed = NULL; + struct resource_node *io = NULL; + struct resource_node *bus_io[2] = {NULL, NULL}; + struct resource_node *mem = NULL; + struct resource_node *bus_mem[2] = {NULL, NULL}; + struct resource_node *mem_tmp = NULL; + struct resource_node *pfmem = NULL; + struct resource_node *bus_pfmem[2] = {NULL, NULL}; + struct bus_node *bus; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + 0 + }; + struct pci_func *func = *func_passed; + u8 function; + u8 device; + u8 irq; + int retval; + + debug ("%s - enter\n", __FUNCTION__); + + function = func->function; + device = func->device; + + /* Configuring necessary info for the bridge so that we could see the devices + * behind it + */ + + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PRIMARY_BUS, func->busno); + + /* _____________________For debugging purposes only __________________________ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PRIMARY_BUS, &pri_number); + debug ("primary # written into the bridge is %x\n", pri_number); + ___________________________________________________________________________*/ + + /* in EBDA, only get allocated 1 additional bus # per slot */ + sec_number = find_sec_number (func->busno, slotno); + if (sec_number == 0xff) { + err ("cannot allocate secondary bus number for the bridged device \n"); + return -EINVAL; + } + + debug ("after find_sec_number, the number we got is %x\n", sec_number); + debug ("AFTER FIND_SEC_NUMBER, func->busno IS %x\n", func->busno); + + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SECONDARY_BUS, sec_number); + + /* __________________For debugging purposes only __________________________________ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SECONDARY_BUS, &sec_number); + debug ("sec_number after write/read is %x\n", sec_number); + ________________________________________________________________________________*/ + + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SUBORDINATE_BUS, sec_number); + + /* __________________For debugging purposes only ____________________________________ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SUBORDINATE_BUS, &sec_number); + debug ("subordinate number after write/read is %x\n", sec_number); + __________________________________________________________________________________*/ + + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_CACHE_LINE_SIZE, CACHE); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_LATENCY_TIMER, LATENCY); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SEC_LATENCY_TIMER, LATENCY); + + debug ("func->busno is %x\n", func->busno); + debug ("sec_number after writing is %x\n", sec_number); + + + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !!!!!!!!!!!!!!!NEED TO ADD!!! FAST BACK-TO-BACK ENABLE!!!!!!!!!!!!!!!!!!!! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + + + /* First we need to allocate mem/io for the bridge itself in case it needs it */ + for (count = 0; address[count]; count++) { /* for 2 BARs */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0xFFFFFFFF); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]); + + if (!bar[count]) { + /* This BAR is not implemented */ + debug ("so we come here then, eh?, count = %d\n", count); + continue; + } + // tmp_bar = bar[count]; + + debug ("Bar %d wants %x\n", count, bar[count]); + + if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + len[count] = bar[count] & 0xFFFFFFFC; + len[count] = ~len[count] + 1; + + debug ("len[count] in IO = %x\n", len[count]); + + bus_io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + + if (!bus_io[count]) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus_io[count], 0, sizeof (struct resource_node)); + bus_io[count]->type = IO; + bus_io[count]->busno = func->busno; + bus_io[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + bus_io[count]->len = len[count]; + if (ibmphp_check_resource (bus_io[count], 0) == 0) { + ibmphp_add_resource (bus_io[count]); + func->io[count] = bus_io[count]; + } else { + err ("cannot allocate requested io for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (bus_io[count]); + return -EIO; + } + + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->io[count]->start); + + } else { + /* This is Memory */ + if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in PFMEM = %x\n", len[count]); + + bus_pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!bus_pfmem[count]) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus_pfmem[count], 0, sizeof (struct resource_node)); + bus_pfmem[count]->type = PFMEM; + bus_pfmem[count]->busno = func->busno; + bus_pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + bus_pfmem[count]->len = len[count]; + bus_pfmem[count]->fromMem = FALSE; + if (ibmphp_check_resource (bus_pfmem[count], 0) == 0) { + ibmphp_add_resource (bus_pfmem[count]); + func->pfmem[count] = bus_pfmem[count]; + } else { + mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem_tmp) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (mem_tmp, 0, sizeof (struct resource_node)); + mem_tmp->type = MEM; + mem_tmp->busno = bus_pfmem[count]->busno; + mem_tmp->devfunc = bus_pfmem[count]->devfunc; + mem_tmp->len = bus_pfmem[count]->len; + if (ibmphp_check_resource (mem_tmp, 0) == 0) { + ibmphp_add_resource (mem_tmp); + bus_pfmem[count]->fromMem = TRUE; + bus_pfmem[count]->rangeno = mem_tmp->rangeno; + ibmphp_add_pfmem_from_mem (bus_pfmem[count]); + func->pfmem[count] = bus_pfmem[count]; + } else { + err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (mem_tmp); + kfree (bus_pfmem[count]); + return -EIO; + } + } + + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->pfmem[count]->start); + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000); + + } + } else { + /* regular memory */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in Memory is %x\n", len[count]); + + bus_mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!bus_mem[count]) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus_mem[count], 0, sizeof (struct resource_node)); + bus_mem[count]->type = MEM; + bus_mem[count]->busno = func->busno; + bus_mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + bus_mem[count]->len = len[count]; + if (ibmphp_check_resource (bus_mem[count], 0) == 0) { + ibmphp_add_resource (bus_mem[count]); + func->mem[count] = bus_mem[count]; + } else { + err ("cannot allocate requested mem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (bus_mem[count]); + return -EIO; + } + + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->mem[count]->start); + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000); + + } + } + } /* end of mem */ + } /* end of for */ + + /* Now need to see how much space the devices behind the bridge needed */ + amount_needed = scan_behind_bridge (func, sec_number); + if (amount_needed == NULL) + return -ENOMEM; + + debug ("after coming back from scan_behind_bridge\n"); + debug ("amount_needed->not_correct = %x\n", amount_needed->not_correct); + debug ("amount_needed->io = %x\n", amount_needed->io); + debug ("amount_needed->mem = %x\n", amount_needed->mem); + debug ("amount_needed->pfmem = %x\n", amount_needed->pfmem); + + if (amount_needed->not_correct) { + debug ("amount_needed is not correct \n"); + for (count = 0; address[count]; count++) { + /* for 2 BARs */ + if (bus_io[count]) { + ibmphp_remove_resource (bus_io[count]); + func->io[count] = NULL; + } else if (bus_pfmem[count]) { + ibmphp_remove_resource (bus_pfmem[count]); + func->pfmem[count] = NULL; + } else if (bus_mem[count]) { + ibmphp_remove_resource (bus_mem[count]); + func->mem[count] = NULL; + } + } + kfree (amount_needed); + return -ENODEV; + } + + if (!amount_needed->io) { + debug ("it doesn't want IO?\n"); + flag_io = TRUE; + } else { + debug ("it wants %x IO behind the bridge \n", amount_needed->io); + io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + + if (!io) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (io, 0, sizeof (struct resource_node)); + io->type = IO; + io->busno = func->busno; + io->devfunc = ((func->device << 3) | (func->function & 0x7)); + io->len = amount_needed->io; + if (ibmphp_check_resource (io, 1) == 0) { + debug ("were we able to add io\n"); + ibmphp_add_resource (io); + flag_io = TRUE; + } + } + + if (!amount_needed->mem) { + debug ("it doesn't want n.e.memory?\n"); + flag_mem = TRUE; + } else { + debug ("it wants %x memory behind the bridge\n", amount_needed->mem); + mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (mem, 0, sizeof (struct resource_node)); + mem->type = MEM; + mem->busno = func->busno; + mem->devfunc = ((func->device << 3) | (func->function & 0x7)); + mem->len = amount_needed->mem; + if (ibmphp_check_resource (mem, 1) == 0) { + ibmphp_add_resource (mem); + flag_mem = TRUE; + debug ("were we able to add mem\n"); + } + } + + if (!amount_needed->pfmem) { + debug ("it doesn't want n.e.pfmem mem?\n"); + flag_pfmem = TRUE; + } else { + debug ("it wants %x pfmemory behind the bridge\n", amount_needed->pfmem); + pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!pfmem) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (pfmem, 0, sizeof (struct resource_node)); + pfmem->type = PFMEM; + pfmem->busno = func->busno; + pfmem->devfunc = ((func->device << 3) | (func->function & 0x7)); + pfmem->len = amount_needed->pfmem; + pfmem->fromMem = FALSE; + if (ibmphp_check_resource (pfmem, 1) == 0) { + ibmphp_add_resource (pfmem); + flag_pfmem = TRUE; + } else { + mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem_tmp) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (mem_tmp, 0, sizeof (struct resource_node)); + mem_tmp->type = MEM; + mem_tmp->busno = pfmem->busno; + mem_tmp->devfunc = pfmem->devfunc; + mem_tmp->len = pfmem->len; + if (ibmphp_check_resource (mem_tmp, 1) == 0) { + ibmphp_add_resource (mem_tmp); + pfmem->fromMem = TRUE; + pfmem->rangeno = mem_tmp->rangeno; + ibmphp_add_pfmem_from_mem (pfmem); + flag_pfmem = TRUE; + } + } + } + + debug ("b4 if (flag_io && flag_mem && flag_pfmem)\n"); + debug ("flag_io = %x, flag_mem = %x, flag_pfmem = %x\n", flag_io, flag_mem, flag_pfmem); + + if (flag_io && flag_mem && flag_pfmem) { + bus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + if (!bus) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus, 0, sizeof (struct bus_node)); + bus->busno = sec_number; + debug ("b4 adding new bus\n"); + rc = add_new_bus (bus, io, mem, pfmem, func->busno); + if (rc) { + if (rc == -ENOMEM) { + ibmphp_remove_bus (bus, func->busno); + return rc; + } + retval = rc; + goto error; + } + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, &io_base); + pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, &pfmem_base); + + if ((io_base & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { + debug ("io 32\n"); + need_io_upper = TRUE; + } + if ((io_base & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { + debug ("pfmem 64\n"); + need_pfmem_upper = TRUE; + } + + if (bus->noIORanges) { + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, 0x00 | bus->rangeIO->start >> 8); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT, 0x00 | bus->rangeIO->end >> 8); + + /* _______________This is for debugging purposes only ____________________ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, &temp); + debug ("io_base = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8); + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT, &temp); + debug ("io_limit = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8); + ________________________________________________________________________*/ + + if (need_io_upper) { /* since can't support n.e.ways */ + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE_UPPER16, 0x0000); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT_UPPER16, 0x0000); + } + } else { + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, 0x00); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT, 0x00); + } + + if (bus->noMemRanges) { + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_BASE, 0x0000 | bus->rangeMem->start >> 16); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_LIMIT, 0x0000 | bus->rangeMem->end >> 16); + + /* ____________________This is for debugging purposes only ________________________ + pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_BASE, &temp); + debug ("mem_base = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_LIMIT, &temp); + debug ("mem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + __________________________________________________________________________________*/ + + } else { + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_BASE, 0xffff); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_LIMIT, 0x0000); + } + if (bus->noPFMemRanges) { + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, 0x0000 | bus->rangePFMem->start >> 16); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_LIMIT, 0x0000 | bus->rangePFMem->end >> 16); + + /* __________________________This is for debugging purposes only _______________________ + pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, &temp); + debug ("pfmem_base = %x", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_LIMIT, &temp); + debug ("pfmem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + ______________________________________________________________________________________*/ + + if (need_pfmem_upper) { /* since can't support n.e.ways */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_BASE_UPPER32, 0x00000000); + pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_LIMIT_UPPER32, 0x00000000); + } + } else { + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, 0xffff); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_LIMIT, 0x0000); + } + + debug ("b4 writing control information\n"); + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_PIN, &irq); + if ((irq > 0x00) && (irq < 0x05)) + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_LINE, func->irq[irq - 1]); + /* + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, ctrl); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY); + pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR); + */ + + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_COMMAND, DEVICEENABLE); + pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, 0x07); + for (i = 0; i < 32; i++) { + if (amount_needed->devices[i]) { + debug ("device where devices[i] is 1 = %x\n", i); + func->devices[i] = 1; + } + } + func->bus = 1; /* For unconfiguring, to indicate it's PPB */ + func_passed = &func; + debug ("func->busno b4 returning is %x\n", func->busno); + debug ("func->busno b4 returning in the other structure is %x\n", (*func_passed)->busno); + kfree (amount_needed); + return 0; + } else { + err ("Configuring bridge was unsuccessful... \n"); + mem_tmp = NULL; + retval = -EIO; + goto error; + } + +error: + if (amount_needed) + kfree (amount_needed); + if (pfmem) + ibmphp_remove_resource (pfmem); + if (io) + ibmphp_remove_resource (io); + if (mem) + ibmphp_remove_resource (mem); + for (i = 0; i < 2; i++) { /* for 2 BARs */ + if (bus_io[i]) { + ibmphp_remove_resource (bus_io[i]); + func->io[i] = NULL; + } else if (bus_pfmem[i]) { + ibmphp_remove_resource (bus_pfmem[i]); + func->pfmem[i] = NULL; + } else if (bus_mem[i]) { + ibmphp_remove_resource (bus_mem[i]); + func->mem[i] = NULL; + } + } + return retval; +} + +/***************************************************************************** + * This function adds up the amount of resources needed behind the PPB bridge + * and passes it to the configure_bridge function + * Input: bridge function + * Ouput: amount of resources needed + *****************************************************************************/ +static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno) +{ + int count, len[6]; + u16 vendor_id; + u8 hdr_type; + u8 device, function; + int howmany = 0; /*this is to see if there are any devices behind the bridge */ + + u32 bar[6], class; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + struct res_needed *amount; + + amount = kmalloc (sizeof (struct res_needed), GFP_KERNEL); + if (amount == NULL) + return NULL; + memset (amount, 0, sizeof (struct res_needed)); + + debug ("the bus_no behind the bridge is %x\n", busno); + debug ("scanning devices behind the bridge...\n"); + for (device = 0; device < 32; device++) { + amount->devices[device] = 0; + for (function = 0; function < 8; function++) { + + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_VENDOR_ID, &vendor_id); + + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + howmany++; + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_HEADER_TYPE, &hdr_type); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_CLASS_REVISION, &class); + + debug ("hdr_type behind the bridge is %x\n", hdr_type); + if (hdr_type & PCI_HEADER_TYPE_BRIDGE) { + err ("embedded bridges not supported for hot-plugging.\n"); + amount->not_correct = TRUE; + return amount; + } + + class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ + if (class == PCI_CLASS_NOT_DEFINED_VGA) { + err ("The device %x is VGA compatible and as is not supported for hot plugging. " + "Please choose another device.\n", device); + amount->not_correct = TRUE; + return amount; + } else if (class == PCI_CLASS_DISPLAY_VGA) { + err ("The device %x is not supported for hot plugging. " + "Please choose another device.\n", device); + amount->not_correct = TRUE; + return amount; + } + + amount->devices[device] = 1; + + for (count = 0; address[count]; count++) { + /* for 6 BARs */ + /* + pci_read_config_byte_nodev(ibmphp_pci_root_ops, busno, device, function, address[count], &tmp); + if (tmp & 0x01) // IO + pci_write_config_dword_nodev(ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFD); + else // MEMORY + pci_write_config_dword_nodev(ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFF); + */ + pci_write_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFF); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &bar[count]); + + debug ("what is bar[count]? %x, count = %d\n", bar[count], count); + + if (!bar[count]) /* This BAR is not implemented */ + continue; + + //tmp_bar = bar[count]; + + debug ("count %d device %x function %x wants %x resources \n", count, device, function, bar[count]); + + if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + len[count] = bar[count] & 0xFFFFFFFC; + len[count] = ~len[count] + 1; + amount->io += len[count]; + } else { + /* This is Memory */ + if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + amount->pfmem += len[count]; + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) + /* takes up another dword */ + count += 1; + + } else { + /* regular memory */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + amount->mem += len[count]; + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + } + } + } /* end for */ + } /* end if (valid) */ + } /* end for */ + } /* end for */ + + if (!howmany) + amount->not_correct = TRUE; + else + amount->not_correct = FALSE; + if ((amount->io) && (amount->io < IOBRIDGE)) + amount->io = IOBRIDGE; + if ((amount->mem) && (amount->mem < MEMBRIDGE)) + amount->mem = MEMBRIDGE; + if ((amount->pfmem) && (amount->pfmem < MEMBRIDGE)) + amount->pfmem = MEMBRIDGE; + return amount; +} + +/* The following 3 unconfigure_boot_ routines deal with the case when we had the card + * upon bootup in the system, since we don't allocate func to such case, we need to read + * the start addresses from pci config space and then find the corresponding entries in + * our resource lists. The functions return either 0, -ENODEV, or -1 (general failure) + * Change: we also call these functions even if we configured the card ourselves (i.e., not + * the bootup case), since it should work same way + */ +static int unconfigure_boot_device (u8 busno, u8 device, u8 function) +{ + u32 start_address; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + int count; + struct resource_node *io; + struct resource_node *mem; + struct resource_node *pfmem; + struct bus_node *bus; + u32 end_address; + u32 temp_end; + u32 size; + u32 tmp_address; + + debug ("%s - enter\n", __FUNCTION__); + + bus = ibmphp_find_res_bus (busno); + if (!bus) { + debug ("cannot find corresponding bus.\n"); + return -EINVAL; + } + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &start_address); + + /* We can do this here, b/c by that time the device driver of the card has been stopped */ + + pci_write_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFF); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &size); + pci_write_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], start_address); + + debug ("start_address is %x\n", start_address); + debug ("busno, device, function %x %x %x\n", busno, device, function); + if (!size) { + /* This BAR is not implemented */ + debug ("is this bar no implemented?, count = %d\n", count); + continue; + } + tmp_address = start_address; + if (start_address & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + start_address &= PCI_BASE_ADDRESS_IO_MASK; + size = size & 0xFFFFFFFC; + size = ~size + 1; + end_address = start_address + size - 1; + if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { + err ("cannot find corresponding IO resource to remove\n"); + return -EIO; + } + debug ("io->start = %x\n", io->start); + temp_end = io->end; + start_address = io->end + 1; + ibmphp_remove_resource (io); + /* This is needed b/c of the old I/O restrictions in the BIOS */ + while (temp_end < end_address) { + if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { + err ("cannot find corresponding IO resource to remove\n"); + return -EIO; + } + debug ("io->start = %x\n", io->start); + temp_end = io->end; + start_address = io->end + 1; + ibmphp_remove_resource (io); + } + + /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ + } else { + /* This is Memory */ + if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + debug ("start address of pfmem is %x\n", start_address); + + if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { + err ("cannot find corresponding PFMEM resource to remove\n"); + return -EIO; + } + if (pfmem) + debug ("pfmem->start = %x\n", pfmem->start); + + ibmphp_remove_resource (pfmem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + + } else { + /* regular memory */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + debug ("start address of mem is %x\n", start_address); + if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { + err ("cannot find corresponding MEM resource to remove\n"); + return -EIO; + } + if (mem) + debug ("mem->start = %x\n", mem->start); + + ibmphp_remove_resource (mem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + } + } /* end of mem */ + } /* end of for */ + + return 0; +} + +static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function) +{ + int count; + int bus_no, pri_no, sub_no, sec_no = 0; + u32 start_address, tmp_address; + u8 sec_number, sub_number, pri_number; + struct resource_node *io = NULL; + struct resource_node *mem = NULL; + struct resource_node *pfmem = NULL; + struct bus_node *bus; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + 0 + }; + + bus_no = (int) busno; + debug ("busno is %x\n", busno); + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PRIMARY_BUS, &pri_number); + debug ("%s - busno = %x, primary_number = %x\n", __FUNCTION__, busno, pri_number); + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SECONDARY_BUS, &sec_number); + debug ("sec_number is %x\n", sec_number); + sec_no = (int) sec_number; + pri_no = (int) pri_number; + if (pri_no != bus_no) { + err ("primary numbers in our structures and pci config space don't match.\n"); + return -EINVAL; + } + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SECONDARY_BUS, &sec_number); + sec_no = (int) sec_no; + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SUBORDINATE_BUS, &sub_number); + sub_no = (int) sub_number; + debug ("sub_no is %d, sec_no is %d\n", sub_no, sec_no); + if (sec_no != sub_number) { + err ("there're more buses behind this bridge. Hot removal is not supported. Please choose another card\n"); + return -ENODEV; + } + + bus = ibmphp_find_res_bus (sec_number); + debug ("bus->busno is %x\n", bus->busno); + debug ("sec_number is %x\n", sec_number); + if (!bus) { + err ("cannot find Bus structure for the bridged device\n"); + return -EINVAL; + } + + ibmphp_remove_bus (bus, busno); + + for (count = 0; address[count]; count++) { + /* for 2 BARs */ + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &start_address); + + if (!start_address) { + /* This BAR is not implemented */ + continue; + } + + tmp_address = start_address; + + if (start_address & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + start_address &= PCI_BASE_ADDRESS_IO_MASK; + if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { + err ("cannot find corresponding IO resource to remove\n"); + return -EIO; + } + if (io) + debug ("io->start = %x\n", io->start); + + ibmphp_remove_resource (io); + + /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ + } else { + /* This is Memory */ + if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { + err ("cannot find corresponding PFMEM resource to remove\n"); + return -EINVAL; + } + if (pfmem) + debug ("pfmem->start = %x\n", pfmem->start); + + ibmphp_remove_resource (pfmem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + + } else { + /* regular memory */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { + err ("cannot find corresponding MEM resource to remove\n"); + return -EINVAL; + } + if (mem) + debug ("mem->start = %x\n", mem->start); + + ibmphp_remove_resource (mem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + } + } /* end of mem */ + } /* end of for */ + debug ("%s - exiting, returning success\n", __FUNCTION__); + return 0; +} + +static int unconfigure_boot_card (struct slot *slot_cur) +{ + u16 vendor_id; + u32 class; + u8 hdr_type; + u8 device; + u8 busno; + u8 function; + int rc; + u8 valid_device = 0x00; /* To see if we are ever able to find valid device and read it */ + + debug ("%s - enter\n", __FUNCTION__); + + device = slot_cur->device; + busno = slot_cur->bus; + + debug ("b4 for loop, device is %x\n", device); + /* For every function on the card */ + for (function = 0x0; function < 0x08; function++) { + + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_VENDOR_ID, &vendor_id); + + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + ++valid_device; + + debug ("%s - found correct device\n", __FUNCTION__); + + /* header: x x x x x x x x + * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge + * |_=> 0 = single function device, 1 = multi-function device + */ + + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_HEADER_TYPE, &hdr_type); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_CLASS_REVISION, &class); + + debug ("hdr_type %x, class %x\n", hdr_type, class); + class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ + if (class == PCI_CLASS_NOT_DEFINED_VGA) { + err ("The device %x function %x is VGA compatible and is not supported for hot removing. " + "Please choose another device.\n", device, function); + return -ENODEV; + } else if (class == PCI_CLASS_DISPLAY_VGA) { + err ("The device %x function %x is not supported for hot removing. " + "Please choose another device.\n", device, function); + return -ENODEV; + } + + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + rc = unconfigure_boot_device (busno, device, function); + if (rc) { + err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n", + device, function, busno); + return rc; + } + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIDEVICE: + rc = unconfigure_boot_device (busno, device, function); + if (rc) { + err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n", + device, function, busno); + return rc; + } + break; + case PCI_HEADER_TYPE_BRIDGE: + class >>= 8; + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This device %x function %x is not PCI-to-PCI bridge, " + "and is not supported for hot-removing. " + "Please try another card.\n", device, function); + return -ENODEV; + } + rc = unconfigure_boot_bridge (busno, device, function); + if (rc != 0) { + err ("was not able to hot-remove PPB properly.\n"); + return rc; + } + + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIBRIDGE: + class >>= 8; + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This device %x function %x is not PCI-to-PCI bridge, " + "and is not supported for hot-removing. " + "Please try another card.\n", device, function); + return -ENODEV; + } + rc = unconfigure_boot_bridge (busno, device, function); + if (rc != 0) { + err ("was not able to hot-remove PPB properly.\n"); + return rc; + } + break; + default: + err ("MAJOR PROBLEM!!!! Cannot read device's header \n"); + return -1; + break; + } /* end of switch */ + } /* end of valid device */ + } /* end of for */ + + if (!valid_device) { + err ("Could not find device to unconfigure. Or could not read the card. \n"); + return -1; + } + return 0; +} + +/* + * free the resources of the card (multi, single, or bridged) + * Parameters: slot, flag to say if this is for removing entire module or just + * unconfiguring the device + * TO DO: will probably need to add some code in case there was some resource, + * to remove it... this is from when we have errors in the configure_card... + * !!!!!!!!!!!!!!!!!!!!!!!!!FOR BUSES!!!!!!!!!!!! + * Returns: 0, -1, -ENODEV + */ +int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end) +{ + int i; + int count; + int rc; + struct slot *sl = *slot_cur; + struct pci_func *cur_func = NULL; + struct pci_func *temp_func; + + debug ("%s - enter\n", __FUNCTION__); + + if (!the_end) { + /* Need to unconfigure the card */ + rc = unconfigure_boot_card (sl); + if ((rc == -ENODEV) || (rc == -EIO) || (rc == -EINVAL)) { + /* In all other cases, will still need to get rid of func structure if it exists */ + return rc; + } + } + + if (sl->func) { + debug ("do we come in here? \n"); + cur_func = sl->func; + while (cur_func) { + /* TO DO: WILL MOST LIKELY NEED TO GET RID OF THE BUS STRUCTURE FROM RESOURCES AS WELL */ + if (cur_func->bus) { + /* in other words, it's a PPB */ + count = 2; + } else { + count = 6; + } + + for (i = 0; i < count; i++) { + if (cur_func->io[count]) { + debug ("io[%d] exists \n", count); + if (the_end > 0) + ibmphp_remove_resource (cur_func->io[count]); + cur_func->io[count] = NULL; + } + if (cur_func->mem[count]) { + debug ("mem[%d] exists \n", count); + if (the_end > 0) + ibmphp_remove_resource (cur_func->mem[count]); + cur_func->mem[count] = NULL; + } + if (cur_func->pfmem[count]) { + debug ("pfmem[%d] exists \n", count); + if (the_end > 0) + ibmphp_remove_resource (cur_func->pfmem[count]); + cur_func->pfmem[count] = NULL; + } + } + + temp_func = cur_func->next; + kfree (cur_func); + cur_func = temp_func; + } + } + + sl->func = NULL; + *slot_cur = sl; + return 0; +} + +/* + * add a new bus resulting from hot-plugging a PPB bridge with devices + * + * Input: bus and the amount of resources needed (we know we can assign those, + * since they've been checked already + * Output: bus added to the correct spot + * 0, -1, error + */ +static int add_new_bus (struct bus_node *bus, struct resource_node *io, struct resource_node *mem, struct resource_node *pfmem, u8 parent_busno) +{ + struct range_node *io_range = NULL; + struct range_node *mem_range = NULL; + struct range_node *pfmem_range = NULL; + struct bus_node *cur_bus = NULL; + + /* Trying to find the parent bus number */ + cur_bus = ibmphp_find_res_bus (parent_busno); + if (!cur_bus) { + err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n"); + return -ENODEV; + } + + list_add (&bus->bus_list, &cur_bus->bus_list); + + if (io) { + io_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!io_range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (io_range, 0, sizeof (struct range_node)); + io_range->start = io->start; + io_range->end = io->end; + io_range->rangeno = 1; + bus->noIORanges = 1; + bus->rangeIO = io_range; + } + if (mem) { + mem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!mem_range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem_range, 0, sizeof (struct range_node)); + mem_range->start = mem->start; + mem_range->end = mem->end; + mem_range->rangeno = 1; + bus->noMemRanges = 1; + bus->rangeMem = mem_range; + } + if (pfmem) { + pfmem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!pfmem_range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (pfmem_range, 0, sizeof (struct range_node)); + pfmem_range->start = pfmem->start; + pfmem_range->end = pfmem->end; + pfmem_range->rangeno = 1; + bus->noPFMemRanges = 1; + bus->rangePFMem = pfmem_range; + } + return 0; +} + +/* + * find the 1st available bus number for PPB to set as its secondary bus + * Parameters: bus_number of the primary bus + * Returns: bus_number of the secondary bus or 0xff in case of failure + */ +static u8 find_sec_number (u8 primary_busno, u8 slotno) +{ + int min, max; + u8 busno; + struct bus_info *bus; + + bus = ibmphp_find_same_bus_num (primary_busno); + if (!bus) { + err ("cannot get slot range of the bus from the BIOS\n"); + return 0xff; + } + max = bus->slot_max; + min = bus->slot_min; + if ((slotno > max) || (slotno < min)) { + err ("got the wrong range\n"); + return 0xff; + } + busno = (u8) (slotno - (u8) min); + busno += primary_busno + 0x01; + if (!ibmphp_find_res_bus (busno)) + return busno; + return 0xff; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/ibmphp_res.c linux-2.5/drivers/hotplug/ibmphp_res.c --- linux-2.5.5/drivers/hotplug/ibmphp_res.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/hotplug/ibmphp_res.c Fri Mar 1 15:07:37 2002 @@ -0,0 +1,2067 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include "ibmphp.h" + +static int flags = 0; /* for testing */ + +static void update_resources (struct bus_node *bus_cur, int type, int rangeno); +static int once_over (void); +static int remove_ranges (struct bus_node *, struct bus_node *); +static int update_bridge_ranges (struct bus_node **); +static int add_range (int type, struct range_node *, struct bus_node *); +static void fix_resources (struct bus_node *); +static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8); + +static LIST_HEAD(gbuses); + +static struct bus_node * alloc_error_bus (struct ebda_pci_rsrc * curr) +{ + struct bus_node * newbus; + + newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + if (!newbus) { + err ("out of system memory \n"); + return NULL; + } + + memset (newbus, 0, sizeof (struct bus_node)); + newbus->busno = curr->bus_num; + list_add_tail (&newbus->bus_list, &gbuses); + return newbus; +} + +static struct resource_node * alloc_resources (struct ebda_pci_rsrc * curr) +{ + struct resource_node *rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!rs) { + err ("out of system memory \n"); + return NULL; + } + memset (rs, 0, sizeof (struct resource_node)); + rs->busno = curr->bus_num; + rs->devfunc = curr->dev_fun; + rs->start = curr->start_addr; + rs->end = curr->end_addr; + rs->len = curr->end_addr - curr->start_addr + 1; + return rs; +} + +static int alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus) +{ + struct bus_node * newbus; + struct range_node *newrange; + u8 num_ranges = 0; + + if (first_bus) { + newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + if (!newbus) { + err ("out of system memory. \n"); + return -ENOMEM; + } + memset (newbus, 0, sizeof (struct bus_node)); + newbus->busno = curr->bus_num; + } else { + newbus = *new_bus; + switch (flag) { + case MEM: + num_ranges = newbus->noMemRanges; + break; + case PFMEM: + num_ranges = newbus->noPFMemRanges; + break; + case IO: + num_ranges = newbus->noIORanges; + break; + } + } + + newrange = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!newrange) { + if (first_bus) + kfree (newbus); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newrange, 0, sizeof (struct range_node)); + newrange->start = curr->start_addr; + newrange->end = curr->end_addr; + + if (first_bus || (!num_ranges)) + newrange->rangeno = 1; + else { + /* need to insert our range */ + add_range (flag, newrange, newbus); + debug ("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end); + } + + switch (flag) { + case MEM: + newbus->rangeMem = newrange; + if (first_bus) + newbus->noMemRanges = 1; + else { + debug ("First Memory Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + ++newbus->noMemRanges; + fix_resources (newbus); + } + break; + case IO: + newbus->rangeIO = newrange; + if (first_bus) + newbus->noIORanges = 1; + else { + debug ("First IO Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + ++newbus->noIORanges; + fix_resources (newbus); + } + break; + case PFMEM: + newbus->rangePFMem = newrange; + if (first_bus) + newbus->noPFMemRanges = 1; + else { + debug ("1st PFMemory Primary on Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + ++newbus->noPFMemRanges; + fix_resources (newbus); + } + + break; + } + + *new_bus = newbus; + *new_range = newrange; + return 0; +} + + +/* Notes: + * 1. The ranges are ordered. The buses are not ordered. (First come) + * + * 2. If cannot allocate out of PFMem range, allocate from Mem ranges. PFmemFromMem + * are not sorted. (no need since use mem node). To not change the entire code, we + * also add mem node whenever this case happens so as not to change + * ibmphp_check_mem_resource etc (and since it really is taking Mem resource) + */ + +/***************************************************************************** + * This is the Resource Management initialization function. It will go through + * the Resource list taken from EBDA and fill in this module's data structures + * + * THIS IS NOT TAKING INTO CONSIDERATION IO RESTRICTIONS OF PRIMARY BUSES, + * SINCE WE'RE GOING TO ASSUME FOR NOW WE DON'T HAVE THOSE ON OUR BUSES FOR NOW + * + * Input: ptr to the head of the resource list from EBDA + * Output: 0, -1 or error codes + ***************************************************************************/ +int ibmphp_rsrc_init (void) +{ + struct ebda_pci_rsrc *curr; + struct range_node *newrange = NULL; + struct bus_node *newbus = NULL; + struct bus_node *bus_cur; + struct bus_node *bus_prev; + struct list_head *tmp; + struct resource_node *new_io = NULL; + struct resource_node *new_mem = NULL; + struct resource_node *new_pfmem = NULL; + int rc; + struct list_head *tmp_ebda; + + list_for_each (tmp_ebda, &ibmphp_ebda_pci_rsrc_head) { + curr = list_entry (tmp_ebda, struct ebda_pci_rsrc, ebda_pci_rsrc_list); + if (!(curr->rsrc_type & PCIDEVMASK)) { + /* EBDA still lists non PCI devices, so ignore... */ + debug ("this is not a PCI DEVICE in rsrc_init, please take care\n"); + // continue; + } + + /* this is a primary bus resource */ + if (curr->rsrc_type & PRIMARYBUSMASK) { + /* memory */ + if ((curr->rsrc_type & RESTYPE) == MMASK) { + /* no bus structure exists in place yet */ + if (list_empty (&gbuses)) { + if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("gbuses = NULL, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } else { + bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); + /* found our bus */ + if (bus_cur) { + rc = alloc_bus_range (&bus_cur, &newrange, curr, MEM, 0); + if (rc) + return rc; + } else { + /* went through all the buses and didn't find ours, need to create a new bus node */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1))) + return rc; + + list_add_tail (&newbus->bus_list, &gbuses); + debug ("New Bus, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } + } + } else if ((curr->rsrc_type & RESTYPE) == PFMASK) { + /* prefetchable memory */ + if (list_empty (&gbuses)) { + /* no bus structure exists in place yet */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("gbuses = NULL, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } else { + bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); + if (bus_cur) { + /* found our bus */ + rc = alloc_bus_range (&bus_cur, &newrange, curr, PFMEM, 0); + if (rc) + return rc; + } else { + /* went through all the buses and didn't find ours, need to create a new bus node */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("1st Bus, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } + } + } else if ((curr->rsrc_type & RESTYPE) == IOMASK) { + /* IO */ + if (list_empty (&gbuses)) { + /* no bus structure exists in place yet */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("gbuses = NULL, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } else { + bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); + if (bus_cur) { + rc = alloc_bus_range (&bus_cur, &newrange, curr, IO, 0); + if (rc) + return rc; + } else { + /* went through all the buses and didn't find ours, need to create a new bus node */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("1st Bus, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } + } + + } else { + ; /* type is reserved WHAT TO DO IN THIS CASE??? + NOTHING TO DO??? */ + } + } else { + /* regular pci device resource */ + if ((curr->rsrc_type & RESTYPE) == MMASK) { + /* Memory resource */ + new_mem = alloc_resources (curr); + if (!new_mem) + return -ENOMEM; + new_mem->type = MEM; + /* + * if it didn't find the bus, means PCI dev + * came b4 the Primary Bus info, so need to + * create a bus rangeno becomes a problem... + * assign a -1 and then update once the range + * actually appears... + */ + if (ibmphp_add_resource (new_mem) < 0) { + newbus = alloc_error_bus (curr); + if (!newbus) + return -ENOMEM; + newbus->firstMem = new_mem; + ++newbus->needMemUpdate; + new_mem->rangeno = -1; + } + debug ("Memory resource for device %x, bus %x, [%x - %x]\n", new_mem->devfunc, new_mem->busno, new_mem->start, new_mem->end); + + } else if ((curr->rsrc_type & RESTYPE) == PFMASK) { + /* PFMemory resource */ + new_pfmem = alloc_resources (curr); + if (!new_pfmem) + return -ENOMEM; + new_pfmem->type = PFMEM; + new_pfmem->fromMem = FALSE; + if (ibmphp_add_resource (new_pfmem) < 0) { + newbus = alloc_error_bus (curr); + if (!newbus) + return -ENOMEM; + newbus->firstPFMem = new_pfmem; + ++newbus->needPFMemUpdate; + new_pfmem->rangeno = -1; + } + + debug ("PFMemory resource for device %x, bus %x, [%x - %x]\n", new_pfmem->devfunc, new_pfmem->busno, new_pfmem->start, new_pfmem->end); + } else if ((curr->rsrc_type & RESTYPE) == IOMASK) { + /* IO resource */ + new_io = alloc_resources (curr); + if (!new_io) + return -ENOMEM; + new_io->type = IO; + + /* + * if it didn't find the bus, means PCI dev + * came b4 the Primary Bus info, so need to + * create a bus rangeno becomes a problem... + * Can assign a -1 and then update once the + * range actually appears... + */ + if (ibmphp_add_resource (new_io) < 0) { + newbus = alloc_error_bus (curr); + if (!newbus) + return -ENOMEM; + newbus->firstIO = new_io; + ++newbus->needIOUpdate; + new_io->rangeno = -1; + } + debug ("IO resource for device %x, bus %x, [%x - %x]\n", new_io->devfunc, new_io->busno, new_io->start, new_io->end); + } + } + } + + debug ("after the while loop in rsrc_init \n"); + + list_for_each (tmp, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + /* This is to get info about PPB resources, since EBDA doesn't put this info into the primary bus info */ + rc = update_bridge_ranges (&bus_cur); + if (rc) + return rc; + } + debug ("b4 once_over in rsrc_init \n"); + rc = once_over (); /* This is to align ranges (so no -1) */ + if (rc) + return rc; + debug ("after once_over in rsrc_init \n"); + return 0; +} + +/******************************************************************************** + * This function adds a range into a sorted list of ranges per bus for a particular + * range type, it then calls another routine to update the range numbers on the + * pci devices' resources for the appropriate resource + * + * Input: type of the resource, range to add, current bus + * Output: 0 or -1, bus and range ptrs + ********************************************************************************/ +static int add_range (int type, struct range_node *range, struct bus_node *bus_cur) +{ + struct range_node *range_cur = NULL; + struct range_node *range_prev; + int count = 0, i_init; + int noRanges = 0; + + switch (type) { + case MEM: + range_cur = bus_cur->rangeMem; + noRanges = bus_cur->noMemRanges; + break; + case PFMEM: + range_cur = bus_cur->rangePFMem; + noRanges = bus_cur->noPFMemRanges; + break; + case IO: + range_cur = bus_cur->rangeIO; + noRanges = bus_cur->noIORanges; + break; + } + + range_prev = NULL; + while (range_cur) { + if (range->start < range_cur->start) + break; + range_prev = range_cur; + range_cur = range_cur->next; + count = count + 1; + } + if (!count) { + /* our range will go at the beginning of the list */ + switch (type) { + case MEM: + bus_cur->rangeMem = range; + break; + case PFMEM: + bus_cur->rangePFMem = range; + break; + case IO: + bus_cur->rangeIO = range; + break; + } + range->next = range_cur; + range->rangeno = 1; + i_init = 0; + } else if (!range_cur) { + /* our range will go at the end of the list */ + range->next = NULL; + range_prev->next = range; + range->rangeno = range_prev->rangeno + 1; + return 0; + } else { + /* the range is in the middle */ + range_prev->next = range; + range->next = range_cur; + range->rangeno = range_cur->rangeno; + i_init = range_prev->rangeno; + } + + for (count = i_init; count < noRanges; ++count) { + ++range_cur->rangeno; + range_cur = range_cur->next; + } + + update_resources (bus_cur, type, i_init + 1); + return 0; +} + +/******************************************************************************* + * This routine goes through the list of resources of type 'type' and updates + * the range numbers that they correspond to. It was called from add_range fnc + * + * Input: bus, type of the resource, the rangeno starting from which to update + ******************************************************************************/ +static void update_resources (struct bus_node *bus_cur, int type, int rangeno) +{ + struct resource_node *res = NULL; + u8 eol = FALSE; /* end of list indicator */ + + switch (type) { + case MEM: + if (bus_cur->firstMem) + res = bus_cur->firstMem; + break; + case PFMEM: + if (bus_cur->firstPFMem) + res = bus_cur->firstPFMem; + break; + case IO: + if (bus_cur->firstIO) + res = bus_cur->firstIO; + break; + } + + if (res) { + while (res) { + if (res->rangeno == rangeno) + break; + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else { + eol = TRUE; + break; + } + } + + if (!eol) { + /* found the range */ + while (res) { + ++res->rangeno; + res = res->next; + } + } + } +} + +static void fix_me (struct resource_node *res, struct bus_node *bus_cur, struct range_node *range) +{ + char * str = ""; + switch (res->type) { + case IO: + str = "io"; + break; + case MEM: + str = "mem"; + break; + case PFMEM: + str = "pfmem"; + break; + } + + while (res) { + if (res->rangeno == -1) { + while (range) { + if ((res->start >= range->start) && (res->end <= range->end)) { + res->rangeno = range->rangeno; + debug ("%s->rangeno in fix_resources is %d\n", str, res->rangeno); + switch (res->type) { + case IO: + --bus_cur->needIOUpdate; + break; + case MEM: + --bus_cur->needMemUpdate; + break; + case PFMEM: + --bus_cur->needPFMemUpdate; + break; + } + break; + } + range = range->next; + } + } + if (res->next) + res = res->next; + else + res = res->nextRange; + } + +} + +/***************************************************************************** + * This routine reassigns the range numbers to the resources that had a -1 + * This case can happen only if upon initialization, resources taken by pci dev + * appear in EBDA before the resources allocated for that bus, since we don't + * know the range, we assign -1, and this routine is called after a new range + * is assigned to see the resources with unknown range belong to the added range + * + * Input: current bus + * Output: none, list of resources for that bus are fixed if can be + *******************************************************************************/ +static void fix_resources (struct bus_node *bus_cur) +{ + struct range_node *range; + struct resource_node *res; + + debug ("%s - bus_cur->busno = %d\n", __FUNCTION__, bus_cur->busno); + + if (bus_cur->needIOUpdate) { + res = bus_cur->firstIO; + range = bus_cur->rangeIO; + fix_me (res, bus_cur, range); + } + if (bus_cur->needMemUpdate) { + res = bus_cur->firstMem; + range = bus_cur->rangeMem; + fix_me (res, bus_cur, range); + } + if (bus_cur->needPFMemUpdate) { + res = bus_cur->firstPFMem; + range = bus_cur->rangePFMem; + fix_me (res, bus_cur, range); + } +} + +/******************************************************************************* + * This routine adds a resource to the list of resources to the appropriate bus + * based on their resource type and sorted by their starting addresses. It assigns + * the ptrs to next and nextRange if needed. + * + * Input: 3 diff. resources (nulled out if not needed) + * Output: ptrs assigned (to the node) + * 0 or -1 + *******************************************************************************/ +int ibmphp_add_resource (struct resource_node *res) +{ + struct resource_node *res_cur; + struct resource_node *res_prev; + struct bus_node *bus_cur; + struct range_node *range_cur = NULL; + struct resource_node *res_start = NULL; + + debug ("%s - enter\n", __FUNCTION__); + + bus_cur = find_bus_wprev (res->busno, NULL, 0); + + if (!bus_cur) { + /* didn't find a bus, smth's wrong!!! */ + err ("no bus in the system, either pci_dev's wrong or allocation failed\n"); + return -ENODEV; + } + + /* Normal case */ + switch (res->type) { + case IO: + range_cur = bus_cur->rangeIO; + res_start = bus_cur->firstIO; + break; + case MEM: + range_cur = bus_cur->rangeMem; + res_start = bus_cur->firstMem; + break; + case PFMEM: + range_cur = bus_cur->rangePFMem; + res_start = bus_cur->firstPFMem; + break; + default: + err ("cannot read the type of the resource to add... problem \n"); + return -EINVAL; + } + while (range_cur) { + if ((res->start >= range_cur->start) && (res->end <= range_cur->end)) { + res->rangeno = range_cur->rangeno; + break; + } + range_cur = range_cur->next; + } + + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * this is again the case of rangeno = -1 + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + + if (!range_cur) { + switch (res->type) { + case IO: + ++bus_cur->needIOUpdate; + break; + case MEM: + ++bus_cur->needMemUpdate; + break; + case PFMEM: + ++bus_cur->needPFMemUpdate; + break; + } + res->rangeno = -1; + } + + debug ("The range is %d\n", res->rangeno); + if (!res_start) { + /* no first{IO,Mem,Pfmem} on the bus, 1st IO/Mem/Pfmem resource ever */ + switch (res->type) { + case IO: + bus_cur->firstIO = res; + break; + case MEM: + bus_cur->firstMem = res; + break; + case PFMEM: + bus_cur->firstPFMem = res; + break; + } + res->next = NULL; + res->nextRange = NULL; + } else { + res_cur = res_start; + res_prev = NULL; + + debug ("res_cur->rangeno is %d\n", res_cur->rangeno); + + while (res_cur) { + if (res_cur->rangeno >= res->rangeno) + break; + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + + if (!res_cur) { + /* at the end of the resource list */ + debug ("i should be here, [%x - %x]\n", res->start, res->end); + res_prev->nextRange = res; + res->next = NULL; + res->nextRange = NULL; + } else if (res_cur->rangeno == res->rangeno) { + /* in the same range */ + while (res_cur) { + if (res->start < res_cur->start) + break; + res_prev = res_cur; + res_cur = res_cur->next; + } + if (!res_cur) { + /* the last resource in this range */ + res_prev->next = res; + res->next = NULL; + res->nextRange = res_prev->nextRange; + res_prev->nextRange = NULL; + } else if (res->start < res_cur->start) { + /* at the beginning or middle of the range */ + if (!res_prev) { + switch (res->type) { + case IO: + bus_cur->firstIO = res; + break; + case MEM: + bus_cur->firstMem = res; + break; + case PFMEM: + bus_cur->firstPFMem = res; + break; + } + } else if (res_prev->rangeno == res_cur->rangeno) + res_prev->next = res; + else + res_prev->nextRange = res; + + res->next = res_cur; + res->nextRange = NULL; + } + } else { + /* this is the case where it is 1st occurence of the range */ + if (!res_prev) { + /* at the beginning of the resource list */ + res->next = NULL; + switch (res->type) { + case IO: + res->nextRange = bus_cur->firstIO; + bus_cur->firstIO = res; + break; + case MEM: + res->nextRange = bus_cur->firstMem; + bus_cur->firstMem = res; + break; + case PFMEM: + res->nextRange = bus_cur->firstPFMem; + bus_cur->firstPFMem = res; + break; + } + } else if (res_cur->rangeno > res->rangeno) { + /* in the middle of the resource list */ + res_prev->nextRange = res; + res->next = NULL; + res->nextRange = res_cur; + } + } + } + + debug ("%s - exit\n", __FUNCTION__); + return 0; +} + +/**************************************************************************** + * This routine will remove the resource from the list of resources + * + * Input: io, mem, and/or pfmem resource to be deleted + * Ouput: modified resource list + * 0 or error code + ****************************************************************************/ +int ibmphp_remove_resource (struct resource_node *res) +{ + struct bus_node *bus_cur; + struct resource_node *res_cur = NULL; + struct resource_node *res_prev; + struct resource_node *mem_cur; + char * type = ""; + + bus_cur = find_bus_wprev (res->busno, NULL, 0); + + if (!bus_cur) { + err ("cannot find corresponding bus of the io resource to remove " + "bailing out...\n"); + return -ENODEV; + } + + switch (res->type) { + case IO: + res_cur = bus_cur->firstIO; + type = "io"; + break; + case MEM: + res_cur = bus_cur->firstMem; + type = "mem"; + break; + case PFMEM: + res_cur = bus_cur->firstPFMem; + type = "pfmem"; + break; + default: + err ("unknown type for resource to remove \n"); + return -EINVAL; + } + res_prev = NULL; + + while (res_cur) { + /* ???????????DO WE _NEED_ TO BE CHECKING FOR END AS WELL?????????? */ + if ((res_cur->start == res->start) && (res_cur->end == res->end)) + break; + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + + if (!res_cur) { + if (res->type == PFMEM) { + /* + * case where pfmem might be in the PFMemFromMem list + * so will also need to remove the corresponding mem + * entry + */ + res_cur = bus_cur->firstPFMemFromMem; + res_prev = NULL; + + while (res_cur) { + if ((res_cur->start == res->start) && (res_cur->end == res->end)) { + mem_cur = bus_cur->firstMem; + while (mem_cur) { + if ((mem_cur->start == res_cur->start) + && (mem_cur->end == res_cur->end)) + break; + if (mem_cur->next) + mem_cur = mem_cur->next; + else + mem_cur = mem_cur->nextRange; + } + if (!mem_cur) { + err ("cannot find corresponding mem node for pfmem...\n"); + return -EINVAL; + } + + ibmphp_remove_resource (mem_cur); + if (!res_prev) + bus_cur->firstPFMemFromMem = res_cur->next; + else + res_prev->next = res_cur->next; + kfree (res_cur); + return 0; + } + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + if (!res_cur) { + err ("cannot find pfmem to delete...\n"); + return -EINVAL; + } + } else { + err ("the %s resource is not in the list to be deleted...\n", type); + return -EINVAL; + } + } + if (!res_prev) { + /* first device to be deleted */ + if (res_cur->next) { + switch (res->type) { + case IO: + bus_cur->firstIO = res_cur->next; + break; + case MEM: + bus_cur->firstMem = res_cur->next; + break; + case PFMEM: + bus_cur->firstPFMem = res_cur->next; + break; + } + } else if (res_cur->nextRange) { + switch (res->type) { + case IO: + bus_cur->firstIO = res_cur->nextRange; + break; + case MEM: + bus_cur->firstMem = res_cur->nextRange; + break; + case PFMEM: + bus_cur->firstPFMem = res_cur->nextRange; + break; + } + } else { + switch (res->type) { + case IO: + bus_cur->firstIO = NULL; + break; + case MEM: + bus_cur->firstMem = NULL; + break; + case PFMEM: + bus_cur->firstPFMem = NULL; + break; + } + } + kfree (res_cur); + return 0; + } else { + if (res_cur->next) { + if (res_prev->rangeno == res_cur->rangeno) + res_prev->next = res_cur->next; + else + res_prev->nextRange = res_cur->next; + } else if (res_cur->nextRange) { + res_prev->next = NULL; + res_prev->nextRange = res_cur->nextRange; + } else { + res_prev->next = NULL; + res_prev->nextRange = NULL; + } + kfree (res_cur); + return 0; + } + + return 0; +} + +static struct range_node * find_range (struct bus_node *bus_cur, struct resource_node * res) +{ + struct range_node * range = NULL; + + switch (res->type) { + case IO: + range = bus_cur->rangeIO; + break; + case MEM: + range = bus_cur->rangeMem; + break; + case PFMEM: + range = bus_cur->rangePFMem; + break; + default: + err ("cannot read resource type in find_range \n"); + } + + while (range) { + if (res->rangeno == range->rangeno) + break; + range = range->next; + } + return range; +} + +/***************************************************************************** + * This routine will check to make sure the io/mem/pfmem->len that the device asked for + * can fit w/i our list of available IO/MEM/PFMEM resources. If cannot, returns -EINVAL, + * otherwise, returns 0 + * + * Input: resource + * Ouput: the correct start and end address are inputted into the resource node, + * 0 or -EINVAL + *****************************************************************************/ +int ibmphp_check_resource (struct resource_node *res, u8 bridge) +{ + struct bus_node *bus_cur; + struct range_node *range = NULL; + struct resource_node *res_prev; + struct resource_node *res_cur = NULL; + u32 len_cur = 0, start_cur = 0, len_tmp = 0; + int noranges = 0; + u32 tmp_start; /* this is to make sure start address is divisible by the length needed */ + u32 tmp_divide; + u8 flag = FALSE; + + if (!res) + return -EINVAL; + + if (bridge) { + /* The rules for bridges are different, 4K divisible for IO, 1M for (pf)mem*/ + if (res->type == IO) + tmp_divide = IOBRIDGE; + else + tmp_divide = MEMBRIDGE; + } else + tmp_divide = res->len; + + bus_cur = find_bus_wprev (res->busno, NULL, 0); + + if (!bus_cur) { + /* didn't find a bus, smth's wrong!!! */ + err ("no bus in the system, either pci_dev's wrong or allocation failed \n"); + return -EINVAL; + } + + debug ("%s - enter\n", __FUNCTION__); + debug ("bus_cur->busno is %d\n", bus_cur->busno); + + /* This is a quick fix to not mess up with the code very much. i.e., + * 2000-2fff, len = 1000, but when we compare, we need it to be fff */ + res->len -= 1; + + switch (res->type) { + case IO: + res_cur = bus_cur->firstIO; + noranges = bus_cur->noIORanges; + break; + case MEM: + res_cur = bus_cur->firstMem; + noranges = bus_cur->noMemRanges; + break; + case PFMEM: + res_cur = bus_cur->firstPFMem; + noranges = bus_cur->noPFMemRanges; + break; + default: + err ("wrong type of resource to check \n"); + return -EINVAL; + } + res_prev = NULL; + + while (res_cur) { + range = find_range (bus_cur, res_cur); + debug ("%s - rangeno = %d\n", __FUNCTION__, res_cur->rangeno); + + if (!range) { + err ("no range for the device exists... bailing out...\n"); + return -EINVAL; + } + + /* found our range */ + if (!res_prev) { + /* first time in the loop */ + if ((res_cur->start != range->start) && ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { + debug ("len_tmp = %x\n", len_tmp); + + if ((len_tmp < len_cur) || (len_cur == 0)) { + + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address is divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= res_cur->start - 1) + break; + } + } + + if (flag && len_cur == res->len) { + debug ("but we are not here, right?\n"); + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } + if (!res_cur->next) { + /* last device on the range */ + if ((range->end != res_cur->end) && ((len_tmp = range->end - (res_cur->end + 1)) >= res->len)) { + debug ("len_tmp = %x\n", len_tmp); + if ((len_tmp < len_cur) || (len_cur == 0)) { + + if (((res_cur->end + 1) % tmp_divide) == 0) { + /* just perfect, starting address is divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = res_cur->end + 1; + } else { + /* Needs adjusting */ + tmp_start = res_cur->end + 1; + flag = FALSE; + + while ((len_tmp = range->end - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= range->end) + break; + } + } + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } + + if (res_prev) { + if (res_prev->rangeno != res_cur->rangeno) { + /* 1st device on this range */ + if ((res_cur->start != range->start) && + ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address is divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= res_cur->start - 1) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } else { + /* in the same range */ + if ((len_tmp = res_cur->start - 1 - res_prev->end - 1) >= res->len) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if (((res_prev->end + 1) % tmp_divide) == 0) { + /* just perfect, starting address's divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = res_prev->end + 1; + } else { + /* Needs adjusting */ + tmp_start = res_prev->end + 1; + flag = FALSE; + + while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= res_cur->start - 1) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } + } + /* end if (res_prev) */ + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } /* end of while */ + + + if (!res_prev) { + /* 1st device ever */ + /* need to find appropriate range */ + switch (res->type) { + case IO: + range = bus_cur->rangeIO; + break; + case MEM: + range = bus_cur->rangeMem; + break; + case PFMEM: + range = bus_cur->rangePFMem; + break; + } + while (range) { + if ((len_tmp = range->end - range->start) >= res->len) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address's divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = range->end - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= range->end) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + range = range->next; + } /* end of while */ + + if ((!range) && (len_cur == 0)) { + /* have gone through the list of devices and ranges and haven't found n.e.thing */ + err ("no appropriate range.. bailing out...\n"); + return -EINVAL; + } else if (len_cur) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + + if (!res_cur) { + debug ("prev->rangeno = %d, noranges = %d\n", res_prev->rangeno, noranges); + if (res_prev->rangeno < noranges) { + /* if there're more ranges out there to check */ + switch (res->type) { + case IO: + range = bus_cur->rangeIO; + break; + case MEM: + range = bus_cur->rangeMem; + break; + case PFMEM: + range = bus_cur->rangePFMem; + break; + } + while (range) { + if ((len_tmp = range->end - range->start) >= res->len) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address's divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = range->end - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= range->end) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + range = range->next; + } /* end of while */ + + if ((!range) && (len_cur == 0)) { + /* have gone through the list of devices and ranges and haven't found n.e.thing */ + err ("no appropriate range.. bailing out...\n"); + return -EINVAL; + } else if (len_cur) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } else { + /* no more ranges to check on */ + if (len_cur) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } else { + /* have gone through the list of devices and haven't found n.e.thing */ + err ("no appropriate range.. bailing out...\n"); + return -EINVAL; + } + } + } /* end if(!res_cur) */ + return -EINVAL; +} + +/******************************************************************************** + * This routine is called from remove_card if the card contained PPB. + * It will remove all the resources on the bus as well as the bus itself + * Input: Bus + * Ouput: 0, -ENODEV + ********************************************************************************/ +int ibmphp_remove_bus (struct bus_node *bus, u8 parent_busno) +{ + struct resource_node *res_cur; + struct resource_node *res_tmp; + struct bus_node *prev_bus; + int rc; + + prev_bus = find_bus_wprev (parent_busno, NULL, 0); + + if (!prev_bus) { + err ("something terribly wrong. Cannot find parent bus to the one to remove\n"); + return -ENODEV; + } + + debug ("In ibmphp_remove_bus... prev_bus->busno is %x\n", prev_bus->busno); + + rc = remove_ranges (bus, prev_bus); + if (rc) + return rc; + + if (bus->firstIO) { + res_cur = bus->firstIO; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstIO = NULL; + } + if (bus->firstMem) { + res_cur = bus->firstMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstMem = NULL; + } + if (bus->firstPFMem) { + res_cur = bus->firstPFMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstPFMem = NULL; + } + + if (bus->firstPFMemFromMem) { + res_cur = bus->firstPFMemFromMem; + while (res_cur) { + res_tmp = res_cur; + res_cur = res_cur->next; + + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstPFMemFromMem = NULL; + } + + list_del (&bus->bus_list); + kfree (bus); + return 0; +} + +/****************************************************************************** + * This routine deletes the ranges from a given bus, and the entries from the + * parent's bus in the resources + * Input: current bus, previous bus + * Output: 0, -EINVAL + ******************************************************************************/ +static int remove_ranges (struct bus_node *bus_cur, struct bus_node *bus_prev) +{ + struct range_node *range_cur; + struct range_node *range_tmp; + int i; + struct resource_node *res = NULL; + + if (bus_cur->noIORanges) { + range_cur = bus_cur->rangeIO; + for (i = 0; i < bus_cur->noIORanges; i++) { + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, IO) < 0) + return -EINVAL; + ibmphp_remove_resource (res); + + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + bus_cur->rangeIO = NULL; + } + if (bus_cur->noMemRanges) { + range_cur = bus_cur->rangeMem; + for (i = 0; i < bus_cur->noMemRanges; i++) { + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, MEM) < 0) + return -EINVAL; + + ibmphp_remove_resource (res); + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + bus_cur->rangeMem = NULL; + } + if (bus_cur->noPFMemRanges) { + range_cur = bus_cur->rangePFMem; + for (i = 0; i < bus_cur->noPFMemRanges; i++) { + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, PFMEM) < 0) + return -EINVAL; + + ibmphp_remove_resource (res); + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + bus_cur->rangePFMem = NULL; + } + return 0; +} + +/* + * find the resource node in the bus + * Input: Resource needed, start address of the resource, type or resource + */ +int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resource_node **res, int flag) +{ + struct resource_node *res_cur = NULL; + char * type = ""; + + switch (flag) { + case IO: + res_cur = bus->firstIO; + type = "io"; + break; + case MEM: + res_cur = bus->firstMem; + type = "mem"; + break; + case PFMEM: + res_cur = bus->firstPFMem; + type = "pfmem"; + break; + default: + err ("wrong type of flag \n"); + return -EINVAL; + } + + while (res_cur) { + if (res_cur->start == start_address) { + *res = res_cur; + break; + } + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + + if (!res_cur) { + if (flag == PFMEM) { + res_cur = bus->firstPFMemFromMem; + while (res_cur) { + if (res_cur->start == start_address) { + *res = res_cur; + break; + } + res_cur = res_cur->next; + } + if (!res_cur) { + err ("SOS...cannot find %s resource in the bus. \n", type); + return -EINVAL; + } + } else { + err ("SOS... cannot find %s resource in the bus. \n", type); + return -EINVAL; + } + } + + if (*res) + debug ("*res->start = %x \n", (*res)->start); + + return 0; +} + +/*********************************************************************** + * This routine will free the resource structures used by the + * system. It is called from cleanup routine for the module + * Parameters: none + * Returns: none + ***********************************************************************/ +void ibmphp_free_resources (void) +{ + struct bus_node *bus_cur = NULL; + struct bus_node *bus_tmp; + struct range_node *range_cur; + struct range_node *range_tmp; + struct resource_node *res_cur; + struct resource_node *res_tmp; + struct list_head *tmp; + struct list_head *next; + int i = 0; + flags = 1; + + list_for_each_safe (tmp, next, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + if (bus_cur->noIORanges) { + range_cur = bus_cur->rangeIO; + for (i = 0; i < bus_cur->noIORanges; i++) { + if (!range_cur) + break; + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + } + if (bus_cur->noMemRanges) { + range_cur = bus_cur->rangeMem; + for (i = 0; i < bus_cur->noMemRanges; i++) { + if (!range_cur) + break; + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + } + if (bus_cur->noPFMemRanges) { + range_cur = bus_cur->rangePFMem; + for (i = 0; i < bus_cur->noPFMemRanges; i++) { + if (!range_cur) + break; + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + } + + if (bus_cur->firstIO) { + res_cur = bus_cur->firstIO; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstIO = NULL; + } + if (bus_cur->firstMem) { + res_cur = bus_cur->firstMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstMem = NULL; + } + if (bus_cur->firstPFMem) { + res_cur = bus_cur->firstPFMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstPFMem = NULL; + } + + if (bus_cur->firstPFMemFromMem) { + res_cur = bus_cur->firstPFMemFromMem; + while (res_cur) { + res_tmp = res_cur; + res_cur = res_cur->next; + + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstPFMemFromMem = NULL; + } + + bus_tmp = bus_cur; + list_del (&bus_cur->bus_list); + kfree (bus_tmp); + bus_tmp = NULL; + } +} + +/********************************************************************************* + * This function will go over the PFmem resources to check if the EBDA allocated + * pfmem out of memory buckets of the bus. If so, it will change the range numbers + * and a flag to indicate that this resource is out of memory. It will also move the + * Pfmem out of the pfmem resource list to the PFMemFromMem list, and will create + * a new Mem node + * This routine is called right after initialization + *******************************************************************************/ +static int once_over (void) +{ + struct resource_node *pfmem_cur; + struct resource_node *pfmem_prev; + struct resource_node *mem; + struct bus_node *bus_cur; + struct list_head *tmp; + + list_for_each (tmp, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + if ((!bus_cur->rangePFMem) && (bus_cur->firstPFMem)) { + for (pfmem_cur = bus_cur->firstPFMem, pfmem_prev = NULL; pfmem_cur; pfmem_prev = pfmem_cur, pfmem_cur = pfmem_cur->next) { + pfmem_cur->fromMem = TRUE; + if (pfmem_prev) + pfmem_prev->next = pfmem_cur->next; + else + bus_cur->firstPFMem = pfmem_cur->next; + + if (!bus_cur->firstPFMemFromMem) + pfmem_cur->next = NULL; + else + /* we don't need to sort PFMemFromMem since we're using mem node for + all the real work anyways, so just insert at the beginning of the + list + */ + pfmem_cur->next = bus_cur->firstPFMemFromMem; + + bus_cur->firstPFMemFromMem = pfmem_cur; + + mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem, 0, sizeof (struct resource_node)); + mem->type = MEM; + mem->busno = pfmem_cur->busno; + mem->devfunc = pfmem_cur->devfunc; + mem->start = pfmem_cur->start; + mem->end = pfmem_cur->end; + mem->len = pfmem_cur->len; + if (ibmphp_add_resource (mem) < 0) + err ("Trouble...trouble... EBDA allocated pfmem from mem, but system doesn't display it has this space... unless not PCI device...\n"); + pfmem_cur->rangeno = mem->rangeno; + } /* end for pfmem */ + } /* end if */ + } /* end list_for_each bus */ + return 0; +} + +int ibmphp_add_pfmem_from_mem (struct resource_node *pfmem) +{ + struct bus_node *bus_cur = find_bus_wprev (pfmem->busno, NULL, 0); + + if (!bus_cur) { + err ("cannot find bus of pfmem to add...\n"); + return -ENODEV; + } + + if (bus_cur->firstPFMemFromMem) + pfmem->next = bus_cur->firstPFMemFromMem; + else + pfmem->next = NULL; + + bus_cur->firstPFMemFromMem = pfmem; + + return 0; +} + +/* This routine just goes through the buses to see if the bus already exists. + * It is called from ibmphp_find_sec_number, to find out a secondary bus number for + * bridged cards + * Parameters: bus_number + * Returns: Bus pointer or NULL + */ +struct bus_node *ibmphp_find_res_bus (u8 bus_number) +{ + return find_bus_wprev (bus_number, NULL, 0); +} + +static inline struct bus_node *find_bus_wprev (u8 bus_number, struct bus_node **prev, u8 flag) +{ + struct bus_node *bus_cur; + struct list_head *tmp; + struct list_head *tmp_prev; + + list_for_each (tmp, &gbuses) { + tmp_prev = tmp->prev; + bus_cur = list_entry (tmp, struct bus_node, bus_list); + if (flag) + *prev = list_entry (tmp_prev, struct bus_node, bus_list); + if (bus_cur->busno == bus_number) + return bus_cur; + } + + return NULL; +} + +void ibmphp_print_test (void) +{ + int i = 0; + struct bus_node *bus_cur = NULL; + struct range_node *range; + struct resource_node *res; + struct list_head *tmp; + + if ((!list_empty(&gbuses)) && flags) { + err ("The GBUSES is not NULL?!?!?!?!?\n"); + return; + } + + list_for_each (tmp, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + debug ("This is bus # %d. There are \n", bus_cur->busno); + debug ("IORanges = %d\t", bus_cur->noIORanges); + debug ("MemRanges = %d\t", bus_cur->noMemRanges); + debug ("PFMemRanges = %d\n", bus_cur->noPFMemRanges); + debug ("The IO Ranges are as follows:\n"); + if (bus_cur->rangeIO) { + range = bus_cur->rangeIO; + for (i = 0; i < bus_cur->noIORanges; i++) { + debug ("rangeno is %d\n", range->rangeno); + debug ("[%x - %x]\n", range->start, range->end); + range = range->next; + } + } + + debug ("The Mem Ranges are as follows:\n"); + if (bus_cur->rangeMem) { + range = bus_cur->rangeMem; + for (i = 0; i < bus_cur->noMemRanges; i++) { + debug ("rangeno is %d\n", range->rangeno); + debug ("[%x - %x]\n", range->start, range->end); + range = range->next; + } + } + + debug ("The PFMem Ranges are as follows:\n"); + + if (bus_cur->rangePFMem) { + range = bus_cur->rangePFMem; + for (i = 0; i < bus_cur->noPFMemRanges; i++) { + debug ("rangeno is %d\n", range->rangeno); + debug ("[%x - %x]\n", range->start, range->end); + range = range->next; + } + } + + debug ("The resources on this bus are as follows\n"); + + debug ("IO...\n"); + if (bus_cur->firstIO) { + res = bus_cur->firstIO; + while (res) { + debug ("The range # is %d\n", res->rangeno); + debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug ("[%x - %x], len=%x\n", res->start, res->end, res->len); + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else + break; + } + } + debug ("Mem...\n"); + if (bus_cur->firstMem) { + res = bus_cur->firstMem; + while (res) { + debug ("The range # is %d\n", res->rangeno); + debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug ("[%x - %x], len=%x\n", res->start, res->end, res->len); + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else + break; + } + } + debug ("PFMem...\n"); + if (bus_cur->firstPFMem) { + res = bus_cur->firstPFMem; + while (res) { + debug ("The range # is %d\n", res->rangeno); + debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug ("[%x - %x], len=%x\n", res->start, res->end, res->len); + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else + break; + } + } + + debug ("PFMemFromMem...\n"); + if (bus_cur->firstPFMemFromMem) { + res = bus_cur->firstPFMemFromMem; + while (res) { + debug ("The range # is %d\n", res->rangeno); + debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug ("[%x - %x], len=%x\n", res->start, res->end, res->len); + res = res->next; + } + } + } +} + +/* This routine will read the windows for any PPB we have and update the + * range info for the secondary bus, and will also input this info into + * primary bus, since BIOS doesn't. This is for PPB that are in the system + * on bootup + * Input: primary busno + * Returns: none + * Note: this function doesn't take into account IO restrictions etc, + * so will only work for bridges with no video/ISA devices behind them It + * also will not work for onboard PPB's that can have more than 1 *bus + * behind them All these are TO DO. + * Also need to add more error checkings... (from fnc returns etc) + */ +static int update_bridge_ranges (struct bus_node **bus) +{ + u8 sec_busno, device, function, busno, hdr_type, start_io_address, end_io_address; + u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address; + u32 start_address, end_address, upper_start, upper_end; + struct bus_node *bus_sec; + struct bus_node *bus_cur; + struct resource_node *io; + struct resource_node *mem; + struct resource_node *pfmem; + struct range_node *range; + bus_cur = *bus; + busno = bus_cur->busno; + + debug ("inside update_bridge_ranges \n"); + debug ("bus_cur->busno = %x\n", bus_cur->busno); + + for (device = 0; device < 32; device++) { + for (function = 0x00; function < 0x08; function++) { + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_VENDOR_ID, &vendor_id); + + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_HEADER_TYPE, &hdr_type); + + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIDEVICE: + break; + case PCI_HEADER_TYPE_BRIDGE: + function = 0x8; + case PCI_HEADER_TYPE_MULTIBRIDGE: + /* We assume here that only 1 bus behind the bridge + TO DO: add functionality for several: + temp = secondary; + while (temp < subordinate) { + ... + temp++; + } + */ + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SECONDARY_BUS, &sec_busno); + bus_sec = find_bus_wprev (sec_busno, NULL, 0); + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_BASE, &start_io_address); + pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_LIMIT, &end_io_address); + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_BASE_UPPER16, &upper_io_start); + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_LIMIT_UPPER16, &upper_io_end); + start_address = (start_io_address & PCI_IO_RANGE_MASK) << 8; + start_address |= (upper_io_start << 16); + end_address = (end_io_address & PCI_IO_RANGE_MASK) << 8; + end_address |= (upper_io_end << 16); + + if ((start_address) && (start_address <= end_address)) { + + range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + + if (!range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (range, 0, sizeof (struct range_node)); + range->start = start_address; + range->end = end_address + 0xfff; + + if (bus_sec->noIORanges > 0) + add_range (IO, range, bus_sec); + else { + /* 1st IO Range on the bus */ + range->rangeno = 1; + bus_sec->rangeIO = range; + } + + ++bus_sec->noIORanges; + fix_resources (bus_sec); + + io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!io) { + kfree (range); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (io, 0, sizeof (struct resource_node)); + io->type = IO; + io->busno = bus_cur->busno; + io->devfunc = ((device << 3) | (function & 0x7)); + io->start = start_address; + io->end = end_address + 0xfff; + io->len = io->end - io->start + 1; + + ibmphp_add_resource (io); + } + + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_MEMORY_BASE, &start_mem_address); + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_MEMORY_LIMIT, &end_mem_address); + + start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; + end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16; + + if ((start_address) && (start_address <= end_address)) { + + range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (range, 0, sizeof (struct range_node)); + range->start = start_address; + range->end = end_address + 0xfffff; + + if (bus_sec->noMemRanges > 0) + add_range (MEM, range, bus_sec); + else { + /* 1st Mem Range on the bus */ + range->rangeno = 1; + bus_sec->rangeMem = range; + } + + ++bus_sec->noMemRanges; + fix_resources (bus_sec); + + mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem) { + kfree (range); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem, 0, sizeof (struct resource_node)); + mem->type = MEM; + mem->busno = bus_cur->busno; + mem->devfunc = ((device << 3) | (function & 0x7)); + mem->start = start_address; + mem->end = end_address + 0xfffff; + mem->len = mem->end - mem->start + 1; + ibmphp_add_resource (mem); + } + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_MEMORY_BASE, &start_mem_address); + pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_MEMORY_LIMIT, &end_mem_address); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_BASE_UPPER32, &upper_start); + pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_LIMIT_UPPER32, &upper_end); + start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; + end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16; +#if BITS_PER_LONG == 64 + start_address |= ((long) upper_start) << 32; + end_address |= ((long) upper_end) << 32; +#endif + + if ((start_address) && (start_address <= end_address)) { + + range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (range, 0, sizeof (struct range_node)); + range->start = start_address; + range->end = end_address + 0xfffff; + + if (bus_sec->noPFMemRanges > 0) + add_range (PFMEM, range, bus_sec); + else { + /* 1st PFMem Range on the bus */ + range->rangeno = 1; + bus_sec->rangePFMem = range; + } + + ++bus_sec->noPFMemRanges; + fix_resources (bus_sec); + + pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!pfmem) { + kfree (range); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (pfmem, 0, sizeof (struct resource_node)); + pfmem->type = PFMEM; + pfmem->busno = bus_cur->busno; + pfmem->devfunc = ((device << 3) | (function & 0x7)); + pfmem->start = start_address; + pfmem->end = end_address + 0xfffff; + pfmem->len = pfmem->end - pfmem->start + 1; + pfmem->fromMem = FALSE; + ibmphp_add_resource (pfmem); + } + break; + } /* end of switch */ + } /* end if vendor */ + } /* end for function */ + } /* end for device */ + + bus = &bus_cur; + return 0; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/pci_hotplug_core.c linux-2.5/drivers/hotplug/pci_hotplug_core.c --- linux-2.5.5/drivers/hotplug/pci_hotplug_core.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/hotplug/pci_hotplug_core.c Fri Mar 1 15:07:38 2002 @@ -1,8 +1,8 @@ /* * PCI HotPlug Controller Core * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. + * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001-2002 IBM Corp. * * All rights reserved. * @@ -23,6 +23,8 @@ * * Send feedback to * + * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs + * */ #include @@ -54,7 +56,7 @@ /* local variables */ static int debug; -#define DRIVER_VERSION "0.3" +#define DRIVER_VERSION "0.4" #define DRIVER_AUTHOR "Greg Kroah-Hartman " #define DRIVER_DESC "PCI Hot Plug PCI Core" @@ -74,7 +76,6 @@ }; static struct super_operations pcihpfs_ops; -static struct address_space_operations pcihpfs_aops; static struct file_operations pcihpfs_dir_operations; static struct file_operations default_file_operations; static struct inode_operations pcihpfs_dir_inode_operations; @@ -112,7 +113,6 @@ inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_rdev = NODEV; - inode->i_mapping->a_ops = &pcihpfs_aops; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch (mode & S_IFMT) { default: @@ -154,18 +154,6 @@ return pcihpfs_mknod (dir, dentry, mode | S_IFREG, 0); } -static int pcihpfs_link (struct dentry *old_dentry, struct inode *dir, - struct dentry *dentry) -{ - struct inode *inode = old_dentry->d_inode; - - inode->i_nlink++; - atomic_inc(&inode->i_count); - dget(dentry); - d_instantiate(dentry, inode); - return 0; -} - static inline int pcihpfs_positive (struct dentry *dentry) { return dentry->d_inode && !d_unhashed(dentry); @@ -196,29 +184,15 @@ if (pcihpfs_empty(dentry)) { struct inode *inode = dentry->d_inode; + lock_kernel(); inode->i_nlink--; + unlock_kernel(); dput(dentry); error = 0; } return error; } -static int pcihpfs_rename (struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) -{ - int error = -ENOTEMPTY; - - if (pcihpfs_empty(new_dentry)) { - struct inode *inode = new_dentry->d_inode; - if (inode) { - inode->i_nlink--; - dput(new_dentry); - } - error = 0; - } - return error; -} - #define pcihpfs_rmdir pcihpfs_unlink /* default file operations */ @@ -238,6 +212,7 @@ { loff_t retval = -EINVAL; + lock_kernel(); switch(orig) { case 0: if (offset > 0) { @@ -254,6 +229,7 @@ default: break; } + unlock_kernel(); return retval; } @@ -265,18 +241,9 @@ return 0; } -static int default_sync_file (struct file *file, struct dentry *dentry, int datasync) -{ - return 0; -} - -static struct address_space_operations pcihpfs_aops = { -}; - static struct file_operations pcihpfs_dir_operations = { read: generic_read_dir, readdir: dcache_readdir, - fsync: default_sync_file, }; static struct file_operations default_file_operations = { @@ -284,8 +251,6 @@ write: default_write_file, open: default_open, llseek: default_file_lseek, - fsync: default_sync_file, - mmap: generic_file_mmap, }; /* file ops for the "power" files */ @@ -296,8 +261,6 @@ write: power_write_file, open: default_open, llseek: default_file_lseek, - fsync: default_sync_file, - mmap: generic_file_mmap, }; /* file ops for the "attention" files */ @@ -308,8 +271,6 @@ write: attention_write_file, open: default_open, llseek: default_file_lseek, - fsync: default_sync_file, - mmap: generic_file_mmap, }; /* file ops for the "latch" files */ @@ -319,8 +280,6 @@ write: default_write_file, open: default_open, llseek: default_file_lseek, - fsync: default_sync_file, - mmap: generic_file_mmap, }; /* file ops for the "presence" files */ @@ -330,8 +289,6 @@ write: default_write_file, open: default_open, llseek: default_file_lseek, - fsync: default_sync_file, - mmap: generic_file_mmap, }; /* file ops for the "test" files */ @@ -341,19 +298,15 @@ write: test_write_file, open: default_open, llseek: default_file_lseek, - fsync: default_sync_file, - mmap: generic_file_mmap, }; static struct inode_operations pcihpfs_dir_inode_operations = { create: pcihpfs_create, lookup: pcihpfs_lookup, - link: pcihpfs_link, unlink: pcihpfs_unlink, mkdir: pcihpfs_mkdir, rmdir: pcihpfs_rmdir, mknod: pcihpfs_mknod, - rename: pcihpfs_rename, }; static struct super_operations pcihpfs_ops = { @@ -485,7 +438,7 @@ if (!parent) { dbg("Ah! can not find a parent!\n"); - return -EFAULT; + return -EINVAL; } *dentry = NULL; @@ -686,7 +639,7 @@ default: err ("Illegal value specified for power\n"); - retval = -EFAULT; + retval = -EINVAL; } exit: @@ -1019,7 +972,7 @@ if (slot == NULL) return -ENODEV; if ((slot->info == NULL) || (slot->ops == NULL)) - return -EFAULT; + return -EINVAL; core = kmalloc (sizeof (struct hotplug_slot_core), GFP_KERNEL); if (!core) @@ -1030,7 +983,7 @@ if (get_slot_from_name (slot->name) != NULL) { spin_unlock (&list_lock); kfree (core); - return -EFAULT; + return -EINVAL; } slot->core_priv = core; @@ -1076,6 +1029,12 @@ return 0; } +static inline void update_inode_time (struct inode *inode) +{ + if (inode) + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; +} + /** * pci_hp_change_slot_info - changes the slot's information structure in the core * @name: the name of the slot whose info has changed @@ -1089,6 +1048,7 @@ int pci_hp_change_slot_info (const char *name, struct hotplug_slot_info *info) { struct hotplug_slot *temp; + struct hotplug_slot_core *core; if (info == NULL) return -ENODEV; @@ -1099,6 +1059,24 @@ spin_unlock (&list_lock); return -ENODEV; } + + /* + * check all fields in the info structure, and update timestamps + * for the files referring to the fields that have now changed. + */ + core = temp->core_priv; + if ((core->power_dentry) && + (temp->info->power_status != info->power_status)) + update_inode_time (core->power_dentry->d_inode); + if ((core->attention_dentry) && + (temp->info->attention_status != info->attention_status)) + update_inode_time (core->attention_dentry->d_inode); + if ((core->latch_dentry) && + (temp->info->latch_status != info->latch_status)) + update_inode_time (core->latch_dentry->d_inode); + if ((core->adapter_dentry) && + (temp->info->adapter_status != info->adapter_status)) + update_inode_time (core->adapter_dentry->d_inode); memcpy (temp->info, info, sizeof (struct hotplug_slot_info)); spin_unlock (&list_lock); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/pcihp_acpi.c linux-2.5/drivers/hotplug/pcihp_acpi.c --- linux-2.5.5/drivers/hotplug/pcihp_acpi.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/hotplug/pcihp_acpi.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,397 @@ +/* + * ACPI PCI Hot Plug Controller Driver + * + * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001-2002 IBM Corp. + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to , + * , + * + * + */ + +#include +#include +#include +#include +#include +#include +#include "pci_hotplug.h" +#include "pcihp_acpi.h" + +static LIST_HEAD(slot_list); + +#if !defined(CONFIG_HOTPLUG_PCI_ACPI_MODULE) + #define MY_NAME "pcihp_acpi" +#else + #define MY_NAME THIS_MODULE->name +#endif + +/* local variables */ +static int debug = 1; /* XXX */ +static int num_slots; + +#define DRIVER_VERSION "0.2" +#define DRIVER_AUTHOR "Greg Kroah-Hartman " +#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +static int enable_slot (struct hotplug_slot *slot); +static int disable_slot (struct hotplug_slot *slot); +static int set_attention_status (struct hotplug_slot *slot, u8 value); +static int hardware_test (struct hotplug_slot *slot, u32 value); +static int get_power_status (struct hotplug_slot *slot, u8 *value); +static int get_attention_status (struct hotplug_slot *slot, u8 *value); +static int get_latch_status (struct hotplug_slot *slot, u8 *value); +static int get_adapter_status (struct hotplug_slot *slot, u8 *value); + +static struct hotplug_slot_ops acpi_hotplug_slot_ops = { + owner: THIS_MODULE, + enable_slot: enable_slot, + disable_slot: disable_slot, + set_attention_status: set_attention_status, + hardware_test: hardware_test, + get_power_status: get_power_status, + get_attention_status: get_attention_status, + get_latch_status: get_latch_status, + get_adapter_status: get_adapter_status, +}; + + +/* Inline functions to check the sanity of a pointer that is passed to us */ +static inline int slot_paranoia_check (struct slot *slot, const char *function) +{ + if (!slot) { + dbg("%s - slot == NULL", function); + return -1; + } + if (slot->magic != SLOT_MAGIC) { + dbg("%s - bad magic number for slot", function); + return -1; + } + if (!slot->hotplug_slot) { + dbg("%s - slot->hotplug_slot == NULL!", function); + return -1; + } + return 0; +} + +static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) +{ + struct slot *slot; + + if (!hotplug_slot) { + dbg("%s - hotplug_slot == NULL", function); + return NULL; + } + + slot = (struct slot *)hotplug_slot->private; + if (slot_paranoia_check (slot, function)) + return NULL; + return slot; +} + + +static int enable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + /* enable the specified slot */ + retval = pcihp_acpi_enable_slot (slot->acpi_slot); + + return retval; +} + +static int disable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + /* disable the specified slot */ + retval = pcihp_acpi_disable_slot (slot->acpi_slot); + + return retval; +} + +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + /* TBD + * ACPI doesn't have known method to manipulate + * attention status LED + */ + switch (status) { + case 0: + /* FIXME turn light off */ + slot->attention_status = 0; + break; + + case 1: + default: + /* FIXME turn light on */ + slot->attention_status = 1; + break; + } + + return retval; +} + +static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + err ("No hardware tests are defined for this driver"); + retval = -ENODEV; + + return retval; +} + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + *value = pcihp_acpi_get_power_status (slot->acpi_slot); + + return retval; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + *value = slot->attention_status; + + return retval; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + *value = pcihp_acpi_get_latch_status (slot->acpi_slot); + + return retval; +} + +static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + *value = pcihp_acpi_get_adapter_status (slot->acpi_slot); + + return retval; +} + +static int init_acpi (void) +{ + int retval; + + dbg("init_acpi"); /* XXX */ + /* initialize internal data structure etc. */ + retval = pcihp_acpi_glue_init(); + + /* read initial number of slots */ + if (!retval) { + num_slots = pcihp_acpi_get_num_slots(); + if (num_slots == 0) + retval = -ENODEV; + } + + return retval; +} + +static void exit_acpi (void) +{ + /* deallocate internal data structures etc. */ + pcihp_acpi_glue_exit(); +} + +#define SLOT_NAME_SIZE 10 +static void make_slot_name (struct slot *slot) +{ + /* FIXME - get this from the ACPI representation of the slot */ + snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d", slot->number); +} + +static int init_slots (void) +{ + struct slot *slot; + int retval = 0; + int i; + + for (i = 0; i < num_slots; ++i) { + slot = kmalloc (sizeof (struct slot), GFP_KERNEL); + if (!slot) + return -ENOMEM; + memset(slot, 0, sizeof(struct slot)); + + slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!slot->hotplug_slot) { + kfree (slot); + return -ENOMEM; + } + memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); + + slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!slot->hotplug_slot->info) { + kfree (slot->hotplug_slot); + kfree (slot); + return -ENOMEM; + } + memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); + + slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); + if (!slot->hotplug_slot->name) { + kfree (slot->hotplug_slot->info); + kfree (slot->hotplug_slot); + kfree (slot); + return -ENOMEM; + } + + slot->magic = SLOT_MAGIC; + slot->number = i; + + slot->hotplug_slot->private = slot; + make_slot_name (slot); + slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; + + slot->acpi_slot = get_slot_from_id (i); + slot->hotplug_slot->info->power_status = pcihp_acpi_get_power_status(slot->acpi_slot); + slot->hotplug_slot->info->attention_status = pcihp_acpi_get_attention_status(slot->acpi_slot); + slot->hotplug_slot->info->latch_status = pcihp_acpi_get_latch_status(slot->acpi_slot); + slot->hotplug_slot->info->adapter_status = pcihp_acpi_get_adapter_status(slot->acpi_slot); + + dbg ("registering slot %d", i); + retval = pci_hp_register (slot->hotplug_slot); + if (retval) { + err ("pci_hp_register failed with error %d", retval); + kfree (slot->hotplug_slot->info); + kfree (slot->hotplug_slot->name); + kfree (slot->hotplug_slot); + kfree (slot); + return retval; + } + + /* add slot to our internal list */ + list_add (&slot->slot_list, &slot_list); + } + + return retval; +} + +static void cleanup_slots (void) +{ + struct list_head *tmp; + struct slot *slot; + + list_for_each (tmp, &slot_list) { + slot = list_entry (tmp, struct slot, slot_list); + list_del (&slot->slot_list); + pci_hp_deregister (slot->hotplug_slot); + kfree (slot->hotplug_slot->info); + kfree (slot->hotplug_slot->name); + kfree (slot->hotplug_slot); + kfree (slot); + } + + return; +} + +static int __init pcihp_acpi_init(void) +{ + int retval; + + /* read all the ACPI info from the system */ + retval = init_acpi(); + if (retval) + return retval; + + retval = init_slots(); + if (retval) + return retval; + + info (DRIVER_DESC " version: " DRIVER_VERSION); + return 0; +} + +static void __exit pcihp_acpi_exit(void) +{ + cleanup_slots(); + exit_acpi(); +} + +module_init(pcihp_acpi_init); +module_exit(pcihp_acpi_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/pcihp_acpi.h linux-2.5/drivers/hotplug/pcihp_acpi.h --- linux-2.5.5/drivers/hotplug/pcihp_acpi.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/hotplug/pcihp_acpi.h Sun Mar 3 17:54:35 2002 @@ -0,0 +1,231 @@ +/* + * ACPI PCI Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to , + * , + * + * + */ + +#ifndef _PCIHP_ACPI_H +#define _PCIHP_ACPI_H + +#include "include/acpi.h" + +#if ACPI_CA_VERSION < 0x20020201 +/* until we get a new version of the ACPI driver for both ia32 and ia64 ... */ +#define acpi_util_eval_error(h,p,s) + +static acpi_status +acpi_evaluate_integer ( + acpi_handle handle, + acpi_string pathname, + acpi_object_list *arguments, + unsigned long *data) +{ + acpi_status status = AE_OK; + acpi_object element; + acpi_buffer buffer = {sizeof(acpi_object), &element}; + + if (!data) + return AE_BAD_PARAMETER; + + status = acpi_evaluate_object(handle, pathname, arguments, &buffer); + if (ACPI_FAILURE(status)) { + acpi_util_eval_error(handle, pathname, status); + return status; + } + + if (element.type != ACPI_TYPE_INTEGER) { + acpi_util_eval_error(handle, pathname, AE_BAD_DATA); + return AE_BAD_DATA; + } + + *data = element.integer.value; + + return AE_OK; +} +#else /* ACPI_CA_VERSION < 0x20020201 */ +#include "acpi_bus.h" +#endif /* ACPI_CA_VERSION < 0x20020201 */ + +/* compatibility stuff */ +#ifndef ACPI_MEMORY_RANGE +#define ACPI_MEMORY_RANGE MEMORY_RANGE +#endif + +#ifndef ACPI_IO_RANGE +#define ACPI_IO_RANGE IO_RANGE +#endif + +#ifndef ACPI_BUS_NUMBER_RANGE +#define ACPI_BUS_NUMBER_RANGE BUS_NUMBER_RANGE +#endif + +#ifndef ACPI_PREFETCHABLE_MEMORY +#define ACPI_PREFETCHABLE_MEMORY PREFETCHABLE_MEMORY +#endif + +#ifndef ACPI_PRODUCER +#define ACPI_PRODUCER PRODUCER +#endif + + +#define dbg(format, arg...) \ + do { \ + if (debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + MY_NAME , ## arg); \ + } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) + +/* + * types and constants + */ + +#define SLOT_MAGIC 0x67267322 + +struct pcihp_acpi_bridge; +struct pcihp_acpi_slot; + +/* slot information for each *physical* slot */ + +struct slot { + u32 magic; + u8 number; + struct hotplug_slot *hotplug_slot; + struct list_head slot_list; + + int attention_status; + + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + + /* if there are multiple corresponding slot objects, + this point to one of them */ + struct pcihp_acpi_slot *acpi_slot; + + struct pci_dev *pci_dev; +}; + +#define RESOURCE_TYPE_IO (1) +#define RESOURCE_TYPE_MEM (2) +#define RESOURCE_TYPE_PREFETCH (3) +#define RESOURCE_TYPE_BUS (4) + +/* TBD 64bit resource support */ +struct pci_resource { + struct pci_resource * next; + u32 base; + u32 length; +}; + +/* bridge information for each bridge device in ACPI namespace */ + +struct pcihp_acpi_bridge { + struct list_head list; + acpi_handle handle; + struct pcihp_acpi_slot *slots; + int nr_slots; + u8 seg; + u8 bus; + u8 sub; + u32 status; + u32 flags; + + /* resources on this bus (free resources) */ + struct pci_resource *free_io; + struct pci_resource *free_mem; + struct pci_resource *free_prefetch; + struct pci_resource *free_bus; + + /* used resources (embedded or owned resources) */ + struct pci_resource *used_io; + struct pci_resource *used_mem; + struct pci_resource *used_prefetch; + struct pci_resource *used_bus; +}; + +/* + * slot information for each slot object in ACPI namespace + * usually 8 objects per slot (for each PCI function) + */ + +struct pcihp_acpi_slot { + struct pcihp_acpi_slot *next; + struct pcihp_acpi_bridge *bridge; /* this slot located on */ + struct list_head sibling; /* one slot may have different + objects (i.e. for each function) */ + acpi_handle handle; + u32 id; /* slot id (this driver specific) */ + u8 device; /* pci device# */ + u8 function; /* pci function# */ + u8 pin; /* pci interrupt pin */ + u32 sun; /* _SUN */ + u32 flags; /* see below */ + u32 status; /* _STA */ +}; + +/* PCI bus bridge HID */ +#define ACPI_PCI_ROOT_HID "PNP0A03" + +/* ACPI _STA method value (ignore bit 4; battery present) */ +#define ACPI_STA_PRESENT (0x00000001) +#define ACPI_STA_ENABLED (0x00000002) +#define ACPI_STA_SHOW_IN_UI (0x00000004) +#define ACPI_STA_FUNCTIONAL (0x00000008) +#define ACPI_STA_ALL (0x0000000f) + +/* bridge flags */ +#define BRIDGE_HAS_STA (0x00000001) + +/* slot flags */ + +#define SLOT_HAS_EJ0 (0x00000001) +#define SLOT_HAS_PS0 (0x00000002) +#define SLOT_HAS_PS3 (0x00000004) + +/* function prototypes */ + +/* pcihp_acpi_glue.c */ +extern int pcihp_acpi_glue_init (void); +extern void pcihp_acpi_glue_exit (void); +extern int pcihp_acpi_get_num_slots (void); +extern struct pcihp_acpi_slot *get_slot_from_id (int id); + +extern int pcihp_acpi_enable_slot (struct pcihp_acpi_slot *slot); +extern int pcihp_acpi_disable_slot (struct pcihp_acpi_slot *slot); +extern u8 pcihp_acpi_get_power_status (struct pcihp_acpi_slot *slot); +extern u8 pcihp_acpi_get_attention_status (struct pcihp_acpi_slot *slot); +extern u8 pcihp_acpi_get_latch_status (struct pcihp_acpi_slot *slot); +extern u8 pcihp_acpi_get_adapter_status (struct pcihp_acpi_slot *slot); + +#endif /* _PCIHP_ACPI_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/pcihp_acpi_ctrl.c linux-2.5/drivers/hotplug/pcihp_acpi_ctrl.c --- linux-2.5.5/drivers/hotplug/pcihp_acpi_ctrl.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/hotplug/pcihp_acpi_ctrl.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,642 @@ +/* + * ACPI PCI HotPlug Utility functions + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to , + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#define _LINUX /* for acpi subcomponent */ + +#include "include/acpi.h" + +#include "pci_hotplug.h" +#include "pchihp_acpi.h" + +#if !defined(CONFIG_HOTPLUG_PCI_MODULE) + #define MY_NAME "pci_hotplug" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(fmt, arg...) do { if (debug) printk(KERN_WARNING "%s: "__FUNCTION__": " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + +/* local variables */ +static int debug = 0; + +/* + * sort_by_size + * + * Sorts nodes on the list by their length. + * Smallest first. + * + */ +static int sort_by_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->length > (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length > current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } // End of out_of_order loop + + return(0); +} + + +/* + * sort_by_max_size + * + * Sorts nodes on the list by their length. + * Largest first. + * + */ +static int sort_by_max_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->length < (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length < current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } // End of out_of_order loop + + return(0); +} + +/* + * get_io_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length that is not in the + * ISA aliasing window. If it finds a node larger than "size" + * it will split it up. + * + * size must be a power of two. + */ +struct pci_resource *hotplug_get_io_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( hotplug_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (node->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of non-aligned base + + // Don't need to check if too small since we already did + if (node->length > size) { + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + // For IO make sure it's not in the ISA aliasing space + if (node->base & 0x300L) + continue; + + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + + return(node); +} + + +/* + * get_max_resource + * + * Gets the largest node that is at least "size" big from the + * list pointed to by head. It aligns the node on top and bottom + * to "size" alignment before returning it. + */ +struct pci_resource *hotplug_get_max_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *max; + struct pci_resource *temp; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if (hotplug_resource_sort_and_combine(head)) + return(NULL); + + if (sort_by_max_size(head)) + return(NULL); + + for (max = *head;max; max = max->next) { + + // If not big enough we could probably just bail, + // instead we'll continue to the next. + if (max->length < size) + continue; + + if (max->base & (size - 1)) { + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (max->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((max->length - (temp_dword - max->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = max->base; + split_node->length = temp_dword - max->base; + max->base = temp_dword; + max->length -= split_node->length; + + // Put it next in the list + split_node->next = max->next; + max->next = split_node; + } + + if ((max->base + max->length) & (size - 1)) { + // this one isn't end aligned properly at the top + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + temp_dword = ((max->base + max->length) & ~(size - 1)); + split_node->base = temp_dword; + split_node->length = max->length + max->base + - split_node->base; + max->length -= split_node->length; + + // Put it in the list + split_node->next = max->next; + max->next = split_node; + } + + // Make sure it didn't shrink too much when we aligned it + if (max->length < size) + continue; + + // Now take it out of the list + temp = (struct pci_resource*) *head; + if (temp == max) { + *head = max->next; + } else { + while (temp && temp->next != max) { + temp = temp->next; + } + + temp->next = max->next; + } + + max->next = NULL; + return(max); + } + + // If we get here, we couldn't find one + return(NULL); +} + + +/* + * get_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length. If it finds a node + * larger than "size" it will split it up. + * + * size must be a power of two. + */ +struct pci_resource *hotplug_get_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( hotplug_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + dbg(__FUNCTION__": req_size =%x node=%p, base=%x, length=%x\n", + size, node, node->base, node->length); + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + dbg(__FUNCTION__": not aligned\n"); + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (node->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of non-aligned base + + // Don't need to check if too small since we already did + if (node->length > size) { + dbg(__FUNCTION__": too big\n"); + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + dbg(__FUNCTION__": got one!!!\n"); + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + return(node); +} + +/* + * get_resource_with_base + * + * this function + * returns the first node of "size" length located at specified base address. + * If it finds a node larger than "size" it will split it up. + * + * size must be a power of two. + */ +struct pci_resource *hotplug_get_resource_with_base (struct pci_resource **head, u32 base, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( hotplug_resource_sort_and_combine(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n", + base, size, node, node->base, node->length); + if (node->base > base) + continue; + + if ((node->base + node->length) < (base + size)) + continue; + + if (node->base < base) { + dbg(": split 1\n"); + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = base; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } + + dbg(": 2st req_base=%x req_size =%x node=%p, base=%x, length=%x\n", + base, size, node, node->base, node->length); + + // Don't need to check if too small since we already did + if (node->length >= size) { + dbg(": split 2\n"); + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + dbg(": got one!!!\n"); + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + return(node); +} + +/* + * hotplug_resource_sort_and_combine + * + * Sorts all of the nodes in the list in ascending order by + * their base addresses. Also does garbage collection by + * combining adjacent nodes. + * + * returns 0 if success + */ +int hotplug_resource_sort_and_combine(struct pci_resource **head) +{ + struct pci_resource *node1; + struct pci_resource *node2; + int out_of_order = 1; + + dbg(__FUNCTION__": head = %p, *head = %p\n", head, *head); + + if (!(*head)) + return(1); + + dbg("*head->next = %p\n",(*head)->next); + + if (!(*head)->next) + return(0); /* only one item on the list, already sorted! */ + + dbg("*head->base = 0x%x\n",(*head)->base); + dbg("*head->next->base = 0x%x\n",(*head)->next->base); + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->base > (*head)->next->base)) { + node1 = *head; + (*head) = (*head)->next; + node1->next = (*head)->next; + (*head)->next = node1; + out_of_order++; + } + + node1 = (*head); + + while (node1->next && node1->next->next) { + if (node1->next->base > node1->next->next->base) { + out_of_order++; + node2 = node1->next; + node1->next = node1->next->next; + node1 = node1->next; + node2->next = node1->next; + node1->next = node2; + } else + node1 = node1->next; + } + } // End of out_of_order loop + + node1 = *head; + + while (node1 && node1->next) { + if ((node1->base + node1->length) == node1->next->base) { + // Combine + dbg("8..\n"); + node1->length += node1->next->length; + node2 = node1->next; + node1->next = node1->next->next; + kfree(node2); + } else + node1 = node1->next; + } + + return(0); +} + +/* +EXPORT_SYMBOL(hotplug_get_io_resource); +EXPORT_SYMBOL(hotplug_get_max_resource); +EXPORT_SYMBOL(hotplug_get_resource); +EXPORT_SYMBOL(hotplug_resource_sort_and_combine); +*/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/hotplug/pcihp_acpi_glue.c linux-2.5/drivers/hotplug/pcihp_acpi_glue.c --- linux-2.5.5/drivers/hotplug/pcihp_acpi_glue.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/hotplug/pcihp_acpi_glue.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,757 @@ +/* + * ACPI PCI HotPlug glue functions to ACPI CA subsystem + * + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include "pcihp_acpi.h" + +/* + * TODO: + * resource management + * irq related interface? (_PRT) + * consider locking + */ + +static LIST_HEAD(bridge_list); + +static int debug = 1; /* XXX set 0 after debug */ +#define MY_NAME "pcihp_acpi_glue" + +static void handle_hotplug_event (acpi_handle, u32, void *); + +/* + * initialization & terminatation routines + */ + +/* + * Ejectable slot satisfies at least these conditions: + * 1. has _ADR method + * 2. has _STA method + * 3. has _EJ0 method + * + * optionally + * 1. has _PS0 method + * 2. has _PS3 method + * 3. TBD... + */ + +/* callback routine to check the existence of ejectable slots */ +static acpi_status +is_ejectable_slot (acpi_handle handle, u32 lvl, void *context, void **rv) +{ + acpi_status status; + acpi_handle tmp; + int *count = (int *)context; + + status = acpi_get_handle(handle, "_ADR", &tmp); + + if (ACPI_FAILURE(status)) { + return AE_OK; + } + + status = acpi_get_handle(handle, "_STA", &tmp); + + if (ACPI_FAILURE(status)) { + return AE_OK; + } + + status = acpi_get_handle(handle, "_EJ0", &tmp); + + if (ACPI_FAILURE(status)) { + return AE_OK; + } + + (*count)++; + + /* only one ejectable slot is enough */ + return AE_CTRL_TERMINATE; +} + + +/* callback routine to register each ACPI PCI slot object */ +static acpi_status +register_slot (acpi_handle handle, u32 lvl, void *context, void **rv) +{ + struct pcihp_acpi_bridge *bridge = (struct pcihp_acpi_bridge *)context; + struct pcihp_acpi_slot *slot, *newslot; + acpi_handle tmp; + acpi_status status = AE_OK; + static int num_slots = 0; /* XXX */ + unsigned long adr, sun, sta; + + status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); + + if (ACPI_FAILURE(status)) { + return AE_OK; + } + + status = acpi_get_handle(handle, "_EJ0", &tmp); + + if (ACPI_FAILURE(status)) { + dbg("This slot doesn't have _EJ0"); + //return AE_OK; + } + + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + + if (ACPI_FAILURE(status)) { + dbg("This slot doesn't have _STA"); + //return AE_OK; + } + + newslot = kmalloc(sizeof(struct pcihp_acpi_slot), GFP_KERNEL); + if (!newslot) { + return AE_NO_MEMORY; + } + + memset(newslot, 0, sizeof(struct pcihp_acpi_slot)); + + INIT_LIST_HEAD(&newslot->sibling); + newslot->bridge = bridge; + newslot->handle = handle; + newslot->device = (adr >> 16) & 0xffff; + newslot->function = adr & 0xffff; + newslot->status = sta; + newslot->sun = -1; + newslot->flags = SLOT_HAS_EJ0; + newslot->id = num_slots++; + bridge->nr_slots++; + + dbg("new slot id=%d device=0x%d function=0x%x", newslot->id, newslot->device, newslot->function); + + status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); + if (ACPI_SUCCESS(status)) { + newslot->sun = sun; + } + + if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) { + newslot->flags |= SLOT_HAS_PS0; + } + + if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) { + newslot->flags |= SLOT_HAS_PS3; + } + + /* search for objects that share the same slot */ + for (slot = bridge->slots; slot; slot = slot->next) + if (slot->device == newslot->device) { + dbg("found a sibling slot!"); + list_add(&slot->sibling, &newslot->sibling); + newslot->id = slot->id; + num_slots --; + bridge->nr_slots --; + break; + } + + /* link myself to bridge's slot list */ + newslot->next = bridge->slots; + bridge->slots = newslot; + + return AE_OK; +} + +/* see if it's worth managing this brige */ +static int +detect_ejectable_slots (acpi_handle *root) +{ + acpi_status status; + int count; + + count = 0; + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root, ACPI_UINT32_MAX, + is_ejectable_slot, (void *)&count, NULL); + + dbg("%s: count=%d", __FUNCTION__, count); + return count; +} + + +/* + * push one resource to resource list + * + * TBD: use hotplug_resource_sort_and_combine + * TBD: 64bit resource handling (is it really used?) + */ +static void +push_resource (u32 base, u32 length, struct pci_resource **resource) +{ + struct pci_resource *resp, *newres; + int coalesced = 0; + + if (length == 0) { + dbg("zero sized resource. ignored."); + return; + } + + for (resp = *resource; resp; resp = resp->next) { + + /* coalesce contiguous region */ + + if (resp->base + resp->length == base) { + resp->length += length; + coalesced = 1; + break; + } + } + + if (!coalesced) { + newres = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!newres) { + /* TBD panic? */ + return; + } + newres->base = base; + newres->length = length; + newres->next = (*resource); + *resource = newres; + } +} + + +/* decode ACPI _CRS data and convert into our internal resource list */ +static void +decode_acpi_resource (acpi_resource *resource, struct pcihp_acpi_bridge *bridge) +{ + acpi_resource_address16 *address16_data; + acpi_resource_address32 *address32_data; + //acpi_resource_address64 *address64_data; + + u32 resource_type, producer_consumer, min_address_range, max_address_range, address_length; + u16 cache_attribute = 0; + + int done = 0, found; + + /* shut up gcc */ + resource_type = producer_consumer = min_address_range = max_address_range = address_length = 0; + + while (!done) { + found = 0; + + switch (resource->id) { + case ACPI_RSTYPE_ADDRESS16: + address16_data = (acpi_resource_address16 *)&resource->data; + resource_type = address16_data->resource_type; + producer_consumer = address16_data->producer_consumer; + min_address_range = address16_data->min_address_range; + max_address_range = address16_data->max_address_range; + address_length = address16_data->address_length; + if (resource_type == ACPI_MEMORY_RANGE) + cache_attribute = address16_data->attribute.memory.cache_attribute; + found = 1; + break; + + case ACPI_RSTYPE_ADDRESS32: + address32_data = (acpi_resource_address32 *)&resource->data; + resource_type = address32_data->resource_type; + producer_consumer = address32_data->producer_consumer; + min_address_range = address32_data->min_address_range; + max_address_range = address32_data->max_address_range; + address_length = address32_data->address_length; + if (resource_type == ACPI_MEMORY_RANGE) + cache_attribute = address32_data->attribute.memory.cache_attribute; + found = 1; + break; +/* + case ACPI_RSTYPE_ADDRESS64: + address64_data = (acpi_resource_address64 *)&resource->data; + resource_type = address64_data->resource_type; + break; +*/ + case ACPI_RSTYPE_END_TAG: + done = 1; + break; + + default: + /* ignore */ + break; + } + + resource = (acpi_resource *)((char*)resource + resource->length); + if (found && producer_consumer == ACPI_PRODUCER) { + switch (resource_type) { + case ACPI_MEMORY_RANGE: + if (cache_attribute == ACPI_PREFETCHABLE_MEMORY) { + dbg("resource type: prefetchable memory 0x%x - 0x%x", min_address_range, max_address_range); + push_resource(min_address_range, + address_length, + &bridge->free_prefetch); + } else { + dbg("resource type: memory 0x%x - 0x%x", min_address_range, max_address_range); + push_resource(min_address_range, + address_length, + &bridge->free_mem); + } + break; + case ACPI_IO_RANGE: + dbg("resource type: io 0x%x - 0x%x", min_address_range, max_address_range); + push_resource(min_address_range, + address_length, + &bridge->free_io); + break; + case ACPI_BUS_NUMBER_RANGE: + dbg("resource type: bus number %d - %d", min_address_range, max_address_range); + push_resource(min_address_range, + address_length, + &bridge->free_bus); + break; + default: + /* invalid type */ + break; + } + } + } +} + + +/* allocate and initialize bridge data structure */ +static int add_bridge (acpi_handle *handle) +{ + struct pcihp_acpi_bridge *bridge; + acpi_status status; + acpi_buffer buffer; + unsigned long tmp; + acpi_handle dummy_handle; + int sta = -1; + + status = acpi_get_handle(handle, "_STA", &dummy_handle); + if (ACPI_SUCCESS(status)) { + status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); + if (ACPI_FAILURE(status)) { + dbg("%s: _STA evaluation failure", __FUNCTION__); + return 0; + } + sta = tmp; + } + + if (sta >= 0 && !(sta & ACPI_STA_PRESENT)) + /* don't register this object */ + return 0; + + dbg("%s: _STA: 0x%x", __FUNCTION__, (unsigned int)sta); + + /* check if this bridge has ejectable slots */ + + detect_ejectable_slots(handle); + //if (detect_ejectable_slots(handle) == 0) + //return 0; + + /* allocate per-bridge data structure and fill in */ + + bridge = kmalloc(sizeof(struct pcihp_acpi_bridge), GFP_KERNEL); + if (bridge == NULL) + return -ENOMEM; + + memset(bridge, 0, sizeof(struct pcihp_acpi_bridge)); + + if (sta >= 0) + bridge->flags |= BRIDGE_HAS_STA; + + /* get PCI segment number */ + status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp); + + if (ACPI_SUCCESS(status)) { + bridge->seg = tmp; + } else { + bridge->seg = 0; + } + + /* get PCI bus number */ + status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp); + + if (ACPI_SUCCESS(status)) { + bridge->bus = tmp; + } else { + bridge->bus = 0; + } + + /* to be overridden when we decode _CRS */ + bridge->sub = bridge->bus; + + /* register all slot objects under this bridge */ + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX, + register_slot, bridge, NULL); + + /* decode resources */ + buffer.length = 0; + buffer.pointer = NULL; + + + /* TBD use new ACPI_ALLOCATE_BUFFER */ + status = acpi_get_current_resources(handle, &buffer); + if (status != AE_BUFFER_OVERFLOW) { + return -1; + } + + buffer.pointer = kmalloc(buffer.length, GFP_KERNEL); + if (!buffer.pointer) { + return -1; + } + + status = acpi_get_current_resources(handle, &buffer); + if (ACPI_FAILURE(status)) { + return -1; + } + + decode_acpi_resource(buffer.pointer, bridge); + + /* TBD decode _HPP (hot plug parameters) */ + // decode_hpp(bridge); + + kfree(buffer.pointer); + + /* check already allocated resources */ + /* TBD */ + + /* install notify handler */ + dbg("installing notify handler"); + status = acpi_install_notify_handler(handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event, NULL); + + if (ACPI_FAILURE(status)) { + err("failed to register interrupt notify handler"); + } + + list_add(&bridge->list, &bridge_list); + + return 0; +} + + +/* callback routine to enumerate all the bridges in ACPI namespace */ +static acpi_status +check_pci_bridge (acpi_handle handle, u32 lvl, void *context, void **rv) +{ + acpi_status status; + acpi_device_info info; + char objname[5]; + acpi_buffer buffer = { sizeof(objname), objname }; + + status = acpi_get_object_info(handle, &info); + if (ACPI_FAILURE(status)) { + dbg("%s: failed to get bridge information", __FUNCTION__); + return AE_OK; /* continue */ + } + + info.hardware_id[sizeof(info.hardware_id)-1] = '\0'; + + if (strcmp(info.hardware_id, ACPI_PCI_ROOT_HID) == 0) { + + acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); + dbg("%s: found PCI root bridge[%s]", __FUNCTION__, objname); + + add_bridge(handle); + } + return AE_OK; +} + + +/* interrupt handler */ +static void handle_hotplug_event (acpi_handle handle, u32 type, void *data) +{ + char objname[5]; + acpi_buffer buffer = { sizeof(objname), objname }; + + acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); + + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + /* hot insertion/surprise removal */ + /* TBD */ + dbg("%s: Bus check notify on %s", __FUNCTION__, objname); + break; + + case ACPI_NOTIFY_DEVICE_CHECK: + /* TBD */ + dbg("%s: Device check notify on %s", __FUNCTION__, objname); + break; + + case ACPI_NOTIFY_EJECT_REQUEST: + /* eject button pushed */ + /* TBD */ + dbg("%s: Device eject notify on %s", __FUNCTION__, objname); + break; + + default: + warn("notify_handler: unknown event type 0x%x", type); + break; + } +} + + +/* + * external interfaces + */ + +int pcihp_acpi_glue_init (void) +{ + acpi_status status; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, check_pci_bridge, + NULL, NULL); + + if (ACPI_FAILURE(status)) { + dbg("%s: acpi_walk_namespace() failed", __FUNCTION__); + } + + return 0; +} + +static void free_all_resources (struct pcihp_acpi_bridge *bridge) +{ + struct pci_resource *res, *next;; + + for (res = bridge->free_io; res; ) { + next = res->next; + kfree(res); + res = next; + } + + for (res = bridge->free_mem; res; ) { + next = res->next; + kfree(res); + res = next; + } + + for (res = bridge->free_prefetch; res; ) { + next = res->next; + kfree(res); + res = next; + } + + for (res = bridge->free_bus; res; ) { + next = res->next; + kfree(res); + res = next; + } +} + + +void pcihp_acpi_glue_exit (void) +{ + struct list_head *node; + struct pcihp_acpi_bridge *bridge; + struct pcihp_acpi_slot *slot, *next; + + list_for_each(node, &bridge_list) { + bridge = (struct pcihp_acpi_bridge *)node; + slot = bridge->slots; + while (slot) { + next = slot->next; + kfree(slot); + slot = next; + } + free_all_resources(bridge); + kfree(bridge); + } +} + + +int pcihp_acpi_get_num_slots (void) +{ + struct list_head *node; + struct pcihp_acpi_bridge *bridge; + int num_slots; + + num_slots = 0; + + list_for_each(node, &bridge_list) { + bridge = (struct pcihp_acpi_bridge *)node; + dbg("Bus:%d num_slots:%d", bridge->bus, bridge->nr_slots); + num_slots += bridge->nr_slots; + } + + dbg("num_slots = %d", num_slots); + return num_slots; +} + + +/* TBD: improve performance */ +struct pcihp_acpi_slot *get_slot_from_id (int id) +{ + struct list_head *node; + struct pcihp_acpi_bridge *bridge; + struct pcihp_acpi_slot *slot; + + list_for_each(node, &bridge_list) { + bridge = (struct pcihp_acpi_bridge *)node; + for (slot = bridge->slots; slot; slot = slot->next) + if (slot->id == id) + return slot; + } + + /* should never happen! */ + dbg("%s: no object for id %d",__FUNCTION__, id); + return 0; +} + + +/* power on slot */ +int pcihp_acpi_enable_slot (struct pcihp_acpi_slot *slot) +{ + acpi_status status; + + if (slot->flags & SLOT_HAS_PS0) { + dbg("%s: powering on bus%d/dev%d.", __FUNCTION__, + slot->bridge->bus, slot->device); + status = acpi_evaluate_object(slot->handle, "_PS0", NULL, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: powering on bus%d/dev%d failed", + __FUNCTION__, slot->bridge->bus, slot->device); + return -1; + } + } + + return 0; +} + + +/* power off slot */ +int pcihp_acpi_disable_slot (struct pcihp_acpi_slot *slot) +{ + acpi_status status; + + if (slot->flags & SLOT_HAS_PS3) { + dbg("%s: powering off bus%d/dev%d.", __FUNCTION__, + slot->bridge->bus, slot->device); + status = acpi_evaluate_object(slot->handle, "_PS3", NULL, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: _PS3 on bus%d/dev%d failed", + __FUNCTION__, slot->bridge->bus, slot->device); + return -1; + } + } + + if (slot->flags & SLOT_HAS_EJ0) { + dbg("%s: eject bus%d/dev%d.", __FUNCTION__, + slot->bridge->bus, slot->device); + status = acpi_evaluate_object(slot->handle, "_EJ0", NULL, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: _EJ0 bus%d/dev%d failed", + __FUNCTION__, slot->bridge->bus, slot->device); + return -1; + } + } + + /* TBD + * evaluate _STA to check if state is successfully changed + * and update status + */ + + return 0; +} + + +static unsigned int get_slot_status(struct pcihp_acpi_slot *slot) +{ + acpi_status status; + unsigned long sta; + + status = acpi_evaluate_integer(slot->handle, "_STA", NULL, &sta); + + if (ACPI_FAILURE(status)) { + err("%s: _STA evaluation failed", __FUNCTION__); + return 0; + } + + return (int)sta; +} + + +/* + * slot enabled: 1 + * slot disabled: 0 + */ +u8 pcihp_acpi_get_power_status (struct pcihp_acpi_slot *slot) +{ + unsigned int sta; + + /* TBD + * . guarantee check _STA on function# 0 + * . check configuration space before _STA? + */ + + sta = get_slot_status(slot); + + return (sta & ACPI_STA_ENABLED) ? 1 : 0; +} + + +/* XXX this function is not used */ +/* + * attention LED ON: 1 + * OFF: 0 + */ +u8 pcihp_acpi_get_attention_status (struct pcihp_acpi_slot *slot) +{ + /* TBD + * no direct attention led status information via ACPI + */ + + return 0; +} + + +/* + * latch closed: 1 + * latch open: 0 + */ +u8 pcihp_acpi_get_latch_status (struct pcihp_acpi_slot *slot) +{ + unsigned int sta; + + /* TBD + * no direct latch information via ACPI + */ + + sta = get_slot_status(slot); + + return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0; +} + + +/* + * adapter presence : 2 + * absence : 0 + */ +u8 pcihp_acpi_get_adapter_status (struct pcihp_acpi_slot *slot) +{ + unsigned int sta; + + /* TBD + * is this information correct? + */ + + sta = get_slot_status(slot); + + return (sta == 0) ? 0 : 2; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/i2c/Config.help linux-2.5/drivers/i2c/Config.help --- linux-2.5.5/drivers/i2c/Config.help Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/i2c/Config.help Fri Feb 15 15:55:24 2002 @@ -80,6 +80,26 @@ . The module will be called i2c-elektor.o. +CONFIG_ITE_I2C_ALGO + This supports the use the ITE8172 I2C interface found on some MIPS + systems. Say Y if you have one of these. You should also say Y for + the ITE I2C peripheral driver support below. + + This support is also available as a module. If you want to compile + it as a modules, say M here and read + . + The module will be called i2c-algo-ite.o. + +CONFIG_ITE_I2C_ADAP + This supports the ITE8172 I2C peripheral found on some MIPS + systems. Say Y if you have one of these. You should also say Y for + the ITE I2C driver algorithm support above. + + This support is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-adap-ite.o. + CONFIG_I2C_CHARDEV Say Y here to use i2c-* device files, usually found in the /dev directory on your system. They make it possible to have user-space diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/i2c/Config.in linux-2.5/drivers/i2c/Config.in --- linux-2.5.5/drivers/i2c/Config.in Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/i2c/Config.in Thu Dec 27 16:32:31 2001 @@ -39,6 +39,10 @@ fi fi + if [ "$CONFIG_ALL_PPC" = "y" ] ; then + dep_tristate 'Keywest I2C interface in Apple Core99 machines' CONFIG_I2C_KEYWEST $CONFIG_I2C + fi + # This is needed for automatic patch generation: sensors code starts here # This is needed for automatic patch generation: sensors code ends here diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/i2c/Makefile linux-2.5/drivers/i2c/Makefile --- linux-2.5.5/drivers/i2c/Makefile Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/i2c/Makefile Thu Dec 27 16:32:31 2001 @@ -18,6 +18,7 @@ obj-$(CONFIG_ITE_I2C_ALGO) += i2c-algo-ite.o obj-$(CONFIG_ITE_I2C_ADAP) += i2c-adap-ite.o obj-$(CONFIG_I2C_PROC) += i2c-proc.o +obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o # This is needed for automatic patch generation: sensors code starts here # This is needed for automatic patch generation: sensors code ends here diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/i2c/i2c-adap-ite.c linux-2.5/drivers/i2c/i2c-adap-ite.c --- linux-2.5.5/drivers/i2c/i2c-adap-ite.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/i2c/i2c-adap-ite.c Sun Mar 3 17:54:35 2002 @@ -241,7 +241,7 @@ }; /* Called when the module is loaded. This function starts the - * cascade of calls up through the heirarchy of i2c modules (i.e. up to the + * cascade of calls up through the hierarchy of i2c modules (i.e. up to the * algorithm layer and into to the core layer) */ static int __init iic_ite_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/i2c/i2c-dev.c linux-2.5/drivers/i2c/i2c-dev.c --- linux-2.5.5/drivers/i2c/i2c-dev.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/i2c/i2c-dev.c Wed Jan 2 01:31:40 2002 @@ -141,7 +141,7 @@ #ifdef DEBUG struct inode *inode = file->f_dentry->d_inode; printk("i2c-dev.o: i2c-%d lseek to %ld bytes relative to %d.\n", - MINOR(inode->i_rdev),(long) offset,origin); + minor(inode->i_rdev),(long) offset,origin); #endif /* DEBUG */ return -ESPIPE; } @@ -165,7 +165,7 @@ return -ENOMEM; #ifdef DEBUG - printk("i2c-dev.o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev), + printk("i2c-dev.o: i2c-%d reading %d bytes.\n",minor(inode->i_rdev), count); #endif @@ -197,7 +197,7 @@ } #ifdef DEBUG - printk("i2c-dev.o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev), + printk("i2c-dev.o: i2c-%d writing %d bytes.\n",minor(inode->i_rdev), count); #endif ret = i2c_master_send(client,tmp,count); @@ -218,7 +218,7 @@ #ifdef DEBUG printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", - MINOR(inode->i_rdev),cmd, arg); + minor(inode->i_rdev),cmd, arg); #endif /* DEBUG */ switch ( cmd ) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/i2c/i2c-keywest.c linux-2.5/drivers/i2c/i2c-keywest.c --- linux-2.5.5/drivers/i2c/i2c-keywest.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/i2c/i2c-keywest.c Mon Feb 4 22:15:16 2002 @@ -0,0 +1,680 @@ +/* + i2c Support for Apple Keywest I2C Bus Controller + + Copyright (c) 2001 Benjamin Herrenschmidt + + Original work by + + Copyright (c) 2000 Philip Edelbrock + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Changes: + + 2001/12/13 BenH New implementation + 2001/12/15 BenH Add support for "byte" and "quick" + transfers. Add i2c_xfer routine. + + My understanding of the various modes supported by keywest are: + + - Dumb mode : not implemented, probably direct tweaking of lines + - Standard mode : simple i2c transaction of type + S Addr R/W A Data A Data ... T + - Standard sub mode : combined 8 bit subaddr write with data read + S Addr R/W A SubAddr A Data A Data ... T + - Combined mode : Subaddress and Data sequences appended with no stop + S Addr R/W A SubAddr S Addr R/W A Data A Data ... T + + Currently, this driver uses only Standard mode for i2c xfer, and + smbus byte & quick transfers ; and uses StandardSub mode for + other smbus transfers instead of combined as we need that for the + sound driver to be happy +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "i2c-keywest.h" + +#undef POLLED_MODE + +#define DBG(x...) do {\ + if (debug > 0) \ + printk(KERN_DEBUG "KW:" x); \ + } while(0) + + +MODULE_AUTHOR("Benjamin Herrenschmidt "); +MODULE_DESCRIPTION("I2C driver for Apple's Keywest"); +MODULE_LICENSE("GPL"); +MODULE_PARM(probe, "i"); +MODULE_PARM(debug, "i"); +EXPORT_NO_SYMBOLS; + +int probe = 0; +int debug = 0; + +static struct keywest_iface *ifaces = NULL; + +#ifdef POLLED_MODE +/* This isn't fast, but will go once I implement interrupt with + * proper timeout + */ +static u8 +wait_interrupt(struct keywest_iface* iface) +{ + int i; + u8 isr; + + for (i = 0; i < POLL_TIMEOUT; i++) { + isr = read_reg(reg_isr) & KW_I2C_IRQ_MASK; + if (isr != 0) + return isr; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } + return isr; +} +#endif /* POLLED_MODE */ + + +static void +do_stop(struct keywest_iface* iface, int result) +{ + write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_STOP); + iface->state = state_stop; + iface->result = result; +} + +/* Main state machine for standard & standard sub mode */ +static void +handle_interrupt(struct keywest_iface *iface, u8 isr) +{ + int ack; + + DBG("handle_interrupt(), got: %x, status: %x, state: %d\n", + isr, read_reg(reg_status), iface->state); + if (isr == 0 && iface->state != state_stop) { + do_stop(iface, -1); + return; + } + if (isr & KW_I2C_IRQ_STOP && iface->state != state_stop) { + iface->result = -1; + iface->state = state_stop; + } + switch(iface->state) { + case state_addr: + if (!(isr & KW_I2C_IRQ_ADDR)) { + do_stop(iface, -1); + break; + } + ack = read_reg(reg_status); + DBG("ack on set address: %x\n", ack); + if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { + do_stop(iface, -1); + break; + } + /* Handle rw "quick" mode */ + if (iface->datalen == 0) + do_stop(iface, 0); + else if (iface->read_write == I2C_SMBUS_READ) { + iface->state = state_read; + if (iface->datalen > 1) + write_reg(reg_control, read_reg(reg_control) + | KW_I2C_CTL_AAK); + } else { + iface->state = state_write; + DBG("write byte: %x\n", *(iface->data)); + write_reg(reg_data, *(iface->data++)); + iface->datalen--; + } + + break; + case state_read: + if (!(isr & KW_I2C_IRQ_DATA)) { + do_stop(iface, -1); + break; + } + *(iface->data++) = read_reg(reg_data); + DBG("read byte: %x\n", *(iface->data-1)); + iface->datalen--; + if (iface->datalen == 0) + iface->state = state_stop; + else + write_reg(reg_control, 0); + break; + case state_write: + if (!(isr & KW_I2C_IRQ_DATA)) { + do_stop(iface, -1); + break; + } + /* Check ack status */ + ack = read_reg(reg_status); + DBG("ack on data write: %x\n", ack); + if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { + do_stop(iface, -1); + break; + } + if (iface->datalen) { + DBG("write byte: %x\n", *(iface->data)); + write_reg(reg_data, *(iface->data++)); + iface->datalen--; + } else + do_stop(iface, 0); + break; + + case state_stop: + if (!(isr & KW_I2C_IRQ_STOP) && (++iface->stopretry) < 10) + do_stop(iface, -1); + else { + iface->state = state_idle; + write_reg(reg_control, 0x00); + write_reg(reg_ier, 0x00); +#ifndef POLLED_MODE + complete(&iface->complete); +#endif /* POLLED_MODE */ + } + break; + } + + write_reg(reg_isr, isr); +} + +#ifndef POLLED_MODE + +/* Interrupt handler */ +static void +keywest_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct keywest_iface *iface = (struct keywest_iface *)dev_id; + + spin_lock(&iface->lock); + del_timer(&iface->timeout_timer); + handle_interrupt(iface, read_reg(reg_isr)); + if (iface->state != state_idle) { + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + } + spin_unlock(&iface->lock); +} + +static void +keywest_timeout(unsigned long data) +{ + struct keywest_iface *iface = (struct keywest_iface *)data; + + DBG("timeout !\n"); + spin_lock_irq(&iface->lock); + handle_interrupt(iface, read_reg(reg_isr)); + if (iface->state != state_idle) { + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + } + spin_unlock(&iface->lock); +} + +#endif /* POLLED_MODE */ + +/* + * SMBUS-type transfer entrypoint + */ +static s32 +keywest_smbus_xfer( struct i2c_adapter* adap, + u16 addr, + unsigned short flags, + char read_write, + u8 command, + int size, + union i2c_smbus_data* data) +{ + struct keywest_chan* chan = (struct keywest_chan*)adap->data; + struct keywest_iface* iface = chan->iface; + int len; + u8* buffer; + u16 cur_word; + int rc = 0; + + if (iface->state == state_dead) + return -1; + + /* Prepare datas & select mode */ + iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK; + switch (size) { + case I2C_SMBUS_QUICK: + len = 0; + buffer = NULL; + iface->cur_mode |= KW_I2C_MODE_STANDARD; + break; + case I2C_SMBUS_BYTE: + len = 1; + buffer = &data->byte; + iface->cur_mode |= KW_I2C_MODE_STANDARD; + break; + case I2C_SMBUS_BYTE_DATA: + len = 1; + buffer = &data->byte; + iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + break; + case I2C_SMBUS_WORD_DATA: + len = 2; + cur_word = cpu_to_le16(data->word); + buffer = (u8 *)&cur_word; + iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + break; + case I2C_SMBUS_BLOCK_DATA: + len = data->block[0]; + buffer = &data->block[1]; + iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + break; + default: + return -1; + } + + /* Original driver had this limitation */ + if (len > 32) + len = 32; + + down(&iface->sem); + + DBG("chan: %d, addr: 0x%x, transfer len: %d, read: %d\n", + chan->chan_no, addr, len, read_write == I2C_SMBUS_READ); + + iface->data = buffer; + iface->datalen = len; + iface->state = state_addr; + iface->result = 0; + iface->stopretry = 0; + iface->read_write = read_write; + + /* Setup channel & clear pending irqs */ + write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4)); + write_reg(reg_isr, read_reg(reg_isr)); + write_reg(reg_status, 0); + + /* Set up address and r/w bit */ + write_reg(reg_addr, + (addr << 1) | ((read_write == I2C_SMBUS_READ) ? 0x01 : 0x00)); + + /* Set up the sub address */ + if ((iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB + || (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED) + write_reg(reg_subaddr, command); + + /* Arm timeout */ + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + + /* Start sending address & enable interrupt*/ + write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR); + write_reg(reg_ier, KW_I2C_IRQ_MASK); + +#ifdef POLLED_MODE + DBG("using polled mode...\n"); + /* State machine, to turn into an interrupt handler */ + while(iface->state != state_idle) { + u8 isr = wait_interrupt(iface); + handle_interrupt(iface, isr); + } +#else /* POLLED_MODE */ + DBG("using interrupt mode...\n"); + wait_for_completion(&iface->complete); +#endif /* POLLED_MODE */ + + rc = iface->result; + DBG("transfer done, result: %d\n", rc); + + if (rc == 0 && size == I2C_SMBUS_WORD_DATA && read_write == I2C_SMBUS_READ) + data->word = le16_to_cpu(cur_word); + + /* Release sem */ + up(&iface->sem); + + return rc; +} + +/* + * Generic i2c master transfer entrypoint + */ +static int +keywest_xfer( struct i2c_adapter *adap, + struct i2c_msg msgs[], + int num) +{ + struct keywest_chan* chan = (struct keywest_chan*)adap->data; + struct keywest_iface* iface = chan->iface; + struct i2c_msg *pmsg; + int i, completed; + int rc = 0; + + down(&iface->sem); + + /* Set adapter to standard mode */ + iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK; + iface->cur_mode |= KW_I2C_MODE_STANDARD; + + completed = 0; + for (i = 0; rc >= 0 && i < num;) { + u8 addr; + + pmsg = &msgs[i++]; + addr = pmsg->addr; + if (pmsg->flags & I2C_M_TEN) { + printk(KERN_ERR "i2c-keywest: 10 bits addr not supported !\n"); + rc = -EINVAL; + break; + } + DBG("xfer: chan: %d, doing %s %d bytes to 0x%02x - %d of %d messages\n", + chan->chan_no, + pmsg->flags & I2C_M_RD ? "read" : "write", + pmsg->len, addr, i, num); + + /* Setup channel & clear pending irqs */ + write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4)); + write_reg(reg_isr, read_reg(reg_isr)); + write_reg(reg_status, 0); + + iface->data = pmsg->buf; + iface->datalen = pmsg->len; + iface->state = state_addr; + iface->result = 0; + iface->stopretry = 0; + if (pmsg->flags & I2C_M_RD) + iface->read_write = I2C_SMBUS_READ; + else + iface->read_write = I2C_SMBUS_WRITE; + + /* Set up address and r/w bit */ + if (pmsg->flags & I2C_M_REV_DIR_ADDR) + addr ^= 1; + write_reg(reg_addr, + (addr << 1) | + ((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00)); + + /* Arm timeout */ + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + + /* Start sending address & enable interrupt*/ + write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR); + write_reg(reg_ier, KW_I2C_IRQ_MASK); + +#ifdef POLLED_MODE + DBG("using polled mode...\n"); + /* State machine, to turn into an interrupt handler */ + while(iface->state != state_idle) { + u8 isr = wait_interrupt(iface); + handle_interrupt(iface, isr); + } +#else /* POLLED_MODE */88 + DBG("using interrupt mode...\n"); + wait_for_completion(&iface->complete); +#endif /* POLLED_MODE */ + + rc = iface->result; + if (rc == 0) + completed++; + DBG("transfer done, result: %d\n", rc); + } + + /* Release sem */ + up(&iface->sem); + + return completed; +} + +static u32 +keywest_func(struct i2c_adapter * adapter) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static void +keywest_inc(struct i2c_adapter *adapter) +{ + MOD_INC_USE_COUNT; +} + +static void +keywest_dec(struct i2c_adapter *adapter) +{ + MOD_DEC_USE_COUNT; +} + +/* For now, we only handle combined mode (smbus) */ +static struct i2c_algorithm keywest_algorithm = { + name: "Keywest i2c", + id: I2C_ALGO_SMBUS, + smbus_xfer: keywest_smbus_xfer, + master_xfer: keywest_xfer, + functionality: keywest_func, +}; + + +static int +create_iface(struct device_node* np) +{ + unsigned long steps, *psteps, *prate; + unsigned bsteps, tsize, i, nchan, addroffset; + struct keywest_iface* iface; + int rc; + + psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL); + steps = psteps ? (*psteps) : 0x10; + + /* Hrm... maybe we can be smarter here */ + for (bsteps = 0; (steps & 0x01) == 0; bsteps++) + steps >>= 1; + + if (!strcmp(np->parent->name, "uni-n")) { + nchan = 2; + addroffset = 3; + } else { + addroffset = 0; + nchan = 1; + } + + tsize = sizeof(struct keywest_iface) + + (sizeof(struct keywest_chan) + 4) * nchan; + iface = (struct keywest_iface *) kmalloc(tsize, GFP_KERNEL); + if (iface == NULL) { + printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n"); + return -ENOMEM; + } + memset(iface, 0, tsize); + init_MUTEX(&iface->sem); + spin_lock_init(&iface->lock); + init_completion(&iface->complete); + iface->bsteps = bsteps; + iface->chan_count = nchan; + iface->state = state_idle; + iface->irq = np->intrs[0].line; + iface->channels = (struct keywest_chan *) + (((unsigned long)(iface + 1) + 3UL) & ~3UL); + iface->base = (unsigned long)ioremap(np->addrs[0].address + addroffset, + np->addrs[0].size); + if (iface->base == 0) { + printk(KERN_ERR "i2c-keywest: can't map inteface !\n"); + kfree(iface); + return -ENOMEM; + } + + init_timer(&iface->timeout_timer); + iface->timeout_timer.function = keywest_timeout; + iface->timeout_timer.data = (unsigned long)iface; + + /* Select interface rate */ + iface->cur_mode = KW_I2C_MODE_100KHZ; + prate = (unsigned long *)get_property(np, "AAPL,i2c-rate", NULL); + if (prate) switch(*prate) { + case 100: + iface->cur_mode = KW_I2C_MODE_100KHZ; + break; + case 50: + iface->cur_mode = KW_I2C_MODE_50KHZ; + break; + case 25: + iface->cur_mode = KW_I2C_MODE_25KHZ; + break; + default: + printk(KERN_WARNING "i2c-keywest: unknown rate %ldKhz, using 100KHz\n", + *prate); + } + + /* Select standard sub mode */ + iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; + + /* Write mode */ + write_reg(reg_mode, iface->cur_mode); + + /* Switch interrupts off & clear them*/ + write_reg(reg_ier, 0x00); + write_reg(reg_isr, KW_I2C_IRQ_MASK); + +#ifndef POLLED_MODE + /* Request chip interrupt */ + rc = request_irq(iface->irq, keywest_irq, 0, "keywest i2c", iface); + if (rc) { + printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq); + iounmap((void *)iface->base); + kfree(iface); + return -ENODEV; + } +#endif /* POLLED_MODE */ + + for (i=0; ichannels[i]; + u8 addr; + + sprintf(chan->adapter.name, "%s %d", np->parent->name, i); + chan->iface = iface; + chan->chan_no = i; + chan->adapter.id = I2C_ALGO_SMBUS; + chan->adapter.algo = &keywest_algorithm; + chan->adapter.algo_data = NULL; + chan->adapter.inc_use = keywest_inc; + chan->adapter.dec_use = keywest_dec; + chan->adapter.client_register = NULL; + chan->adapter.client_unregister = NULL; + chan->adapter.data = chan; + + rc = i2c_add_adapter(&chan->adapter); + if (rc) { + printk("i2c-keywest.c: Adapter %s registration failed\n", + chan->adapter.name); + chan->adapter.data = NULL; + } + if (probe) { + printk("Probe: "); + for (addr = 0x00; addr <= 0x7f; addr++) { + if (i2c_smbus_xfer(&chan->adapter,addr, + 0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) + printk("%02x ", addr); + } + printk("\n"); + } + } + + printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n", + np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps); + + iface->next = ifaces; + ifaces = iface; + return 0; +} + +static void +dispose_iface(struct keywest_iface *iface) +{ + int i, rc; + + ifaces = iface->next; + + /* Make sure we stop all activity */ + down(&iface->sem); +#ifndef POLLED_MODE + spin_lock_irq(&iface->lock); + while (iface->state != state_idle) { + spin_unlock_irq(&iface->lock); + schedule(); + spin_lock_irq(&iface->lock); + } +#endif /* POLLED_MODE */ + iface->state = state_dead; +#ifndef POLLED_MODE + spin_unlock_irq(&iface->lock); + free_irq(iface->irq, iface); +#endif /* POLLED_MODE */ + up(&iface->sem); + + /* Release all channels */ + for (i=0; ichan_count; i++) { + struct keywest_chan* chan = &iface->channels[i]; + if (!chan->adapter.data) + continue; + rc = i2c_del_adapter(&chan->adapter); + chan->adapter.data = NULL; + /* We aren't that prepared to deal with this... */ + if (rc) + printk("i2c-keywest.c: i2c_del_adapter failed, that's bad !\n"); + } + iounmap((void *)iface->base); + kfree(iface); +} + +static int __init +i2c_keywest_init(void) +{ + struct device_node *np; + int rc = -ENODEV; + + np = find_compatible_devices("i2c", "keywest"); + while (np != 0) { + if (np->n_addrs >= 1 && np->n_intrs >= 1) + rc = create_iface(np); + np = np->next; + } + if (ifaces) + rc = 0; + return rc; +} + +static void __exit +i2c_keywest_cleanup(void) +{ + while(ifaces) + dispose_iface(ifaces); +} + +module_init(i2c_keywest_init); +module_exit(i2c_keywest_cleanup); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/i2c/i2c-keywest.h linux-2.5/drivers/i2c/i2c-keywest.h --- linux-2.5.5/drivers/i2c/i2c-keywest.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/i2c/i2c-keywest.h Thu Dec 27 16:32:31 2001 @@ -0,0 +1,111 @@ +#ifndef __I2C_KEYWEST_H__ +#define __I2C_KEYWEST_H__ + +/* The Tumbler audio equalizer can be really slow sometimes */ +#define POLL_TIMEOUT (2*HZ) + +/* Register indices */ +typedef enum { + reg_mode = 0, + reg_control, + reg_status, + reg_isr, + reg_ier, + reg_addr, + reg_subaddr, + reg_data +} reg_t; + + +/* Mode register */ +#define KW_I2C_MODE_100KHZ 0x00 +#define KW_I2C_MODE_50KHZ 0x01 +#define KW_I2C_MODE_25KHZ 0x02 +#define KW_I2C_MODE_DUMB 0x00 +#define KW_I2C_MODE_STANDARD 0x04 +#define KW_I2C_MODE_STANDARDSUB 0x08 +#define KW_I2C_MODE_COMBINED 0x0C +#define KW_I2C_MODE_MODE_MASK 0x0C +#define KW_I2C_MODE_CHAN_MASK 0xF0 + +/* Control register */ +#define KW_I2C_CTL_AAK 0x01 +#define KW_I2C_CTL_XADDR 0x02 +#define KW_I2C_CTL_STOP 0x04 +#define KW_I2C_CTL_START 0x08 + +/* Status register */ +#define KW_I2C_STAT_BUSY 0x01 +#define KW_I2C_STAT_LAST_AAK 0x02 +#define KW_I2C_STAT_LAST_RW 0x04 +#define KW_I2C_STAT_SDA 0x08 +#define KW_I2C_STAT_SCL 0x10 + +/* IER & ISR registers */ +#define KW_I2C_IRQ_DATA 0x01 +#define KW_I2C_IRQ_ADDR 0x02 +#define KW_I2C_IRQ_STOP 0x04 +#define KW_I2C_IRQ_START 0x08 +#define KW_I2C_IRQ_MASK 0x0F + +/* Physical interface */ +struct keywest_iface +{ + unsigned long base; + unsigned bsteps; + int irq; + struct semaphore sem; + spinlock_t lock; + struct keywest_chan* channels; + unsigned chan_count; + u8 cur_mode; + char read_write; + u8* data; + unsigned datalen; + int state; + int result; + int stopretry; + struct timer_list timeout_timer; + struct completion complete; + struct keywest_iface* next; +}; + +enum { + state_idle, + state_addr, + state_read, + state_write, + state_stop, + state_dead +}; + +/* Channel on an interface */ +struct keywest_chan +{ + struct i2c_adapter adapter; + struct keywest_iface* iface; + unsigned chan_no; +}; + +/* Register access */ + +static inline u8 __read_reg(struct keywest_iface *iface, reg_t reg) +{ + return in_8(((volatile u8 *)iface->base) + + (((unsigned)reg) << iface->bsteps)); +} + +static inline void __write_reg(struct keywest_iface *iface, reg_t reg, u8 val) +{ + out_8(((volatile u8 *)iface->base) + + (((unsigned)reg) << iface->bsteps), val); + (void)__read_reg(iface, reg); + udelay(10); +} + +#define write_reg(reg, val) __write_reg(iface, reg, val) +#define read_reg(reg) __read_reg(iface, reg) + + + +#endif /* __I2C_KEYWEST_H__ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/i2c/i2c-proc.c linux-2.5/drivers/i2c/i2c-proc.c --- linux-2.5.5/drivers/i2c/i2c-proc.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/i2c/i2c-proc.c Mon Jan 14 22:39:45 2002 @@ -119,6 +119,10 @@ sprintf(name_buffer, "%s-i2c-%d-%02x", prefix, id, addr); } *name = kmalloc(strlen(name_buffer) + 1, GFP_KERNEL); + if (!*name) { + printk (KERN_WARNING "i2c_create_name: not enough memory\n"); + return -ENOMEM; + } strcpy(*name, name_buffer); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/Config.help linux-2.5/drivers/ide/Config.help --- linux-2.5.5/drivers/ide/Config.help Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/ide/Config.help Tue Feb 26 20:09:24 2002 @@ -612,13 +612,13 @@ CONFIG_BLK_DEV_PDC4030 This driver provides support for the secondary IDE interface and - cache of Promise IDE chipsets, e.g. DC4030 and DC5030. This driver - is known to incur timeouts/retries during heavy I/O to drives - attached to the secondary interface. CD-ROM and TAPE devices are - not supported yet. This driver is enabled at runtime using the - "ide0=dc4030" kernel boot parameter. See the - and files - for more info. + cache of the original Promise IDE chipsets, e.g. DC4030 and DC5030. + It is nothing to do with the later range of Promise UDMA chipsets - + see the PDC_202XX support for these. CD-ROM and TAPE devices are not + supported (and probably never will be since I don't think the cards + support them). This driver is enabled at runtime using the "ide0=dc4030" + or "ide1=dc4030" kernel boot parameter. See the + file for more info. CONFIG_BLK_DEV_QD65XX This driver is enabled at runtime using the "ide0=qd65xx" kernel @@ -697,6 +697,11 @@ Say Y if you have such an Macintosh model and want to use IDE devices (hard disks, CD-ROM drives, etc.) that are connected to the builtin IDE interface. + +CONFIG_BLK_DEV_Q40IDE + Enable the on-board IDE controller in the Q40/Q60. This should + normally be on; disable it only if you are running a custom hard + drive subsystem through an expansion card. CONFIG_BLK_DEV_IDE_ICSIDE On Acorn systems, say Y here if you wish to use the ICS IDE diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/Config.in linux-2.5/drivers/ide/Config.in --- linux-2.5.5/drivers/ide/Config.in Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/ide/Config.in Sun Mar 3 17:54:35 2002 @@ -49,14 +49,14 @@ bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD dep_bool ' Force enable legacy 2.0.X HOSTS to use DMA' CONFIG_BLK_DEV_IDEDMA_FORCED $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI - dep_bool ' Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO + dep_bool ' Enable DMA only for disks' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL - dep_bool ' Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP - dep_bool ' Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP -# dep_bool ' Asynchronous DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP + dep_bool ' Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP + dep_bool ' Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP +# dep_bool ' Asynchronous DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI -# dep_bool ' Tag Command Queue DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDMA_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP +# dep_bool ' Tag Command Queue DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDMA_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP dep_bool ' AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX @@ -78,6 +78,10 @@ dep_mbool ' IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO fi + if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then + dep_mbool ' IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI + dep_mbool ' IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO + fi dep_bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL dep_mbool ' Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP @@ -105,6 +109,9 @@ if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then define_bool CONFIG_BLK_DEV_IDEPCI $CONFIG_BLK_DEV_IDEDMA_PMAC fi + fi + if [ "$CONFIG_SIBYTE_SWARM" = "y" ]; then + bool ' SWARM onboard IDE support' CONFIG_BLK_DEV_IDE_SWARM fi if [ "$CONFIG_ARCH_ACORN" = "y" ]; then dep_bool ' ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_ARCH_ACORN diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/Makefile linux-2.5/drivers/ide/Makefile --- linux-2.5.5/drivers/ide/Makefile Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/ide/Makefile Sun Mar 3 17:54:35 2002 @@ -49,6 +49,7 @@ ide-obj-$(CONFIG_BLK_DEV_IDEPCI) += ide-pci.o ide-obj-$(CONFIG_BLK_DEV_ISAPNP) += ide-pnp.o ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC) += ide-pmac.o +ide-obj-$(CONFIG_BLK_DEV_IDE_SWARM) += ide-swarm.o ide-obj-$(CONFIG_BLK_DEV_MAC_IDE) += macide.o ide-obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o ide-obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/aec62xx.c linux-2.5/drivers/ide/aec62xx.c --- linux-2.5.5/drivers/ide/aec62xx.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/ide/aec62xx.c Fri Mar 1 15:07:38 2002 @@ -48,7 +48,6 @@ static int aec62xx_get_info(char *, char **, off_t, int); extern int (*aec62xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count) @@ -203,22 +202,18 @@ static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table) { - int bus_speed = system_bus_clock(); - for ( ; chipset_table->xfer_speed ; chipset_table++) if (chipset_table->xfer_speed == speed) { - return ((byte) ((bus_speed <= 33) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34)); + return ((byte) ((system_bus_speed <= 33) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34)); } return 0x00; } static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table) { - int bus_speed = system_bus_clock(); - for ( ; chipset_table->xfer_speed ; chipset_table++) if (chipset_table->xfer_speed == speed) { - return ((byte) ((bus_speed <= 33) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34)); + return ((byte) ((system_bus_speed <= 33) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34)); } return 0x00; } @@ -314,8 +309,8 @@ unsigned long dma_base = hwif->dma_base; byte speed = -1; - if (drive->media != ide_disk) - return ((int) ide_dma_off_quietly); + if (drive->type != ATA_DISK) + return ide_dma_off_quietly; if (((id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008) || @@ -360,7 +355,7 @@ byte speed = -1; byte ultra66 = eighty_ninty_three(drive); - if (drive->media != ide_disk) + if (drive->type != ATA_DISK) return ((int) ide_dma_off_quietly); if ((id->dma_ultra & 0x0010) && (ultra) && (ultra66)) { @@ -522,11 +517,11 @@ #endif /* CONFIG_BLK_DEV_IDEDMA */ #endif /* CONFIG_AEC62XX_TUNING */ -unsigned int __init pci_init_aec62xx (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_aec62xx (struct pci_dev *dev) { if (dev->resource[PCI_ROM_RESOURCE].start) { pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); - printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); + printk("%s: ROM enabled at 0x%08lx\n", dev->name, dev->resource[PCI_ROM_RESOURCE].start); } #if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ali14xx.c linux-2.5/drivers/ide/ali14xx.c --- linux-2.5.5/drivers/ide/ali14xx.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/ide/ali14xx.c Fri Mar 1 15:07:38 2002 @@ -119,15 +119,14 @@ byte param1, param2, param3, param4; unsigned long flags; ide_pio_data_t d; - int bus_speed = system_bus_clock(); pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d); /* calculate timing, according to PIO mode */ time1 = d.cycle_time; time2 = ide_pio_timings[pio].active_time; - param3 = param1 = (time2 * bus_speed + 999) / 1000; - param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1; + param3 = param1 = (time2 * system_bus_speed + 999) / 1000; + param4 = param2 = (time1 * system_bus_speed + 999) / 1000 - param1; if (pio < 3) { param3 += 8; param4 += 8; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/alim15x3.c linux-2.5/drivers/ide/alim15x3.c --- linux-2.5.5/drivers/ide/alim15x3.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/ide/alim15x3.c Fri Mar 1 15:07:38 2002 @@ -247,7 +247,6 @@ int s_time, a_time, c_time; byte s_clc, a_clc, r_clc; unsigned long flags; - int bus_speed = system_bus_clock(); int port = hwif->index ? 0x5c : 0x58; int portFIFO = hwif->channel ? 0x55 : 0x54; byte cd_dma_fifo = 0; @@ -255,18 +254,18 @@ pio = ide_get_best_pio_mode(drive, pio, 5, &d); s_time = ide_pio_timings[pio].setup_time; a_time = ide_pio_timings[pio].active_time; - if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8) + if ((s_clc = (s_time * system_bus_speed + 999) / 1000) >= 8) s_clc = 0; - if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8) + if ((a_clc = (a_time * system_bus_speed + 999) / 1000) >= 8) a_clc = 0; c_time = ide_pio_timings[pio].cycle_time; #if 0 - if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16) + if ((r_clc = ((c_time - s_time - a_time) * system_bus_speed + 999) / 1000) >= 16) r_clc = 0; #endif - if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) { + if (!(r_clc = (c_time * system_bus_speed + 999) / 1000 - a_clc - s_clc)) { r_clc = 1; } else { if (r_clc >= 16) @@ -279,7 +278,7 @@ * PIO mode => ATA FIFO on, ATAPI FIFO off */ pci_read_config_byte(dev, portFIFO, &cd_dma_fifo); - if (drive->media==ide_disk) { + if (drive->type == ATA_DISK) { if (hwif->index) { pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50); } else { @@ -425,9 +424,9 @@ } else if ((m5229_revision < 0xC2) && #ifndef CONFIG_WDC_ALI15X3 ((chip_is_1543c_e && strstr(id->model, "WDC ")) || - (drive->media!=ide_disk))) { + (drive->type != ATA_DISK))) { #else /* CONFIG_WDC_ALI15X3 */ - (drive->media!=ide_disk)) { + (drive->type != ATA_DISK)) { #endif /* CONFIG_WDC_ALI15X3 */ return 0; } else { @@ -442,7 +441,7 @@ ide_dma_action_t dma_func = ide_dma_on; byte can_ultra_dma = ali15x3_can_ultra(drive); - if ((m5229_revision<=0x20) && (drive->media!=ide_disk)) + if ((m5229_revision<=0x20) && (drive->type != ATA_DISK)) return hwif->dmaproc(ide_dma_off_quietly, drive); if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) { @@ -495,7 +494,7 @@ case ide_dma_check: return ali15x3_config_drive_for_dma(drive); case ide_dma_write: - if ((m5229_revision < 0xC2) && (drive->media != ide_disk)) + if ((m5229_revision < 0xC2) && (drive->type != ATA_DISK)) return 1; /* try PIO instead of DMA */ break; default: @@ -505,7 +504,7 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ -unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_ali15x3(struct pci_dev *dev) { unsigned long fixdma_base = pci_resource_start(dev, 4); @@ -524,7 +523,7 @@ outb(inb(fixdma_base+2) & 0x60, fixdma_base+2); if (inb(fixdma_base+2) & 0x80) - printk("%s: simplex device: DMA will fail!!\n", name); + printk("%s: simplex device: DMA will fail!!\n", dev->name); } #if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/amd74xx.c linux-2.5/drivers/ide/amd74xx.c --- linux-2.5.5/drivers/ide/amd74xx.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/ide/amd74xx.c Fri Mar 1 15:07:38 2002 @@ -34,7 +34,6 @@ static int amd74xx_get_info(char *, char **, off_t, int); extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; static int amd74xx_get_info (char *buffer, char **addr, off_t offset, int count) @@ -406,13 +405,13 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ -unsigned int __init pci_init_amd74xx (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_amd74xx(struct pci_dev *dev) { unsigned long fixdma_base = pci_resource_start(dev, 4); #ifdef CONFIG_BLK_DEV_IDEDMA if (!amd74xx_swdma_check(dev)) - printk("%s: disabling single-word DMA support (revision < C4)\n", name); + printk("%s: disabling single-word DMA support (revision < C4)\n", dev->name); #endif /* CONFIG_BLK_DEV_IDEDMA */ if (!fixdma_base) { @@ -426,7 +425,7 @@ outb(inb(fixdma_base+2) & 0x60, fixdma_base+2); if (inb(fixdma_base+2) & 0x80) - printk("%s: simplex device: DMA will fail!!\n", name); + printk("%s: simplex device: DMA will fail!!\n", dev->name); } #if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) if (!amd74xx_proc) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ataraid.c linux-2.5/drivers/ide/ataraid.c --- linux-2.5.5/drivers/ide/ataraid.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/ide/ataraid.c Thu Feb 21 01:26:10 2002 @@ -70,7 +70,7 @@ static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int minor; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl)) return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg); @@ -80,7 +80,7 @@ static int ataraid_open(struct inode * inode, struct file * filp) { int minor; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open)) return (ataraid_ops[minor]->open)(inode,filp); @@ -91,7 +91,7 @@ static int ataraid_release(struct inode * inode, struct file * filp) { int minor; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release)) return (ataraid_ops[minor]->release)(inode,filp); @@ -102,7 +102,7 @@ { int minor; int retval; - minor = MINOR(bh->b_rdev)>>SHIFT; + minor = minor(bh->b_rdev)>>SHIFT; if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) { @@ -229,7 +229,7 @@ void ataraid_register_disk(int device,long size) { - register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16, + register_disk(&ataraid_gendisk, mk_kdev(ATAMAJOR,16*device),16, &ataraid_fops,size); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/cmd640.c linux-2.5/drivers/ide/cmd640.c --- linux-2.5.5/drivers/ide/cmd640.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/ide/cmd640.c Fri Mar 1 15:07:38 2002 @@ -23,7 +23,7 @@ * * A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com, * bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz, - * chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de, + * chrisc@dbass.demon.co.uk, dalecki@evision-ventures.com, * derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de, * flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net, * j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net, @@ -596,14 +596,13 @@ { int setup_time, active_time, recovery_time, clock_time; byte setup_count, active_count, recovery_count, recovery_count2, cycle_count; - int bus_speed = system_bus_clock(); if (pio_mode > 5) pio_mode = 5; setup_time = ide_pio_timings[pio_mode].setup_time; active_time = ide_pio_timings[pio_mode].active_time; recovery_time = cycle_time - (setup_time + active_time); - clock_time = 1000 / bus_speed; + clock_time = 1000 / system_bus_speed; cycle_count = (cycle_time + clock_time - 1) / clock_time; setup_count = (setup_time + clock_time - 1) / clock_time; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/cmd64x.c linux-2.5/drivers/ide/cmd64x.c --- linux-2.5.5/drivers/ide/cmd64x.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/ide/cmd64x.c Fri Mar 1 15:07:38 2002 @@ -88,7 +88,6 @@ static int cmd64x_get_info(char *, char **, off_t, int); static int cmd680_get_info(char *, char **, off_t, int); extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count) @@ -283,8 +282,6 @@ int setup_time, active_time, recovery_time, clock_time, pio_mode, cycle_time; byte recovery_count2, cycle_count; int setup_count, active_count, recovery_count; - int bus_speed = system_bus_clock(); - /*byte b;*/ ide_pio_data_t d; switch (mode_wanted) { @@ -309,7 +306,7 @@ setup_time = ide_pio_timings[pio_mode].setup_time; active_time = ide_pio_timings[pio_mode].active_time; recovery_time = cycle_time - (setup_time + active_time); - clock_time = 1000 / bus_speed; + clock_time = 1000 / system_bus_speed; cycle_count = (cycle_time + clock_time - 1) / clock_time; setup_count = (setup_time + clock_time - 1) / clock_time; @@ -450,7 +447,8 @@ u8 regU = 0; u8 regD = 0; - if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) return 1; + if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0)) + return 1; (void) pci_read_config_byte(dev, pciD, ®D); (void) pci_read_config_byte(dev, pciU, ®U); @@ -643,8 +641,8 @@ break; } - if (drive->media != ide_disk) { - cmdprintk("CMD64X: drive->media != ide_disk at double check, inital check failed!!\n"); + if (drive->type != ATA_DISK) { + cmdprintk("CMD64X: drive is not a disk at double check, inital check failed!!\n"); return ((int) ide_dma_off); } @@ -790,7 +788,7 @@ } if ((id != NULL) && ((id->capability & 1) != 0) && - hwif->autodma && (drive->media == ide_disk)) { + hwif->autodma && (drive->type == ATA_DISK)) { /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) { dma_func = ide_dma_off; @@ -956,7 +954,7 @@ return 0; } -void cmd680_reset (ide_drive_t *drive) +static void cmd680_reset (ide_drive_t *drive) { #if 0 ide_hwif_t *hwif = HWIF(drive); @@ -968,9 +966,9 @@ #endif } -unsigned int cmd680_pci_init (struct pci_dev *dev, const char *name) +static unsigned int cmd680_pci_init(struct pci_dev *dev) { - u8 tmpbyte = 0; + u8 tmpbyte = 0; pci_write_config_byte(dev, 0x80, 0x00); pci_write_config_byte(dev, 0x84, 0x00); pci_read_config_byte(dev, 0x8A, &tmpbyte); @@ -994,7 +992,7 @@ return 0; } -unsigned int cmd64x_pci_init (struct pci_dev *dev, const char *name) +static unsigned int cmd64x_pci_init(struct pci_dev *dev) { unsigned char mrdmode; unsigned int class_rev; @@ -1005,7 +1003,7 @@ #ifdef __i386__ if (dev->resource[PCI_ROM_RESOURCE].start) { pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); - printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); + printk("%s: ROM enabled at 0x%08lx\n", dev->name, dev->resource[PCI_ROM_RESOURCE].start); } #endif @@ -1013,7 +1011,7 @@ case PCI_DEVICE_ID_CMD_643: break; case PCI_DEVICE_ID_CMD_646: - printk("%s: chipset revision 0x%02X, ", name, class_rev); + printk("%s: chipset revision 0x%02X, ", dev->name, class_rev); switch(class_rev) { case 0x07: case 0x05: @@ -1083,11 +1081,11 @@ return 0; } -unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_cmd64x(struct pci_dev *dev) { if (dev->device == PCI_DEVICE_ID_CMD_680) - return cmd680_pci_init (dev, name); - return cmd64x_pci_init (dev, name); + return cmd680_pci_init (dev); + return cmd64x_pci_init (dev); } unsigned int cmd680_ata66 (ide_hwif_t *hwif) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/cs5530.c linux-2.5/drivers/ide/cs5530.c --- linux-2.5.5/drivers/ide/cs5530.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/ide/cs5530.c Fri Mar 1 15:07:38 2002 @@ -37,7 +37,6 @@ static int cs5530_get_info(char *, char **, off_t, int); extern int (*cs5530_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count) @@ -251,7 +250,7 @@ /* * Initialize the cs5530 bridge for reliable IDE DMA operation. */ -unsigned int __init pci_init_cs5530 (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_cs5530(struct pci_dev *dev) { struct pci_dev *master_0 = NULL, *cs5530_0 = NULL; unsigned short pcicmd = 0; @@ -278,11 +277,11 @@ } } if (!master_0) { - printk("%s: unable to locate PCI MASTER function\n", name); + printk("%s: unable to locate PCI MASTER function\n", dev->name); return 0; } if (!cs5530_0) { - printk("%s: unable to locate CS5530 LEGACY function\n", name); + printk("%s: unable to locate CS5530 LEGACY function\n", dev->name); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/cy82c693.c linux-2.5/drivers/ide/cy82c693.c --- linux-2.5.5/drivers/ide/cy82c693.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/ide/cy82c693.c Fri Mar 1 15:07:38 2002 @@ -141,7 +141,6 @@ static void compute_clocks (byte pio, pio_clocks_t *p_pclk) { int clk1, clk2; - int bus_speed = system_bus_clock(); /* get speed of PCI bus */ /* we don't check against CY82C693's min and max speed, * so you can play with the idebus=xx parameter @@ -151,17 +150,17 @@ pio = CY82C693_MAX_PIO; /* let's calc the address setup time clocks */ - p_pclk->address_time = (byte)calc_clk(ide_pio_timings[pio].setup_time, bus_speed); + p_pclk->address_time = (byte)calc_clk(ide_pio_timings[pio].setup_time, system_bus_speed); /* let's calc the active and recovery time clocks */ - clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed); + clk1 = calc_clk(ide_pio_timings[pio].active_time, system_bus_speed); /* calc recovery timing */ clk2 = ide_pio_timings[pio].cycle_time - ide_pio_timings[pio].active_time - ide_pio_timings[pio].setup_time; - clk2 = calc_clk(clk2, bus_speed); + clk2 = calc_clk(clk2, system_bus_speed); clk1 = (clk1<<4)|clk2; /* combine active and recovery clocks */ @@ -384,7 +383,7 @@ * the device prior to INIT. */ -unsigned int __init pci_init_cy82c693(struct pci_dev *dev, const char *name) +unsigned int __init pci_init_cy82c693(struct pci_dev *dev) { #ifdef CY82C693_SETDMA_CLOCK byte data; @@ -400,7 +399,7 @@ data = IN_BYTE(CY82_DATA_PORT); #if CY82C693_DEBUG_INFO - printk (KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", name, data); + printk (KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", dev->name, data); #endif /* CY82C693_DEBUG_INFO */ /* @@ -421,7 +420,7 @@ OUT_BYTE(data, CY82_DATA_PORT); #if CY82C693_DEBUG_INFO - printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", name, data); + printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", dev->name, data); #endif /* CY82C693_DEBUG_INFO */ #endif /* CY82C693_SETDMA_CLOCK */ @@ -434,7 +433,7 @@ void __init ide_init_cy82c693(ide_hwif_t *hwif) { hwif->chipset = ide_cy82c693; - hwif->tuneproc = &cy82c693_tune_drive; + hwif->tuneproc = cy82c693_tune_drive; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; hwif->autodma = 0; @@ -442,7 +441,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->highmem = 1; - hwif->dmaproc = &cy82c693_dmaproc; + hwif->dmaproc = cy82c693_dmaproc; if (!noautodma) hwif->autodma = 1; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/hd.c linux-2.5/drivers/ide/hd.c --- linux-2.5.5/drivers/ide/hd.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/ide/hd.c Thu Feb 21 01:26:10 2002 @@ -66,6 +66,7 @@ static int revalidate_hddisk(kdev_t, int); +#define TIMEOUT_VALUE (6*HZ) #define HD_DELAY 0 #define MAX_ERRORS 16 /* Max read/write errors/sector */ @@ -558,7 +559,7 @@ reset_hd(); return; } - dev = MINOR(CURRENT->rq_dev); + dev = minor(CURRENT->rq_dev); block = CURRENT->sector; nsect = CURRENT->nr_sectors; if (dev >= (NR_HD<<6) || (dev & 0x3f) || @@ -568,7 +569,7 @@ kdevname(CURRENT->rq_dev)); else printk("hd%c: bad access: block=%d, count=%d\n", - (MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect); + (minor(CURRENT->rq_dev)>>6)+'a', block, nsect); end_request(0); goto repeat; } @@ -626,7 +627,7 @@ struct hd_geometry *loc = (struct hd_geometry *) arg; int dev; - if ((!inode) || !(inode->i_rdev)) + if ((!inode) || kdev_none(inode->i_rdev)) return -EINVAL; dev = DEVICE_NR(inode->i_rdev); if (dev >= NR_HD) @@ -822,7 +823,7 @@ hd_gendisk.nr_real = NR_HD; for(drive=0; drive < NR_HD; drive++) - register_disk(&hd_gendisk, MKDEV(MAJOR_NR,drive<<6), 1<<6, + register_disk(&hd_gendisk, mk_kdev(MAJOR_NR,drive<<6), 1<<6, &hd_fops, hd_info[drive].head * hd_info[drive].sect * hd_info[drive].cyl); } @@ -833,7 +834,7 @@ printk("hd: unable to get major %d for hard disk\n",MAJOR_NR); return -1; } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &hd_lock); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_hd_request, &hd_lock); blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 255); add_gendisk(&hd_gendisk); init_timer(&device_timer); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/hpt34x.c linux-2.5/drivers/ide/hpt34x.c --- linux-2.5.5/drivers/ide/hpt34x.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/ide/hpt34x.c Fri Mar 1 15:07:38 2002 @@ -56,7 +56,6 @@ static int hpt34x_get_info(char *, char **, off_t, int); extern int (*hpt34x_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count) @@ -210,7 +209,7 @@ struct hd_driveid *id = drive->id; byte speed = 0x00; - if (drive->media != ide_disk) + if (drive->type != ATA_DISK) return ((int) ide_dma_off_quietly); hpt34x_clear_chipset(drive); @@ -333,7 +332,7 @@ outb(reading, dma_base); /* specify r/w */ outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ drive->waiting_for_dma = 1; - if (drive->media != ide_disk) + if (drive->type != ATA_DISK) return 0; 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); @@ -357,7 +356,7 @@ */ #define HPT34X_PCI_INIT_REG 0x80 -unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_hpt34x(struct pci_dev *dev) { int i = 0; unsigned long hpt34xIoBase = pci_resource_start(dev, 4); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/hpt366.c linux-2.5/drivers/ide/hpt366.c --- linux-2.5.5/drivers/ide/hpt366.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/ide/hpt366.c Fri Mar 1 15:07:38 2002 @@ -355,7 +355,6 @@ #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) static int hpt366_get_info(char *, char **, off_t, int); extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count) { @@ -579,7 +578,7 @@ static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed) { - if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) + if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0)) return -1; if (!drive->init_speed) @@ -664,7 +663,7 @@ byte ultra66 = eighty_ninty_three(drive); int rval; - if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) + if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0)) return ((int) ide_dma_off_quietly); if ((id->dma_ultra & 0x0020) && @@ -1097,7 +1096,7 @@ udelay(100); } -unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_hpt366(struct pci_dev *dev) { byte test = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/hptraid.c linux-2.5/drivers/ide/hptraid.c --- linux-2.5.5/drivers/ide/hptraid.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/ide/hptraid.c Mon Jan 7 20:47:14 2002 @@ -75,16 +75,16 @@ unsigned char val; unsigned long sectors; - if (!inode || !inode->i_rdev) + if (!inode || kdev_none(inode->i_rdev)) return -EINVAL; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; switch (cmd) { case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; - sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects; - if (MINOR(inode->i_rdev)&15) + sectors = ataraid_gendisk.part[minor(inode->i_rdev)].nr_sects; + if (minor(inode->i_rdev)&15) return put_user(sectors, (unsigned long *) arg); return put_user(raid[minor].sectors , (unsigned long *) arg); break; @@ -102,7 +102,7 @@ if (put_user(val, (byte *) &loc->sectors)) return -EFAULT; bios_cyl = raid[minor].sectors/63/255; if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect, + if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -118,7 +118,7 @@ if (put_user(val, (byte *) &loc->sectors)) return -EFAULT; bios_cyl = raid[minor].sectors/63/255; if (put_user(bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect, + if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -167,7 +167,7 @@ /* Partitions need adding of the start sector of the partition to the requested sector */ - rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; + rsect += ataraid_gendisk.part[minor(bh->b_rdev)].start_sect; /* Woops we need to split the request to avoid crossing a stride barrier */ if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) { @@ -248,7 +248,7 @@ kdev_t dev; ide_drive_t *ideinfo; - dev = MKDEV(major,minor); + dev = mk_kdev(major,minor); ideinfo = get_info_ptr (dev); if (ideinfo==NULL) return 0; @@ -268,7 +268,7 @@ static void __init probedisk(int major, int minor,int device) { int i; - struct block_device *bdev = bdget(MKDEV(major,minor)); + struct block_device *bdev = bdget(mk_kdev(major,minor)); struct gendisk *gd; if (!bdev) @@ -301,14 +301,14 @@ /* now blank the /proc/partitions table for the wrong partition table, so that scripts don't accidentally mount it and crash the kernel */ /* XXX: the 0 is an utter hack --hch */ - gd=get_gendisk(MKDEV(major, 0)); + gd=get_gendisk(mk_kdev(major, 0)); if (gd!=NULL) { int j; for (j=1+(minor<minor_shift);j<((minor+1)<minor_shift);j++) gd->part[j].nr_sects=0; } - raid[device].disk[i].device = MKDEV(major,minor); + raid[device].disk[i].device = mk_kdev(major,minor); raid[device].disk[i].sectors = maxsectors(major,minor); raid[device].stride = (1<media != ide_disk || !drive->present) + if (drive->type != ATA_DISK || !drive->present) select |= HT_PREFETCH_MODE; (void) inb(HT_CONFIG_PORT); (void) inb(HT_CONFIG_PORT); @@ -207,7 +207,6 @@ int active_time, recovery_time; int active_cycles, recovery_cycles; ide_pio_data_t d; - int bus_speed = system_bus_clock(); if (pio) { pio = ide_get_best_pio_mode(drive, pio, 5, &d); @@ -224,8 +223,8 @@ /* * Cycle times should be Vesa bus cycles */ - active_cycles = (active_time * bus_speed + 999) / 1000; - recovery_cycles = (recovery_time * bus_speed + 999) / 1000; + active_cycles = (active_time * system_bus_speed + 999) / 1000; + recovery_cycles = (recovery_time * system_bus_speed + 999) / 1000; /* * Upper and lower limits */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-cd.c linux-2.5/drivers/ide/ide-cd.c --- linux-2.5.5/drivers/ide/ide-cd.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/ide/ide-cd.c Fri Mar 1 15:07:38 2002 @@ -1010,6 +1010,7 @@ } /* + * Try to satisfy some of the current read request from======= * Try to satisfy some of the current read request from our cached data. * Returns nonzero if the request has been completed, zero otherwise. */ @@ -1398,11 +1399,8 @@ ide_init_drive_cmd (&req); req.flags = REQ_PC; req.special = (char *) pc; - if (ide_do_drive_cmd (drive, &req, ide_wait)) { - printk("%s: do_drive_cmd returned stat=%02x,err=%02x\n", - drive->name, req.buffer[0], req.buffer[1]); - /* FIXME: we should probably abort/retry or something */ - } + ide_do_drive_cmd (drive, &req, ide_wait); + /* FIXME: we should probably abort/retry or something */ if (pc->stat != 0) { /* The request failed. Retry if it was due to a unit attention status @@ -2906,15 +2904,10 @@ return 0; } -int ide_cdrom_init(void); -int ide_cdrom_reinit (ide_drive_t *drive); +static int ide_cdrom_reinit (ide_drive_t *drive); -static ide_driver_t ide_cdrom_driver = { - name: "ide-cdrom", - media: ide_cdrom, - busy: 0, - supports_dma: 1, - supports_dsc_overlap: 1, +static struct ata_operations ide_cdrom_driver = { + owner: THIS_MODULE, cleanup: ide_cdrom_cleanup, standby: NULL, flushcache: NULL, @@ -2929,7 +2922,6 @@ capacity: ide_cdrom_capacity, special: NULL, proc: NULL, - driver_init: ide_cdrom_init, driver_reinit: ide_cdrom_reinit, }; @@ -2939,7 +2931,7 @@ MODULE_PARM(ignore, "s"); MODULE_DESCRIPTION("ATAPI CD-ROM Driver"); -int ide_cdrom_reinit (ide_drive_t *drive) +static int ide_cdrom_reinit (ide_drive_t *drive) { struct cdrom_info *info; int failed = 0; @@ -2957,17 +2949,20 @@ } memset (info, 0, sizeof (struct cdrom_info)); drive->driver_data = info; - DRIVER(drive)->busy++; + + /* ATA-PATTERN */ + ata_ops(drive)->busy++; if (ide_cdrom_setup (drive)) { - DRIVER(drive)->busy--; + ata_ops(drive)->busy--; if (ide_cdrom_cleanup (drive)) printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name); return 1; } - DRIVER(drive)->busy--; + ata_ops(drive)->busy--; + failed--; - ide_register_module(&ide_cdrom_driver); + revalidate_drives(); MOD_DEC_USE_COUNT; return 0; } @@ -2977,12 +2972,11 @@ ide_drive_t *drive; int failed = 0; - while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, &ide_cdrom_driver, failed)) != NULL) + while ((drive = ide_scan_devices(ATA_ROM, "ide-cdrom", &ide_cdrom_driver, failed)) != NULL) if (ide_cdrom_cleanup (drive)) { printk ("%s: cleanup_module() called while still busy\n", drive->name); failed++; } - ide_unregister_module (&ide_cdrom_driver); } int ide_cdrom_init(void) @@ -2992,7 +2986,7 @@ int failed = 0; MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) { + while ((drive = ide_scan_devices (ATA_ROM, "ide-cdrom", NULL, failed++)) != NULL) { /* skip drives that we were told to ignore */ if (ignore != NULL) { if (strstr(ignore, drive->name)) { @@ -3016,17 +3010,20 @@ } memset (info, 0, sizeof (struct cdrom_info)); drive->driver_data = info; - DRIVER(drive)->busy++; + + /* ATA-PATTERN */ + ata_ops(drive)->busy++; if (ide_cdrom_setup (drive)) { - DRIVER(drive)->busy--; + ata_ops(drive)->busy--; if (ide_cdrom_cleanup (drive)) printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name); continue; } - DRIVER(drive)->busy--; + ata_ops(drive)->busy--; + failed--; } - ide_register_module(&ide_cdrom_driver); + revalidate_drives(); MOD_DEC_USE_COUNT; return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-disk.c linux-2.5/drivers/ide/ide-disk.c --- linux-2.5.5/drivers/ide/ide-disk.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/ide/ide-disk.c Fri Mar 1 15:07:38 2002 @@ -378,11 +378,6 @@ return drive->removable; /* if removable, always assume it was changed */ } -static void idedisk_revalidate (ide_drive_t *drive) -{ - ide_revalidate_drive(drive); -} - /* * Queries for true maximum capacity of the drive. * Returns maximum LBA address (> 0) of the drive, 0 if failed. @@ -915,13 +910,22 @@ ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL); } -static void idedisk_setup (ide_drive_t *drive) +/* This is just a hook for the overall driver tree. + * + * FIXME: This is soon goig to replace the custom linked list games played up + * to great extend between the different components of the IDE drivers. + */ + +static struct device_driver idedisk_devdrv = {}; + +static void idedisk_setup(ide_drive_t *drive) { int i; - + struct hd_driveid *id = drive->id; unsigned long capacity; - + int drvid = -1; + idedisk_add_settings(drive); if (id == NULL) @@ -933,7 +937,7 @@ */ if (drive->removable && !drive_is_flashcard(drive)) { /* - * Removable disks (eg. SYQUEST); ignore 'WD' drives + * Removable disks (eg. SYQUEST); ignore 'WD' drives. */ if (id->model[0] != 'W' || id->model[1] != 'D') { drive->doorlocking = 1; @@ -942,13 +946,26 @@ for (i = 0; i < MAX_DRIVES; ++i) { ide_hwif_t *hwif = HWIF(drive); - if (drive != &hwif->drives[i]) continue; + if (drive != &hwif->drives[i]) + continue; + drvid = i; hwif->gd->de_arr[i] = drive->de; if (drive->removable) hwif->gd->flags[i] |= GENHD_FL_REMOVABLE; break; } + /* Register us within the device tree. + */ + + if (drvid != -1) { + sprintf(drive->device.bus_id, "%d", drvid); + sprintf(drive->device.name, "ide-disk"); + drive->device.driver = &idedisk_devdrv; + drive->device.parent = &HWIF(drive)->device; + device_register(&drive->device); + } + /* Extract geometry if we did not already have one for the drive */ if (!drive->cyl || !drive->head || !drive->sect) { drive->cyl = drive->bios_cyl = id->cyls; @@ -1023,6 +1040,12 @@ static int idedisk_cleanup (ide_drive_t *drive) { + + /* FIXME: we will have to think twice whatever this is the proper place + * to do it. + */ + + put_device(&drive->device); if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache) if (do_idedisk_flushcache(drive)) printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n", @@ -1030,18 +1053,13 @@ return ide_unregister_subdriver(drive); } -int idedisk_init (void); -int idedisk_reinit(ide_drive_t *drive); +static int idedisk_reinit(ide_drive_t *drive); /* * IDE subdriver functions, registered with ide.c */ -static ide_driver_t idedisk_driver = { - name: "ide-disk", - media: ide_disk, - busy: 0, - supports_dma: 1, - supports_dsc_overlap: 0, +static struct ata_operations idedisk_driver = { + owner: THIS_MODULE, cleanup: idedisk_cleanup, standby: do_idedisk_standby, flushcache: do_idedisk_flushcache, @@ -1051,18 +1069,17 @@ open: idedisk_open, release: idedisk_release, media_change: idedisk_media_change, - revalidate: idedisk_revalidate, + revalidate: ide_revalidate_drive, pre_reset: idedisk_pre_reset, capacity: idedisk_capacity, special: idedisk_special, proc: idedisk_proc, - driver_init: idedisk_init, driver_reinit: idedisk_reinit, }; MODULE_DESCRIPTION("ATA DISK Driver"); -int idedisk_reinit (ide_drive_t *drive) +static int idedisk_reinit(ide_drive_t *drive) { int failed = 0; @@ -1072,18 +1089,19 @@ printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); return 1; } - DRIVER(drive)->busy++; + + ata_ops(drive)->busy++; idedisk_setup(drive); if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); - (void) idedisk_cleanup(drive); - DRIVER(drive)->busy--; + idedisk_cleanup(drive); + ata_ops(drive)->busy--; return 1; } - DRIVER(drive)->busy--; + ata_ops(drive)->busy--; failed--; - ide_register_module(&idedisk_driver); + revalidate_drives(); MOD_DEC_USE_COUNT; return 0; } @@ -1093,7 +1111,7 @@ ide_drive_t *drive; int failed = 0; - while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) { + while ((drive = ide_scan_devices(ATA_DISK, "ide-disk", &idedisk_driver, failed)) != NULL) { if (idedisk_cleanup (drive)) { printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name); failed++; @@ -1105,7 +1123,6 @@ ide_remove_proc_entries(drive->proc, idedisk_proc); #endif } - ide_unregister_module(&idedisk_driver); } int idedisk_init (void) @@ -1114,23 +1131,23 @@ int failed = 0; MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) { + while ((drive = ide_scan_devices(ATA_DISK, "ide-disk", NULL, failed++)) != NULL) { if (ide_register_subdriver (drive, &idedisk_driver)) { printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); continue; } - DRIVER(drive)->busy++; + ata_ops(drive)->busy++; idedisk_setup(drive); if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); - (void) idedisk_cleanup(drive); - DRIVER(drive)->busy--; + idedisk_cleanup(drive); + ata_ops(drive)->busy--; continue; } - DRIVER(drive)->busy--; + ata_ops(drive)->busy--; failed--; } - ide_register_module(&idedisk_driver); + revalidate_drives(); MOD_DEC_USE_COUNT; return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-dma.c linux-2.5/drivers/ide/ide-dma.c --- linux-2.5.5/drivers/ide/ide-dma.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/ide/ide-dma.c Fri Mar 1 15:07:38 2002 @@ -470,7 +470,7 @@ ide_hwif_t *hwif = HWIF(drive); #ifdef CONFIG_IDEDMA_ONLYDISK - if (drive->media != ide_disk) + if (drive->type != ATA_DISK) config_allows_dma = 0; #endif @@ -555,7 +555,7 @@ { u64 addr = BLK_BOUNCE_HIGH; - if (on && drive->media == ide_disk && HWIF(drive)->highmem) { + if (on && drive->type == ATA_DISK && HWIF(drive)->highmem) { if (!PCI_DMA_BUS_IS_PHYS) addr = BLK_BOUNCE_ANY; else @@ -613,7 +613,7 @@ outb(reading, dma_base); /* specify r/w */ outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ drive->waiting_for_dma = 1; - if (drive->media != ide_disk) + if (drive->type != ATA_DISK) return 0; #ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL); /* issue cmd to drive */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-features.c linux-2.5/drivers/ide/ide-features.c --- linux-2.5.5/drivers/ide/ide-features.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/ide/ide-features.c Fri Mar 1 15:07:38 2002 @@ -70,22 +70,6 @@ } /* - * - */ -char *ide_media_verbose (ide_drive_t *drive) -{ - switch (drive->media) { - case ide_scsi: return("scsi "); - case ide_disk: return("disk "); - case ide_optical: return("optical"); - case ide_cdrom: return("cdrom "); - case ide_tape: return("tape "); - case ide_floppy: return("floppy "); - default: return("???????"); - } -} - -/* * A Verbose noise maker for debugging on the attempted dmaing calls. */ char *ide_dmafunc_verbose (ide_dma_action_t dmafunc) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-floppy.c linux-2.5/drivers/ide/ide-floppy.c --- linux-2.5.5/drivers/ide/ide-floppy.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/ide/ide-floppy.c Fri Mar 1 15:07:38 2002 @@ -1,8 +1,8 @@ /* - * linux/drivers/ide/ide-floppy.c Version 0.97.sv Jan 14 2001 + * linux/drivers/ide/ide-floppy.c Version 0.99 Feb 24 2002 * * Copyright (C) 1996 - 1999 Gadi Oxman - * Copyright (C) 2000 - 2001 Paul Bristow + * Copyright (C) 2000 - 2002 Paul Bristow */ /* @@ -13,7 +13,7 @@ * * This driver supports the following IDE floppy drives: * - * LS-120 SuperDisk + * LS-120/240 SuperDisk * Iomega Zip 100/250 * Iomega PC Card Clik!/PocketZip * @@ -76,9 +76,11 @@ * bit was being deasserted by my IOMEGA ATAPI ZIP 100 * drive before the drive was actually ready. * Ver 0.98a Oct 29 01 Expose delay value so we can play. + * Ver 0.99 Feb 24 02 Remove duplicate code, modify clik! detection code + * to support new PocketZip drives */ -#define IDEFLOPPY_VERSION "0.98a" +#define IDEFLOPPY_VERSION "0.99" #include #include @@ -1827,14 +1829,6 @@ } /* - * Revalidate the new media. Should set blk_size[] - */ -static void idefloppy_revalidate (ide_drive_t *drive) -{ - ide_revalidate_drive(drive); -} - -/* * Return the current floppy capacity to ide.c. */ static unsigned long idefloppy_capacity (ide_drive_t *drive) @@ -2004,7 +1998,7 @@ * above fix. It makes nasty clicking noises without * it, so please don't remove this. */ - if (strcmp(drive->id->model, "IOMEGA Clik! 40 CZ ATAPI") == 0) { + if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) { blk_queue_max_sectors(&drive->queue, 64); set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags); } @@ -2046,18 +2040,13 @@ #endif /* CONFIG_PROC_FS */ -int idefloppy_init(void); -int idefloppy_reinit(ide_drive_t *drive); +static int idefloppy_reinit(ide_drive_t *drive); /* * IDE subdriver functions, registered with ide.c */ -static ide_driver_t idefloppy_driver = { - name: "ide-floppy", - media: ide_floppy, - busy: 0, - supports_dma: 1, - supports_dsc_overlap: 0, +static struct ata_operations idefloppy_driver = { + owner: THIS_MODULE, cleanup: idefloppy_cleanup, standby: NULL, flushcache: NULL, @@ -2067,22 +2056,21 @@ open: idefloppy_open, release: idefloppy_release, media_change: idefloppy_media_change, - revalidate: idefloppy_revalidate, + revalidate: ide_revalidate_drive, pre_reset: NULL, capacity: idefloppy_capacity, special: NULL, proc: idefloppy_proc, - driver_init: idefloppy_init, driver_reinit: idefloppy_reinit, }; -int idefloppy_reinit (ide_drive_t *drive) +static int idefloppy_reinit (ide_drive_t *drive) { idefloppy_floppy_t *floppy; int failed = 0; MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) { + while ((drive = ide_scan_devices(ATA_FLOPPY, "ide-floppy", NULL, failed++)) != NULL) { if (!idefloppy_identify_device (drive, drive->id)) { printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name); continue; @@ -2100,12 +2088,15 @@ kfree (floppy); continue; } - DRIVER(drive)->busy++; + + /* ATA-PATTERN */ + ata_ops(drive)->busy++; idefloppy_setup (drive, floppy); - DRIVER(drive)->busy--; + ata_ops(drive)->busy--; + failed--; } - ide_register_module(&idefloppy_driver); + revalidate_drives(); MOD_DEC_USE_COUNT; return 0; } @@ -2117,7 +2108,7 @@ ide_drive_t *drive; int failed = 0; - while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL) { + while ((drive = ide_scan_devices(ATA_FLOPPY, "ide-floppy", &idefloppy_driver, failed)) != NULL) { if (idefloppy_cleanup (drive)) { printk ("%s: cleanup_module() called while still busy\n", drive->name); failed++; @@ -2130,7 +2121,6 @@ ide_remove_proc_entries(drive->proc, idefloppy_proc); #endif } - ide_unregister_module(&idefloppy_driver); } /* @@ -2144,7 +2134,7 @@ printk("ide-floppy driver " IDEFLOPPY_VERSION "\n"); MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) { + while ((drive = ide_scan_devices (ATA_FLOPPY, "ide-floppy", NULL, failed++)) != NULL) { if (!idefloppy_identify_device (drive, drive->id)) { printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name); continue; @@ -2162,12 +2152,14 @@ kfree (floppy); continue; } - DRIVER(drive)->busy++; + /* ATA-PATTERN */ + ata_ops(drive)->busy++; idefloppy_setup (drive, floppy); - DRIVER(drive)->busy--; + ata_ops(drive)->busy--; + failed--; } - ide_register_module(&idefloppy_driver); + revalidate_drives(); MOD_DEC_USE_COUNT; return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-geometry.c linux-2.5/drivers/ide/ide-geometry.c --- linux-2.5.5/drivers/ide/ide-geometry.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/ide/ide-geometry.c Fri Mar 1 15:07:38 2002 @@ -1,94 +1,16 @@ /* * linux/drivers/ide/ide-geometry.c + * + * Sun Feb 24 23:13:03 CET 2002: Patch by Andries Brouwer to remove the + * confused CMOS probe applied. This is solving more problems then it my + * (unexpectedly) introduce. */ + #include #include #include #include -#ifdef CONFIG_BLK_DEV_IDE - -/* - * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc - * controller that is BIOS compatible with ST-506, and thus showing up in our - * BIOS table, but not register compatible, and therefore not present in CMOS. - * - * Furthermore, we will assume that our ST-506 drives are the primary - * drives in the system -- the ones reflected as drive 1 or 2. The first - * drive is stored in the high nibble of CMOS byte 0x12, the second in the low - * nibble. This will be either a 4 bit drive type or 0xf indicating use byte - * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value - * means we have an AT controller hard disk for that drive. - * - * Of course, there is no guarantee that either drive is actually on the - * "primary" IDE interface, but we don't bother trying to sort that out here. - * If a drive is not actually on the primary interface, then these parameters - * will be ignored. This results in the user having to supply the logical - * drive geometry as a boot parameter for each drive not on the primary i/f. - */ -/* - * The only "perfect" way to handle this would be to modify the setup.[cS] code - * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info - * for us during initialization. I have the necessary docs -- any takers? -ml - */ -/* - * I did this, but it doesnt work - there is no reasonable way to find the - * correspondence between the BIOS numbering of the disks and the Linux - * numbering. -aeb - * - * The code below is bad. One of the problems is that drives 1 and 2 - * may be SCSI disks (even when IDE disks are present), so that - * the geometry we read here from BIOS is attributed to the wrong disks. - * Consequently, also the former "drive->present = 1" below was a mistake. - * - * Eventually the entire routine below should be removed. - * - * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS - * chip. - */ - -void probe_cmos_for_drives (ide_hwif_t *hwif) -{ -#ifdef __i386__ - extern struct drive_info_struct drive_info; - byte cmos_disks, *BIOS = (byte *) &drive_info; - int unit; - unsigned long flags; - -#ifdef CONFIG_BLK_DEV_PDC4030 - if (hwif->chipset == ide_pdc4030 && hwif->channel != 0) - return; -#endif /* CONFIG_BLK_DEV_PDC4030 */ - spin_lock_irqsave(&rtc_lock, flags); - cmos_disks = CMOS_READ(0x12); - spin_unlock_irqrestore(&rtc_lock, flags); - /* Extract drive geometry from CMOS+BIOS if not already setup */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - - if ((cmos_disks & (0xf0 >> (unit*4))) - && !drive->present && !drive->nobios) { - unsigned short cyl = *(unsigned short *)BIOS; - unsigned char head = *(BIOS+2); - unsigned char sect = *(BIOS+14); - if (cyl > 0 && head > 0 && sect > 0 && sect < 64) { - drive->cyl = drive->bios_cyl = cyl; - drive->head = drive->bios_head = head; - drive->sect = drive->bios_sect = sect; - drive->ctl = *(BIOS+8); - } else { - printk("hd%c: C/H/S=%d/%d/%d from BIOS ignored\n", - unit+'a', cyl, head, sect); - } - } - - BIOS += 16; - } -#endif -} -#endif /* CONFIG_BLK_DEV_IDE */ - - #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) extern ide_drive_t * get_info_ptr(kdev_t); @@ -105,14 +27,14 @@ unsigned long total; /* - * The specs say: take geometry as obtained from Identify, - * compute total capacity C*H*S from that, and truncate to - * 1024*255*63. Now take S=63, H the first in the sequence - * 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total. - * [Please tell aeb@cwi.nl in case this computes a - * geometry different from what OnTrack uses.] + * The specs say: take geometry as obtained from Identify, compute + * total capacity C*H*S from that, and truncate to 1024*255*63. Now + * take S=63, H the first in the sequence 4, 8, 16, 32, 64, 128, 255 + * such that 63*H*1024 >= total. [Please tell aeb@cwi.nl in case this + * computes a geometry different from what OnTrack uses.] */ - total = DRIVER(drive)->capacity(drive); + + total = ata_ops(drive)->capacity(drive); *s = 63; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-m8xx.c linux-2.5/drivers/ide/ide-m8xx.c --- linux-2.5.5/drivers/ide/ide-m8xx.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/ide/ide-m8xx.c Mon Feb 18 03:39:04 2002 @@ -1,8 +1,14 @@ /* - * - * * linux/drivers/ide/ide-m8xx.c * + * Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de + * Modified for direct IDE interface + * by Thomas Lange, thomas@corelatus.com + * Modified for direct IDE interface on 8xx without using the PCMCIA + * controller + * by Steven.Scholz@imc-berlin.de + * Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups + * by Mathew Locke */ #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-pci.c linux-2.5/drivers/ide/ide-pci.c --- linux-2.5.5/drivers/ide/ide-pci.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/ide/ide-pci.c Sun Mar 3 17:54:35 2002 @@ -9,7 +9,7 @@ /* * This module provides support for automatic detection and - * configuration of all PCI IDE interfaces present in a system. + * configuration of all PCI IDE interfaces present in a system. */ /* @@ -32,243 +32,100 @@ #include #include -#define DEVID_PIIXa ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0}) -#define DEVID_PIIXb ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1}) -#define DEVID_MPIIX ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX}) -#define DEVID_PIIX3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1}) -#define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB}) -#define DEVID_ICH0 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1}) -#define DEVID_PIIX4E2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1}) -#define DEVID_ICH ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1}) -#define DEVID_PIIX4U2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1}) -#define DEVID_PIIX4NX ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX}) -#define DEVID_ICH2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9}) -#define DEVID_ICH2M ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8}) -#define DEVID_ICH3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10}) -#define DEVID_VIA_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561}) -#define DEVID_MR_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1}) -#define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1}) -#define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246}) -#define DEVID_PDC20262 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262}) -#define DEVID_PDC20265 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265}) -#define DEVID_PDC20267 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267}) -#define DEVID_PDC20268 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268}) -#define DEVID_PDC20268R ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R}) -#define DEVID_PDC20269 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269}) -#define DEVID_PDC20275 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275}) -#define DEVID_RZ1000 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000}) -#define DEVID_RZ1001 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001}) -#define DEVID_SAMURAI ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE}) -#define DEVID_CMD640 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640}) -#define DEVID_CMD643 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643}) -#define DEVID_CMD646 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646}) -#define DEVID_CMD648 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648}) -#define DEVID_CMD649 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649}) -#define DEVID_CMD680 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_680}) -#define DEVID_SIS5513 ((ide_pci_devid_t){PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513}) -#define DEVID_OPTI621 ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621}) -#define DEVID_OPTI621V ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558}) -#define DEVID_OPTI621X ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825}) -#define DEVID_TRM290 ((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290}) -#define DEVID_NS87410 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410}) -#define DEVID_NS87415 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415}) -#define DEVID_HT6565 ((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565}) -#define DEVID_AEC6210 ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF}) -#define DEVID_AEC6260 ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860}) -#define DEVID_AEC6260R ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R}) -#define DEVID_W82C105 ((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105}) -#define DEVID_UM8673F ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F}) -#define DEVID_UM8886A ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A}) -#define DEVID_UM8886BF ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF}) -#define DEVID_HPT34X ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343}) -#define DEVID_HPT366 ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366}) -#define DEVID_ALI15X3 ((ide_pci_devid_t){PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229}) -#define DEVID_CY82C693 ((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693}) -#define DEVID_HINT ((ide_pci_devid_t){0x3388, 0x8013}) -#define DEVID_CS5530 ((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE}) -#define DEVID_AMD7401 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401}) -#define DEVID_AMD7409 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409}) -#define DEVID_AMD7411 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411}) -#define DEVID_AMD7441 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7441}) -#define DEVID_PDCADMA ((ide_pci_devid_t){PCI_VENDOR_ID_PDC, PCI_DEVICE_ID_PDC_1841}) -#define DEVID_SLC90E66 ((ide_pci_devid_t){PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1}) -#define DEVID_OSB4 ((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE}) -#define DEVID_CSB5 ((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE}) -#define DEVID_ITE8172G ((ide_pci_devid_t){PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G}) +/* Missing PCI device IDs: */ +#define PCI_VENDOR_ID_HINT 0x3388 +#define PCI_DEVICE_ID_HINT 0x8013 #define IDE_IGNORE ((void *)-1) #define IDE_NO_DRIVER ((void *)-2) #ifdef CONFIG_BLK_DEV_AEC62XX -extern unsigned int pci_init_aec62xx(struct pci_dev *, const char *); +extern unsigned int pci_init_aec62xx(struct pci_dev *); extern unsigned int ata66_aec62xx(ide_hwif_t *); extern void ide_init_aec62xx(ide_hwif_t *); extern void ide_dmacapable_aec62xx(ide_hwif_t *, unsigned long); -#define PCI_AEC62XX &pci_init_aec62xx -#define ATA66_AEC62XX &ata66_aec62xx -#define INIT_AEC62XX &ide_init_aec62xx -#define DMA_AEC62XX &ide_dmacapable_aec62xx -#else -#define PCI_AEC62XX NULL -#define ATA66_AEC62XX NULL -#define INIT_AEC62XX IDE_NO_DRIVER -#define DMA_AEC62XX NULL #endif #ifdef CONFIG_BLK_DEV_ALI15X3 -extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *); +extern unsigned int pci_init_ali15x3(struct pci_dev *); extern unsigned int ata66_ali15x3(ide_hwif_t *); extern void ide_init_ali15x3(ide_hwif_t *); extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long); -#define PCI_ALI15X3 &pci_init_ali15x3 -#define ATA66_ALI15X3 &ata66_ali15x3 -#define INIT_ALI15X3 &ide_init_ali15x3 -#define DMA_ALI15X3 &ide_dmacapable_ali15x3 -#else -#define PCI_ALI15X3 NULL -#define ATA66_ALI15X3 NULL -#define INIT_ALI15X3 IDE_NO_DRIVER -#define DMA_ALI15X3 NULL #endif #ifdef CONFIG_BLK_DEV_AMD74XX -extern unsigned int pci_init_amd74xx(struct pci_dev *, const char *); +extern unsigned int pci_init_amd74xx(struct pci_dev *); extern unsigned int ata66_amd74xx(ide_hwif_t *); extern void ide_init_amd74xx(ide_hwif_t *); extern void ide_dmacapable_amd74xx(ide_hwif_t *, unsigned long); -#define PCI_AMD74XX &pci_init_amd74xx -#define ATA66_AMD74XX &ata66_amd74xx -#define INIT_AMD74XX &ide_init_amd74xx -#define DMA_AMD74XX &ide_dmacapable_amd74xx -#else -#define PCI_AMD74XX NULL -#define ATA66_AMD74XX NULL -#define INIT_AMD74XX IDE_NO_DRIVER -#define DMA_AMD74XX NULL #endif #ifdef CONFIG_BLK_DEV_CMD64X -extern unsigned int pci_init_cmd64x(struct pci_dev *, const char *); +extern unsigned int pci_init_cmd64x(struct pci_dev *); extern unsigned int ata66_cmd64x(ide_hwif_t *); extern void ide_init_cmd64x(ide_hwif_t *); extern void ide_dmacapable_cmd64x(ide_hwif_t *, unsigned long); -#define PCI_CMD64X &pci_init_cmd64x -#define ATA66_CMD64X &ata66_cmd64x -#define INIT_CMD64X &ide_init_cmd64x -#else -#define PCI_CMD64X NULL -#define ATA66_CMD64X NULL -#ifdef __sparc_v9__ -#define INIT_CMD64X IDE_IGNORE -#else -#define INIT_CMD64X IDE_NO_DRIVER -#endif #endif #ifdef CONFIG_BLK_DEV_CY82C693 -extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *); +extern unsigned int pci_init_cy82c693(struct pci_dev *); extern void ide_init_cy82c693(ide_hwif_t *); -#define PCI_CY82C693 &pci_init_cy82c693 -#define INIT_CY82C693 &ide_init_cy82c693 -#else -#define PCI_CY82C693 NULL -#define INIT_CY82C693 IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_CS5530 -extern unsigned int pci_init_cs5530(struct pci_dev *, const char *); +extern unsigned int pci_init_cs5530(struct pci_dev *); extern void ide_init_cs5530(ide_hwif_t *); -#define PCI_CS5530 &pci_init_cs5530 -#define INIT_CS5530 &ide_init_cs5530 -#else -#define PCI_CS5530 NULL -#define INIT_CS5530 IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_HPT34X -extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *); +extern unsigned int pci_init_hpt34x(struct pci_dev *); extern void ide_init_hpt34x(ide_hwif_t *); -#define PCI_HPT34X &pci_init_hpt34x -#define INIT_HPT34X &ide_init_hpt34x -#else -#define PCI_HPT34X NULL -#define INIT_HPT34X IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_HPT366 extern byte hpt363_shared_irq; extern byte hpt363_shared_pin; -extern unsigned int pci_init_hpt366(struct pci_dev *, const char *); + +extern unsigned int pci_init_hpt366(struct pci_dev *); extern unsigned int ata66_hpt366(ide_hwif_t *); extern void ide_init_hpt366(ide_hwif_t *); extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long); -#define PCI_HPT366 &pci_init_hpt366 -#define ATA66_HPT366 &ata66_hpt366 -#define INIT_HPT366 &ide_init_hpt366 -#define DMA_HPT366 &ide_dmacapable_hpt366 #else +/* FIXME: those have to be killed */ static byte hpt363_shared_irq; static byte hpt363_shared_pin; -#define PCI_HPT366 NULL -#define ATA66_HPT366 NULL -#define INIT_HPT366 IDE_NO_DRIVER -#define DMA_HPT366 NULL #endif #ifdef CONFIG_BLK_DEV_NS87415 extern void ide_init_ns87415(ide_hwif_t *); -#define INIT_NS87415 &ide_init_ns87415 -#else -#define INIT_NS87415 IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_OPTI621 extern void ide_init_opti621(ide_hwif_t *); -#define INIT_OPTI621 &ide_init_opti621 -#else -#define INIT_OPTI621 IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_PDC_ADMA -extern unsigned int pci_init_pdcadma(struct pci_dev *, const char *); +extern unsigned int pci_init_pdcadma(struct pci_dev *); extern unsigned int ata66_pdcadma(ide_hwif_t *); extern void ide_init_pdcadma(ide_hwif_t *); extern void ide_dmacapable_pdcadma(ide_hwif_t *, unsigned long); -#define PCI_PDCADMA &pci_init_pdcadma -#define ATA66_PDCADMA &ata66_pdcadma -#define INIT_PDCADMA &ide_init_pdcadma -#define DMA_PDCADMA &ide_dmacapable_pdcadma -#else -#define PCI_PDCADMA IDE_IGNORE -#define ATA66_PDCADMA IDE_IGNORE -#define INIT_PDCADMA IDE_IGNORE -#define DMA_PDCADMA IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_PDC202XX -extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *); +extern unsigned int pci_init_pdc202xx(struct pci_dev *); extern unsigned int ata66_pdc202xx(ide_hwif_t *); extern void ide_init_pdc202xx(ide_hwif_t *); -#define PCI_PDC202XX &pci_init_pdc202xx -#define ATA66_PDC202XX &ata66_pdc202xx -#define INIT_PDC202XX &ide_init_pdc202xx -#else -#define PCI_PDC202XX IDE_IGNORE -#define ATA66_PDC202XX IDE_IGNORE -#define INIT_PDC202XX IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_PIIX -extern unsigned int pci_init_piix(struct pci_dev *, const char *); +extern unsigned int pci_init_piix(struct pci_dev *); extern unsigned int ata66_piix(ide_hwif_t *); extern void ide_init_piix(ide_hwif_t *); -#define PCI_PIIX &pci_init_piix -#define ATA66_PIIX &ata66_piix -#define INIT_PIIX &ide_init_piix -#else -#define PCI_PIIX NULL -#define ATA66_PIIX NULL -#define INIT_PIIX IDE_NO_DRIVER +#endif + +#ifdef CONFIG_BLK_DEV_IT8172 +extern unsigned int pci_init_it8172(struct pci_dev *); +extern void ide_init_it8172(ide_hwif_t *); #endif #ifdef CONFIG_BLK_DEV_IT8172 @@ -280,91 +137,46 @@ #else #define PCI_IT8172 NULL #define ATA66_IT8172 NULL -#define INIT_IT8172 IDE_NO_DRIVER +#define INIT_IT8172 NULL #endif #ifdef CONFIG_BLK_DEV_RZ1000 extern void ide_init_rz1000(ide_hwif_t *); -#define INIT_RZ1000 &ide_init_rz1000 -#else -#define INIT_RZ1000 IDE_IGNORE #endif -#define INIT_SAMURAI NULL - #ifdef CONFIG_BLK_DEV_SVWKS -extern unsigned int pci_init_svwks(struct pci_dev *, const char *); +extern unsigned int pci_init_svwks(struct pci_dev *); extern unsigned int ata66_svwks(ide_hwif_t *); extern void ide_init_svwks(ide_hwif_t *); -#define PCI_SVWKS &pci_init_svwks -#define ATA66_SVWKS &ata66_svwks -#define INIT_SVWKS &ide_init_svwks -#else -#define PCI_SVWKS NULL -#define ATA66_SVWKS NULL -#define INIT_SVWKS IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_SIS5513 -extern unsigned int pci_init_sis5513(struct pci_dev *, const char *); +extern unsigned int pci_init_sis5513(struct pci_dev *); extern unsigned int ata66_sis5513(ide_hwif_t *); extern void ide_init_sis5513(ide_hwif_t *); -#define PCI_SIS5513 &pci_init_sis5513 -#define ATA66_SIS5513 &ata66_sis5513 -#define INIT_SIS5513 &ide_init_sis5513 -#else -#define PCI_SIS5513 NULL -#define ATA66_SIS5513 NULL -#define INIT_SIS5513 IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_SLC90E66 -extern unsigned int pci_init_slc90e66(struct pci_dev *, const char *); +extern unsigned int pci_init_slc90e66(struct pci_dev *); extern unsigned int ata66_slc90e66(ide_hwif_t *); extern void ide_init_slc90e66(ide_hwif_t *); -#define PCI_SLC90E66 &pci_init_slc90e66 -#define ATA66_SLC90E66 &ata66_slc90e66 -#define INIT_SLC90E66 &ide_init_slc90e66 -#else -#define PCI_SLC90E66 NULL -#define ATA66_SLC90E66 NULL -#define INIT_SLC90E66 IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_SL82C105 -extern unsigned int pci_init_sl82c105(struct pci_dev *, const char *); +extern unsigned int pci_init_sl82c105(struct pci_dev *); extern void dma_init_sl82c105(ide_hwif_t *, unsigned long); extern void ide_init_sl82c105(ide_hwif_t *); -#define PCI_W82C105 &pci_init_sl82c105 -#define DMA_W82C105 &dma_init_sl82c105 -#define INIT_W82C105 &ide_init_sl82c105 -#else -#define PCI_W82C105 NULL -#define DMA_W82C105 NULL -#define INIT_W82C105 IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_TRM290 extern void ide_init_trm290(ide_hwif_t *); -#define INIT_TRM290 &ide_init_trm290 -#else -#define INIT_TRM290 IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_VIA82CXXX -extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *); +extern unsigned int pci_init_via82cxxx(struct pci_dev *); extern unsigned int ata66_via82cxxx(ide_hwif_t *); extern void ide_init_via82cxxx(ide_hwif_t *); extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long); -#define PCI_VIA82CXXX &pci_init_via82cxxx -#define ATA66_VIA82CXXX &ata66_via82cxxx -#define INIT_VIA82CXXX &ide_init_via82cxxx -#define DMA_VIA82CXXX &ide_dmacapable_via82cxxx -#else -#define PCI_VIA82CXXX NULL -#define ATA66_VIA82CXXX NULL -#define INIT_VIA82CXXX IDE_NO_DRIVER -#define DMA_VIA82CXXX NULL #endif typedef struct ide_pci_enablebit_s { @@ -373,117 +185,158 @@ byte val; /* value of masked reg when "enabled" */ } ide_pci_enablebit_t; +/* Flags used to untangle quirk handling. + */ +#define ATA_F_DMA 0x01 +#define ATA_F_NODMA 0x02 /* no DMA mode supported at all */ +#define ATA_F_NOADMA 0x04 /* DMA has to be enabled explicitely */ +#define ATA_F_FIXIRQ 0x08 /* fixed irq wiring */ +#define ATA_F_SER 0x10 /* serialize on first and second channel interrupts */ +#define ATA_F_IRQ 0x20 /* trust IRQ information from config */ +#define ATA_F_PHACK 0x40 /* apply PROMISE hacks */ +#define ATA_F_HPTHACK 0x80 /* apply HPT366 hacks */ + typedef struct ide_pci_device_s { - ide_pci_devid_t devid; - char *name; - unsigned int (*init_chipset)(struct pci_dev *dev, const char *name); + unsigned short vendor; + unsigned short device; + unsigned int (*init_chipset)(struct pci_dev *dev); unsigned int (*ata66_check)(ide_hwif_t *hwif); - void (*init_hwif)(ide_hwif_t *hwif); + void (*init_hwif)(ide_hwif_t *hwif); void (*dma_init)(ide_hwif_t *hwif, unsigned long dmabase); ide_pci_enablebit_t enablebits[2]; - byte bootable; + unsigned int bootable; unsigned int extra; + unsigned int flags; } ide_pci_device_t; -static ide_pci_device_t ide_pci_chipsets[] __initdata = { - {DEVID_PIIXa, "PIIX", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIXb, "PIIX", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_MPIIX, "MPIIX", NULL, NULL, INIT_PIIX, NULL, {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX3, "PIIX3", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX4, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_ICH0, "ICH0", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX4E2, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_ICH, "ICH", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX4U2, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX4NX, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_ICH2, "ICH2", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_ICH2M, "ICH2-M", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_ICH3, "ICH3", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_MR_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, - {DEVID_VP_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, -#ifdef CONFIG_PDC202XX_FORCE - {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 16 }, - {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 }, - {DEVID_PDC20265,"PDC20265", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 48 }, - {DEVID_PDC20267,"PDC20267", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 }, -#else /* !CONFIG_PDC202XX_FORCE */ - {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, - {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, - {DEVID_PDC20265,"PDC20265", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, - {DEVID_PDC20267,"PDC20267", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, +static ide_pci_device_t pci_chipsets[] __initdata = { +#ifdef CONFIG_BLK_DEV_PIIX + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, NULL, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, NULL, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, NULL, NULL, ide_init_piix, NULL, {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}}, ON_BOARD, 0, ATA_F_NODMA }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, pci_init_piix, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, pci_init_piix, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, pci_init_piix, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1, pci_init_piix, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1, pci_init_piix, ata66_piix, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1, pci_init_piix, ata66_piix, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_init_piix, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, ATA_F_NOADMA }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, pci_init_piix, ata66_piix, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, pci_init_piix, ata66_piix, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, pci_init_piix, ata66_piix, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, +#endif +#ifdef CONFIG_BLK_DEV_VIA82CXXX + {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1, pci_init_via82cxxx, ata66_via82cxxx, ide_init_via82cxxx, ide_dmacapable_via82cxxx, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0, ATA_F_NOADMA }, + {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, pci_init_via82cxxx, ata66_via82cxxx, ide_init_via82cxxx, ide_dmacapable_via82cxxx, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0, ATA_F_NOADMA }, #endif - {DEVID_PDC20268,"PDC20268", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, +#ifdef CONFIG_BLK_DEV_PDC202XX +# ifdef CONFIG_PDC202XX_FORCE + {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, pci_init_pdc202xx, NULL, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 16, ATA_F_IRQ | ATA_F_DMA }, + {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48, ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA}, + {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 48, ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA}, + {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48, ATA_F_IRQ | ATA_F_DMA }, +# else + {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, pci_init_pdc202xx, NULL, ide_init_pdc202xx, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16, ATA_F_IRQ | ATA_F_DMA }, + {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48, ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA }, + {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48, ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA }, + {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48, ATA_F_IRQ | ATA_F_DMA }, +# endif + {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA }, /* Promise used a different PCI ident for the raid card apparently to try and prevent Linux detecting it and using our own raid code. We want to detect it for the ataraid drivers, so we have to list both here.. */ - {DEVID_PDC20268R,"PDC20270", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, - {DEVID_PDC20269,"PDC20269", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, - {DEVID_PDC20275,"PDC20275", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, - {DEVID_RZ1000, "RZ1000", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_RZ1001, "RZ1001", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_SAMURAI, "SAMURAI", NULL, NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CMD640, "CMD640", NULL, NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_NS87410, "NS87410", NULL, NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0 }, - {DEVID_SIS5513, "SIS5513", PCI_SIS5513, ATA66_SIS5513, INIT_SIS5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0 }, - {DEVID_CMD643, "CMD643", PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CMD646, "CMD646", PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_CMD648, "CMD648", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CMD649, "CMD649", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CMD680, "CMD680", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_HT6565, "HT6565", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_OPTI621, "OPTI621", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, - {DEVID_OPTI621X,"OPTI621X", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, - {DEVID_TRM290, "TRM290", NULL, NULL, INIT_TRM290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_NS87415, "NS87415", NULL, NULL, INIT_NS87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_AEC6210, "AEC6210", PCI_AEC62XX, NULL, INIT_AEC62XX, DMA_AEC62XX, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0 }, - {DEVID_AEC6260, "AEC6260", PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0 }, - {DEVID_AEC6260R,"AEC6260R", PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0 }, - {DEVID_W82C105, "W82C105", PCI_W82C105, NULL, INIT_W82C105, DMA_W82C105, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 }, - {DEVID_UM8673F, "UM8673F", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_HPT34X, "HPT34X", PCI_HPT34X, NULL, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16 }, - {DEVID_HPT366, "HPT366", PCI_HPT366, ATA66_HPT366, INIT_HPT366, DMA_HPT366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 240 }, - {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, ATA66_ALI15X3, INIT_ALI15X3, DMA_ALI15X3, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CS5530, "CS5530", PCI_CS5530, NULL, INIT_CS5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_AMD7401, "AMD7401", NULL, NULL, NULL, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, - {DEVID_AMD7409, "AMD7409", PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, - {DEVID_AMD7411, "AMD7411", PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, - {DEVID_AMD7441, "AMD7441", PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, - {DEVID_PDCADMA, "PDCADMA", PCI_PDCADMA, ATA66_PDCADMA, INIT_PDCADMA, DMA_PDCADMA, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, - {DEVID_SLC90E66,"SLC90E66", PCI_SLC90E66, ATA66_SLC90E66, INIT_SLC90E66, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_OSB4, "ServerWorks OSB4", PCI_SVWKS, ATA66_SVWKS, INIT_SVWKS, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CSB5, "ServerWorks CSB5", PCI_SVWKS, ATA66_SVWKS, INIT_SVWKS, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_ITE8172G,"IT8172G", PCI_IT8172, NULL, INIT_IT8172, NULL, {{0x00,0x00,0x00}, {0x40,0x00,0x01}}, ON_BOARD, 0 }, - {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; + {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA }, + {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA }, + {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA }, +#endif +#ifdef CONFIG_BLK_DEV_RZ1000 + {PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, NULL, NULL, ide_init_rz1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, NULL, NULL, ide_init_rz1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, +#endif +#ifdef CONFIG_BLK_DEV_SIS5513 + {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, pci_init_sis5513, ata66_sis5513, ide_init_sis5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0, ATA_F_NOADMA }, +#endif +#ifdef CONFIG_BLK_DEV_CMD64X + {PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, pci_init_cmd64x, NULL, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, pci_init_cmd64x, NULL, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0, ATA_F_DMA }, + {PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, pci_init_cmd64x, ata66_cmd64x, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA }, + {PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, pci_init_cmd64x, ata66_cmd64x, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA }, + {PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_680, pci_init_cmd64x, ata66_cmd64x, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA }, +#endif +#ifdef CONFIG_BLK_DEV_OPTI621 + {PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, NULL, NULL, ide_init_opti621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, NULL, NULL, ide_init_opti621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 }, +#endif +#ifdef CONFIG_BLK_DEV_TRM290 + {PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290, NULL, NULL, ide_init_trm290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, +#endif +#ifdef CONFIG_BLK_DEV_NS87415 + {PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, NULL, NULL, ide_init_ns87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, +#endif +#ifdef CONFIG_BLK_DEV_AEC62XX + {PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, pci_init_aec62xx, NULL, ide_init_aec62xx, ide_dmacapable_aec62xx, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0, ATA_F_SER | ATA_F_IRQ | ATA_F_DMA }, + {PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860, pci_init_aec62xx, ata66_aec62xx, ide_init_aec62xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0, ATA_F_IRQ | ATA_F_NOADMA | ATA_F_DMA }, + {PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R, pci_init_aec62xx, ata66_aec62xx, ide_init_aec62xx, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA }, +#endif +#ifdef CONFIG_BLK_DEV_SL82C105 + {PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, pci_init_sl82c105, NULL, ide_init_sl82c105, dma_init_sl82c105, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0, 0 }, +#endif +#ifdef CONFIG_BLK_DEV_HPT34X + {PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343, pci_init_hpt34x, NULL, ide_init_hpt34x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16, ATA_F_NOADMA | ATA_F_DMA }, +#endif +#ifdef CONFIG_BLK_DEV_HPT366 + {PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, pci_init_hpt366, ata66_hpt366, ide_init_hpt366, ide_dmacapable_hpt366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 240, ATA_F_IRQ | ATA_F_HPTHACK | ATA_F_DMA }, +#endif +#ifdef CONFIG_BLK_DEV_ALI15X3 + {PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, pci_init_ali15x3, ata66_ali15x3, ide_init_ali15x3, ide_dmacapable_ali15x3, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, +#endif +#ifdef CONFIG_BLK_DEV_CY82C693 + {PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, pci_init_cy82c693, NULL, ide_init_cy82c693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA }, +#endif +#ifdef CONFIG_BLK_DEV_CS5530 + {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE, pci_init_cs5530, NULL, ide_init_cs5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA }, +#endif +#ifdef CONFIG_BLK_DEV_AMD74XX + {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, NULL, NULL, NULL, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7441, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 }, +#endif +#ifdef CONFIG_BLK_DEV_PDC_ADMA + {PCI_VENDOR_ID_PDC, PCI_DEVICE_ID_PDC_1841, pci_init_pdcadma, ata66_pdcadma, ide_init_pdcadma, ide_dmacapable_pdcadma, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_NODMA }, +#endif +#ifdef CONFIG_BLK_DEV_SLC90E66 + {PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, pci_init_slc90e66, ata66_slc90e66, ide_init_slc90e66, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 }, +#endif +#ifdef CONFIG_BLK_DEV_SVWKS + {PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, pci_init_svwks, ata66_svwks, ide_init_svwks, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA }, + {PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, pci_init_svwks, ata66_svwks, ide_init_svwks, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, +#endif +#ifdef CONFIG_BLK_DEV_IT8172 + {PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, pci_init_it8172, NULL, ide_init_it8172, NULL, {{0x00,0x00,0x00}, {0x40,0x00,0x01}}, ON_BOARD, 0, 0 }, +#endif + /* Those are id's of chips we don't deal currently with. */ + {PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640, NULL, NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, NULL, NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 }, + {PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_FIXIRQ }, + {PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_FIXIRQ }, + {PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_FIXIRQ }, + {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_NOADMA }, + {0, 0, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; /* * This allows offboard ide-pci cards the enable a BIOS, verify interrupt * settings of split-mirror pci-config space, place chipset into init-mode, * and/or preserve an interrupt if the card is not native ide support. */ -static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name) +static unsigned int __init trust_pci_irq(ide_pci_device_t *d, struct pci_dev *dev) { - switch(dev->device) { - case PCI_DEVICE_ID_TTI_HPT366: - case PCI_DEVICE_ID_PROMISE_20246: - case PCI_DEVICE_ID_PROMISE_20262: - case PCI_DEVICE_ID_PROMISE_20265: - case PCI_DEVICE_ID_PROMISE_20267: - case PCI_DEVICE_ID_PROMISE_20268: - case PCI_DEVICE_ID_PROMISE_20268R: - case PCI_DEVICE_ID_PROMISE_20269: - case PCI_DEVICE_ID_PROMISE_20275: - case PCI_DEVICE_ID_ARTOP_ATP850UF: - case PCI_DEVICE_ID_ARTOP_ATP860: - case PCI_DEVICE_ID_ARTOP_ATP860R: - return dev->irq; - default: - break; - } + if (d->flags & ATA_F_IRQ) + return dev->irq; + return 0; } @@ -491,7 +344,7 @@ * Match a PCI IDE port against an entry in ide_hwifs[], * based on io_base port if possible. */ -static ide_hwif_t __init *ide_match_hwif (unsigned long io_base, byte bootable, const char *name) +static ide_hwif_t __init *lookup_hwif (unsigned long io_base, byte bootable, const char *name) { int h; ide_hwif_t *hwif; @@ -553,7 +406,7 @@ return NULL; } -static int __init ide_setup_pci_baseregs (struct pci_dev *dev, const char *name) +static int __init setup_pci_baseregs (struct pci_dev *dev, const char *name) { byte reg, progif = 0; @@ -566,7 +419,7 @@ return 1; } printk("%s: placing both ports into native PCI mode\n", name); - (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5); + pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5); if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) { printk("%s: rewrite of PROGIF failed, wanted 0x%04x, got 0x%04x\n", name, progif|5, progif); return 1; @@ -588,23 +441,181 @@ } /* - * ide_setup_pci_device() looks at the primary/secondary interfaces - * on a PCI IDE device and, if they are enabled, prepares the IDE driver - * for use with them. This generic code works for most PCI chipsets. + * Setup a particular port on an ATA host controller. * - * One thing that is not standardized is the location of the - * primary/secondary interface "enable/disable" bits. For chipsets that - * we "know" about, this information is in the ide_pci_device_t struct; - * for all other chipsets, we just assume both interfaces are enabled. + * This get's called once for the master and for the slave interface. */ -static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d) +static int __init setup_host_channel(struct pci_dev *dev, + ide_pci_device_t *d, + int port, + u8 class_rev, + int pciirq, ide_hwif_t **mate, + int autodma, + unsigned short *pcicmd) { - unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0; - unsigned short pcicmd = 0, tried_config = 0; - byte tmp = 0; - ide_hwif_t *hwif, *mate = NULL; + unsigned long base = 0; + unsigned long ctl = 0; + ide_pci_enablebit_t *e = &(d->enablebits[port]); + ide_hwif_t *hwif; + + u8 tmp; + if (port == 1) { + + /* If this is a Promise FakeRaid controller, the 2nd controller + * will be marked as disabled while it is actually there and + * enabled by the bios for raid purposes. Skip the normal "is + * it enabled" test for those. + */ + if (d->flags & ATA_F_PHACK) + goto controller_ok; + } + + /* Test whatever the port is enabled. + */ + if (e->reg) { + if (pci_read_config_byte(dev, e->reg, &tmp)) + return 0; /* error! */ + if ((tmp & e->mask) != e->val) + return 0; + } + + /* Nothing to be done for the second port. + */ + if (port == 1) { + if ((d->flags & ATA_F_HPTHACK) && (class_rev < 0x03)) + return 0; + } +controller_ok: + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) { + ctl = dev->resource[(2 * port) + 1].start; + base = dev->resource[2 * port].start; + if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) || !(base & PCI_BASE_ADDRESS_IO_MASK)) { + printk(KERN_WARNING "%s: error: IO reported as MEM by BIOS!\n", dev->name); + /* try it with the default values */ + ctl = 0; + base = 0; + } + } + if (ctl && !base) { + printk(KERN_WARNING "%s: error: missing MEM base info from BIOS!\n", dev->name); + /* we will still try to get along with the default */ + } + if (base && !ctl) { + printk(KERN_WARNING "%s: error: missing IO base info from BIOS!\n", dev->name); + /* we will still try to get along with the default */ + } + + /* Fill in the default values: */ + if (!ctl) + ctl = port ? 0x374 : 0x3f4; + if (!base) + base = port ? 0x170 : 0x1f0; + + if ((hwif = lookup_hwif(base, d->bootable, dev->name)) == NULL) + return -ENOMEM; /* no room in ide_hwifs[] */ + + if (hwif->io_ports[IDE_DATA_OFFSET] != base) { + ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL); + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); + hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; + } + + hwif->chipset = ide_pci; + hwif->pci_dev = dev; + hwif->channel = port; + if (!hwif->irq) + hwif->irq = pciirq; + + /* Setup the mate interface if we have two channels. + */ + if (*mate) { + hwif->mate = *mate; + (*mate)->mate = hwif; + if (d->flags & ATA_F_SER) { + hwif->serialized = 1; + (*mate)->serialized = 1; + } + } + + /* Hard wired IRQ lines on UMC chips and no DMA transfers.*/ + if (d->flags & ATA_F_FIXIRQ) { + hwif->irq = hwif->channel ? 15 : 14; + goto no_dma; + } + if (d->flags & ATA_F_NODMA) + goto no_dma; + + /* Check whatever this interface is UDMA4 mode capable. */ + if (hwif->udma_four) { + printk("%s: warning: ATA-66/100 forced bit set!\n", dev->name); + } else { + if (d->ata66_check) + hwif->udma_four = d->ata66_check(hwif); + } +#ifdef CONFIG_BLK_DEV_IDEDMA + if (d->flags & ATA_F_NOADMA) + autodma = 0; + + if (autodma) + hwif->autodma = 1; + + if ((d->flags & ATA_F_DMA) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) { + unsigned long dma_base; + + dma_base = ide_get_or_set_dma_base(hwif, (!*mate && d->extra) ? d->extra : 0, dev->name); + if (dma_base && !(*pcicmd & PCI_COMMAND_MASTER)) { + + /* + * Set up BM-DMA capability (PnP BIOS should have done this already) + */ + if (!(d->vendor == PCI_VENDOR_ID_CYRIX && d->device == PCI_DEVICE_ID_CYRIX_5530_IDE)) + hwif->autodma = 0; /* default DMA off if we had to configure it here */ + pci_write_config_word(dev, PCI_COMMAND, *pcicmd | PCI_COMMAND_MASTER); + if (pci_read_config_word(dev, PCI_COMMAND, pcicmd) || !(*pcicmd & PCI_COMMAND_MASTER)) { + printk("%s: %s error updating PCICMD\n", hwif->name, dev->name); + dma_base = 0; + } + } + if (dma_base) { + if (d->dma_init) + d->dma_init(hwif, dma_base); + else /* FIXME: use a generic device descriptor instead */ + ide_setup_dma(hwif, dma_base, 8); + } else { + printk("%s: %s Bus-Master DMA was disabled by BIOS\n", hwif->name, dev->name); + } + } +#endif +no_dma: + if (d->init_hwif) /* Call chipset-specific routine for each enabled hwif */ + d->init_hwif(hwif); + + *mate = hwif; + + /* we are done */ + + return 0; +} + +/* + * Looks at the primary/secondary chanells on a PCI IDE device and, if they + * are enabled, prepares the IDE driver for use with them. This generic code + * works for most PCI chipsets. + * + * One thing that is not standardized is the location of the primary/secondary + * interface "enable/disable" bits. For chipsets that we "know" about, this + * information is in the ide_pci_device_t struct; for all other chipsets, we + * just assume both interfaces are enabled. + */ + +static void __init setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d) +{ + int autodma = 0; + int pciirq = 0; + unsigned short pcicmd = 0; + unsigned short tried_config = 0; + ide_hwif_t *mate = NULL; unsigned int class_rev; - static int secondpdc = 0; #ifdef CONFIG_IDEDMA_AUTO if (!noautodma) @@ -612,18 +623,18 @@ #endif if (d->init_hwif == IDE_NO_DRIVER) { - printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", d->name); + printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", dev->name); d->init_hwif = NULL; } if (pci_enable_device(dev)) { - printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name); + printk(KERN_WARNING "%s: Could not enable PCI device.\n", dev->name); return; } check_if_enabled: if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) { - printk("%s: error accessing PCI regs\n", d->name); + printk("%s: error accessing PCI regs\n", dev->name); return; } if (!(pcicmd & PCI_COMMAND_IO)) { /* is device disabled? */ @@ -635,42 +646,38 @@ * but we'll eventually ignore it again if no drives respond. */ if (tried_config++ - || ide_setup_pci_baseregs(dev, d->name) + || setup_pci_baseregs(dev, dev->name) || pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) { - printk("%s: device disabled (BIOS)\n", d->name); + printk("%s: device disabled (BIOS)\n", dev->name); return; } autodma = 0; /* default DMA off if we had to configure it here */ goto check_if_enabled; } if (tried_config) - printk("%s: device enabled (Linux)\n", d->name); + printk("%s: device enabled (Linux)\n", dev->name); pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) { - /* see comments in hpt34x.c on why..... */ - char *chipset_names[] = {"HPT343", "HPT345"}; - strcpy(d->name, chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]); + if (d->vendor == PCI_VENDOR_ID_TTI && PCI_DEVICE_ID_TTI_HPT343) { + /* see comments in hpt34x.c to see why... */ d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD; } - printk("%s: chipset revision %d\n", d->name, class_rev); + printk("%s: chipset revision %d\n", dev->name, class_rev); /* * Can we trust the reported IRQ? */ pciirq = dev->irq; - - if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID) - { + + if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID) { /* By rights we want to ignore these, but the Promise Fastrak people have some strange ideas about proprietary so we have to act otherwise on those. The supertrak however we need to skip */ - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265)) - { + if (d->vendor == PCI_VENDOR_ID_PROMISE && d->device == PCI_DEVICE_ID_PROMISE_20265) { printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n"); if(dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_INTEL && dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) @@ -679,180 +686,43 @@ return; } } - /* Its attached to something else, just a random bridge. + /* Its attached to something else, just a random bridge. Suspect a fastrak and fall through */ } if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) { - printk("%s: not 100%% native mode: will probe irqs later\n", d->name); + printk("%s: not 100%% native mode: will probe irqs later\n", dev->name); /* * This allows offboard ide-pci cards the enable a BIOS, * verify interrupt settings of split-mirror pci-config * space, place chipset into init-mode, and/or preserve * an interrupt if the card is not native ide support. */ - pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : ide_special_settings(dev, d->name); + if (d->init_chipset) + pciirq = d->init_chipset(dev); + else + pciirq = trust_pci_irq(d, dev); } else if (tried_config) { - printk("%s: will probe irqs later\n", d->name); + printk("%s: will probe irqs later\n", dev->name); pciirq = 0; } else if (!pciirq) { - printk("%s: bad irq (%d): will probe later\n", d->name, pciirq); + printk("%s: bad irq (%d): will probe later\n", dev->name, pciirq); pciirq = 0; } else { if (d->init_chipset) - (void) d->init_chipset(dev, d->name); + d->init_chipset(dev); #ifdef __sparc__ printk("%s: 100%% native mode on irq %s\n", - d->name, __irq_itoa(pciirq)); + dev->name, __irq_itoa(pciirq)); #else - printk("%s: 100%% native mode on irq %d\n", d->name, pciirq); + printk("%s: 100%% native mode on irq %d\n", dev->name, pciirq); #endif } /* - * Set up the IDE ports + * Set up IDE chanells. First the primary, then the secondary. */ - for (port = 0; port <= 1; ++port) { - unsigned long base = 0, ctl = 0; - ide_pci_enablebit_t *e = &(d->enablebits[port]); - - /* - * If this is a Promise FakeRaid controller, the 2nd controller will be marked as - * disabled while it is actually there and enabled by the bios for raid purposes. - * Skip the normal "is it enabled" test for those. - */ - if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265)) && (secondpdc++==1) && (port==1) ) - goto controller_ok; - if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262)) && (secondpdc++==1) && (port==1) ) - goto controller_ok; - - if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val)) - continue; /* port not enabled */ -controller_ok: - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port) && (class_rev < 0x03)) - return; - if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) { - ctl = dev->resource[(2*port)+1].start; - base = dev->resource[2*port].start; - if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) || - !(base & PCI_BASE_ADDRESS_IO_MASK)) { - printk("%s: IO baseregs (BIOS) are reported as MEM, report to .\n", d->name); -#if 0 - /* FIXME! This really should check that it really gets the IO/MEM part right! */ - continue; -#endif - } - } - if ((ctl && !base) || (base && !ctl)) { - printk("%s: inconsistent baseregs (BIOS) for port %d, skipping\n", d->name, port); - continue; - } - if (!ctl) - ctl = port ? 0x374 : 0x3f4; /* use default value */ - if (!base) - base = port ? 0x170 : 0x1f0; /* use default value */ - if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL) - continue; /* no room in ide_hwifs[] */ - if (hwif->io_ports[IDE_DATA_OFFSET] != base) { - ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL); - memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); - hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; - } - hwif->chipset = ide_pci; - hwif->pci_dev = dev; - hwif->pci_devid = d->devid; - hwif->channel = port; - if (!hwif->irq) - hwif->irq = pciirq; - if (mate) { - hwif->mate = mate; - mate->mate = hwif; - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210)) { - hwif->serialized = 1; - mate->serialized = 1; - } - } - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8673F)) { - hwif->irq = hwif->channel ? 15 : 14; - goto bypass_umc_dma; - } - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_MPIIX)) - goto bypass_piix_dma; - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA)) - goto bypass_legacy_dma; - if (hwif->udma_four) { - printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name); - } else { - hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0; - } -#ifdef CONFIG_BLK_DEV_IDEDMA - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_PIIX4NX) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_VIA_IDE) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_MR_IDE) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_VP_IDE)) - autodma = 0; - if (autodma) - hwif->autodma = 1; - - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD680) || - IDE_PCI_DEVID_EQ(d->devid, DEVID_OSB4) || - ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) { - unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name); - if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) { - /* - * Set up BM-DMA capability (PnP BIOS should have done this) - */ - if (!IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530)) - hwif->autodma = 0; /* default DMA off if we had to configure it here */ - (void) pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER); - if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) { - printk("%s: %s error updating PCICMD\n", hwif->name, d->name); - dma_base = 0; - } - } - if (dma_base) { - if (d->dma_init) { - d->dma_init(hwif, dma_base); - } else { - ide_setup_dma(hwif, dma_base, 8); - } - } else { - printk("%s: %s Bus-Master DMA disabled (BIOS)\n", hwif->name, d->name); - } - } -#endif /* CONFIG_BLK_DEV_IDEDMA */ -bypass_legacy_dma: -bypass_piix_dma: -bypass_umc_dma: - if (d->init_hwif) /* Call chipset-specific routine for each enabled hwif */ - d->init_hwif(hwif); - mate = hwif; - at_least_one_hwif_enabled = 1; - } - if (!at_least_one_hwif_enabled) - printk("%s: neither IDE port enabled (BIOS)\n", d->name); + setup_host_channel(dev, d, 0, class_rev, pciirq, &mate, autodma, &pcicmd); + setup_host_channel(dev, d, 1, class_rev, pciirq, &mate, autodma, &pcicmd); } static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d) @@ -860,9 +730,9 @@ struct pci_dev *dev2 = NULL, *findev; ide_pci_device_t *d2; - if ((dev->bus->self && - dev->bus->self->vendor == PCI_VENDOR_ID_DEC) && - (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) { + if (dev->bus->self && + dev->bus->self->vendor == PCI_VENDOR_ID_DEC && + dev->bus->self->device == PCI_DEVICE_ID_DEC_21150) { if (PCI_SLOT(dev->devfn) & 2) { return; } @@ -884,13 +754,13 @@ } } - printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn); - ide_setup_pci_device(dev, d); + printk("%s: IDE controller on PCI bus %02x dev %02x\n", dev->name, dev->bus->number, dev->devfn); + setup_pci_device(dev, d); if (!dev2) return; d2 = d; - printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn); - ide_setup_pci_device(dev2, d2); + printk("%s: IDE controller on PCI bus %02x dev %02x\n", dev2->name, dev2->bus->number, dev2->devfn); + setup_pci_device(dev2, d2); } static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d) @@ -899,7 +769,6 @@ ide_pci_device_t *d2; unsigned char pin1 = 0, pin2 = 0; unsigned int class_rev; - char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"}; if (PCI_FUNC(dev->devfn) & 1) return; @@ -907,20 +776,18 @@ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - strcpy(d->name, chipset_names[class_rev]); - switch(class_rev) { case 4: - case 3: printk("%s: IDE controller on PCI slot %s\n", d->name, dev->slot_name); - ide_setup_pci_device(dev, d); + case 3: printk("%s: IDE controller on PCI slot %s\n", dev->name, dev->slot_name); + setup_pci_device(dev, d); return; default: break; } pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); pci_for_each_dev(findev) { - if ((findev->vendor == dev->vendor) && - (findev->device == dev->device) && + if (findev->vendor == dev->vendor && + findev->device == dev->device && ((findev->devfn - dev->devfn) == 1) && (PCI_FUNC(findev->devfn) & 1)) { dev2 = findev; @@ -929,7 +796,7 @@ hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0; if (hpt363_shared_pin && hpt363_shared_irq) { d->bootable = ON_BOARD; - printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", d->name, pin1, pin2); + printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", dev->name, pin1, pin2); #if 0 /* I forgot why I did this once, but it fixed something. */ pci_write_config_byte(dev2, PCI_INTERRUPT_PIN, dev->irq); @@ -940,48 +807,55 @@ break; } } - printk("%s: IDE controller on PCI slot %s\n", d->name, dev->slot_name); - ide_setup_pci_device(dev, d); + printk("%s: IDE controller on PCI slot %s\n", dev->name, dev->slot_name); + setup_pci_device(dev, d); if (!dev2) return; d2 = d; - printk("%s: IDE controller on PCI slot %s\n", d2->name, dev2->slot_name); - ide_setup_pci_device(dev2, d2); + printk("%s: IDE controller on PCI slot %s\n", dev2->name, dev2->slot_name); + setup_pci_device(dev2, d2); } /* - * ide_scan_pcibus() gets invoked at boot time from ide.c. - * It finds all PCI IDE controllers and calls ide_setup_pci_device for them. + * This finds all PCI IDE controllers and calls appriopriate initialization + * functions for them. */ -void __init ide_scan_pcidev (struct pci_dev *dev) +static void __init ide_scan_pcidev(struct pci_dev *dev) { - ide_pci_devid_t devid; + unsigned short vendor; + unsigned short device; ide_pci_device_t *d; - devid.vid = dev->vendor; - devid.did = dev->device; - for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d); + vendor = dev->vendor; + device = dev->device; + + /* Look up the chipset information. + */ + d = pci_chipsets; + while (d->vendor && !(d->vendor == vendor && d->device == device)) + ++d; + if (d->init_hwif == IDE_IGNORE) - printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name); - else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(PCI_FUNC(dev->devfn) & 1)) + printk("%s: has been ignored by PCI bus scan\n", dev->name); + else if ((d->vendor == PCI_VENDOR_ID_OPTI && d->device == PCI_DEVICE_ID_OPTI_82C558) && !(PCI_FUNC(dev->devfn) & 1)) return; - else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))) + else if ((d->vendor == PCI_VENDOR_ID_CONTAQ && d->device == PCI_DEVICE_ID_CONTAQ_82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))) return; /* CY82C693 is more than only a IDE controller */ - else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_ITE8172G) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))) + else if ((d->vendor == PCI_VENDOR_ID_ITE && d->device == PCI_DEVICE_ID_ITE_IT8172G) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))) return; /* IT8172G is also more than only an IDE controller */ - else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1)) + else if ((d->vendor == PCI_VENDOR_ID_UMC && d->device == PCI_DEVICE_ID_UMC_UM8886A) && !(PCI_FUNC(dev->devfn) & 1)) return; /* UM8886A/BF pair */ - else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366)) + else if (d->flags & ATA_F_HPTHACK) hpt366_device_order_fixup(dev, d); - else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R)) + else if (d->vendor == PCI_VENDOR_ID_PROMISE && d->device == PCI_DEVICE_ID_PROMISE_20268R) pdc20270_device_order_fixup(dev, d); - else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { - if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL)) - printk("%s: unknown IDE controller on PCI slot %s, VID=%04x, DID=%04x\n", - d->name, dev->slot_name, devid.vid, devid.did); + else if (!(d->vendor == 0 && d->device == 0) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { + if (d->vendor == 0 && d->device == 0) + printk("%s: unknown IDE controller on PCI slot %s, vendor=%04x, device=%04x\n", + dev->name, dev->slot_name, vendor, device); else - printk("%s: IDE controller on PCI slot %s\n", d->name, dev->slot_name); - ide_setup_pci_device(dev, d); + printk("%s: IDE controller on PCI slot %s\n", dev->name, dev->slot_name); + setup_pci_device(dev, d); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-pnp.c linux-2.5/drivers/ide/ide-pnp.c --- linux-2.5.5/drivers/ide/ide-pnp.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/ide/ide-pnp.c Fri Mar 1 15:07:38 2002 @@ -57,6 +57,7 @@ static int __init pnpide_generic_init(struct pci_dev *dev, int enable) { hw_regs_t hw; + ide_hwif_t *hwif; int index; if (!enable) @@ -69,10 +70,11 @@ generic_ide_offsets, (ide_ioreg_t) DEV_IO(dev, 1), 0, NULL, DEV_IRQ(dev, 0)); - index = ide_register_hw(&hw, NULL); + index = ide_register_hw(&hw, &hwif); if (index != -1) { - printk("ide%d: %s IDE interface\n", index, DEV_NAME(dev)); + hwif->pci_dev = dev; + printk("ide%d: %s IDE interface\n", index, DEV_NAME(dev)); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-probe.c linux-2.5/drivers/ide/ide-probe.c --- linux-2.5.5/drivers/ide/ide-probe.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/ide/ide-probe.c Fri Mar 1 15:07:38 2002 @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -129,17 +130,17 @@ } #endif /* CONFIG_BLK_DEV_PDC4030 */ switch (type) { - case ide_floppy: + case ATA_FLOPPY: if (!strstr(id->model, "CD-ROM")) { if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP")) printk("cdrom or floppy?, assuming "); - if (drive->media != ide_cdrom) { + if (drive->type != ATA_ROM) { printk ("FLOPPY"); break; } } - type = ide_cdrom; /* Early cdrom models used zero */ - case ide_cdrom: + type = ATA_ROM; /* Early cdrom models used zero */ + case ATA_ROM: drive->removable = 1; #ifdef CONFIG_PPC /* kludge for Apple PowerBook internal zip */ @@ -151,10 +152,10 @@ #endif printk ("CD/DVD-ROM"); break; - case ide_tape: + case ATA_TAPE: printk ("TAPE"); break; - case ide_optical: + case ATA_MOD: printk ("OPTICAL"); drive->removable = 1; break; @@ -163,7 +164,7 @@ break; } printk (" drive\n"); - drive->media = type; + drive->type = type; return; } @@ -183,7 +184,7 @@ mate->noprobe = 1; } } - drive->media = ide_disk; + drive->type = ATA_DISK; printk("ATA DISK drive\n"); QUIRK_LIST(HWIF(drive),drive); return; @@ -326,12 +327,12 @@ int rc; ide_hwif_t *hwif = HWIF(drive); if (drive->present) { /* avoid waiting for inappropriate probes */ - if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY)) + if ((drive->type != ATA_DISK) && (cmd == WIN_IDENTIFY)) return 4; } #ifdef DEBUG - printk("probing for %s: present=%d, media=%d, probetype=%s\n", - drive->name, drive->present, drive->media, + printk("probing for %s: present=%d, type=%d, probetype=%s\n", + drive->name, drive->present, drive->type, (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI"); #endif ide_delay_50ms(); /* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */ @@ -420,10 +421,10 @@ if (!drive->present) return; /* drive not found */ if (drive->id == NULL) { /* identification failed? */ - if (drive->media == ide_disk) { + if (drive->type == ATA_DISK) { printk ("%s: non-IDE drive, CHS=%d/%d/%d\n", drive->name, drive->cyl, drive->head, drive->sect); - } else if (drive->media == ide_cdrom) { + } else if (drive->type == ATA_ROM) { printk("%s: ATAPI cdrom (?)\n", drive->name); } else { drive->present = 0; /* nuke it */ @@ -465,37 +466,46 @@ static void hwif_register (ide_hwif_t *hwif) { + /* Register this hardware interface within the global device tree. + */ + sprintf(hwif->device.bus_id, "%04x", hwif->io_ports[IDE_DATA_OFFSET]); + sprintf(hwif->device.name, "ide"); + hwif->device.driver_data = hwif; + if (hwif->pci_dev) + hwif->device.parent = &hwif->pci_dev->dev; + else + hwif->device.parent = NULL; /* Would like to do = &device_legacy */ + device_register(&hwif->device); + if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) == ((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) { ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name); hwif->straight8 = 1; - goto jump_straight8; - } - - if (hwif->io_ports[IDE_DATA_OFFSET]) - ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name); - if (hwif->io_ports[IDE_ERROR_OFFSET]) - ide_request_region(hwif->io_ports[IDE_ERROR_OFFSET], 1, hwif->name); - if (hwif->io_ports[IDE_NSECTOR_OFFSET]) - ide_request_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1, hwif->name); - if (hwif->io_ports[IDE_SECTOR_OFFSET]) - ide_request_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1, hwif->name); - if (hwif->io_ports[IDE_LCYL_OFFSET]) - ide_request_region(hwif->io_ports[IDE_LCYL_OFFSET], 1, hwif->name); - if (hwif->io_ports[IDE_HCYL_OFFSET]) - ide_request_region(hwif->io_ports[IDE_HCYL_OFFSET], 1, hwif->name); - if (hwif->io_ports[IDE_SELECT_OFFSET]) - ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name); - if (hwif->io_ports[IDE_STATUS_OFFSET]) - ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name); + } else { + if (hwif->io_ports[IDE_DATA_OFFSET]) + ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_ERROR_OFFSET]) + ide_request_region(hwif->io_ports[IDE_ERROR_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_NSECTOR_OFFSET]) + ide_request_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_SECTOR_OFFSET]) + ide_request_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_LCYL_OFFSET]) + ide_request_region(hwif->io_ports[IDE_LCYL_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_HCYL_OFFSET]) + ide_request_region(hwif->io_ports[IDE_HCYL_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_SELECT_OFFSET]) + ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_STATUS_OFFSET]) + ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name); -jump_straight8: + } if (hwif->io_ports[IDE_CONTROL_OFFSET]) ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name); #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) if (hwif->io_ports[IDE_IRQ_OFFSET]) ide_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name); -#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */ +#endif } /* @@ -509,13 +519,6 @@ if (hwif->noprobe) return; -#ifdef CONFIG_BLK_DEV_IDE - if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) { - extern void probe_cmos_for_drives(ide_hwif_t *); - - probe_cmos_for_drives (hwif); - } -#endif if ((hwif->chipset != ide_4drives || !hwif->mate->present) && #if CONFIG_BLK_DEV_PDC4030 @@ -533,7 +536,7 @@ } if (!msgout) printk("%s: ports already in use, skipping probe\n", hwif->name); - return; + return; } __save_flags(flags); /* local CPU only */ @@ -784,60 +787,51 @@ static void init_gendisk (ide_hwif_t *hwif) { struct gendisk *gd; - unsigned int unit, units, minors, i; + unsigned int unit, minors, i; extern devfs_handle_t ide_devfs_handle; -#if 1 - units = MAX_DRIVES; -#else - /* figure out maximum drive number on the interface */ - for (units = MAX_DRIVES; units > 0; --units) { - if (hwif->drives[units-1].present) - break; - } -#endif - - minors = units * (1<sizes = kmalloc (minors * sizeof(int), GFP_KERNEL); if (!gd->sizes) goto err_kmalloc_gd_sizes; + gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL); if (!gd->part) goto err_kmalloc_gd_part; + memset(gd->part, 0, minors * sizeof(struct hd_struct)); + blksize_size[hwif->major] = kmalloc (minors*sizeof(int), GFP_KERNEL); if (!blksize_size[hwif->major]) goto err_kmalloc_bs; - - memset(gd->part, 0, minors * sizeof(struct hd_struct)); - for (i = 0; i < minors; ++i) blksize_size[hwif->major][i] = BLOCK_SIZE; - for (unit = 0; unit < units; ++unit) + + for (unit = 0; unit < MAX_DRIVES; ++unit) hwif->drives[unit].part = &gd->part[unit << PARTN_BITS]; gd->major = hwif->major; /* our major device number */ gd->major_name = IDE_MAJOR_NAME; /* treated special in genhd.c */ gd->minor_shift = PARTN_BITS; /* num bits for partitions */ - gd->nr_real = units; /* current num real drives */ + gd->nr_real = MAX_DRIVES; /* current num real drives */ gd->next = NULL; /* linked list of major devs */ gd->fops = ide_fops; /* file operations */ - gd->de_arr = kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL); - gd->flags = kmalloc (sizeof *gd->flags * units, GFP_KERNEL); + gd->de_arr = kmalloc(sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL); + gd->flags = kmalloc(sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL); if (gd->de_arr) - memset (gd->de_arr, 0, sizeof *gd->de_arr * units); + memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES); if (gd->flags) - memset (gd->flags, 0, sizeof *gd->flags * units); + memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES); hwif->gd = gd; add_gendisk(gd); - for (unit = 0; unit < units; ++unit) { -#if 1 - char name[64]; + for (unit = 0; unit < MAX_DRIVES; ++unit) { + char name[80]; ide_add_generic_settings(hwif->drives + unit); hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit); sprintf (name, "host%d/bus%d/target%d/lun%d", @@ -846,19 +840,6 @@ hwif->channel, unit, hwif->drives[unit].lun); if (hwif->drives[unit].present) hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL); -#else - if (hwif->drives[unit].present) { - char name[64]; - - ide_add_generic_settings(hwif->drives + unit); - hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit); - sprintf (name, "host%d/bus%d/target%d/lun%d", - (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index, - hwif->channel, unit, hwif->drives[unit].lun); - hwif->drives[unit].de = - devfs_mk_dir (ide_devfs_handle, name, NULL); - } -#endif } return; @@ -869,7 +850,7 @@ err_kmalloc_gd_sizes: kfree(gd); err_kmalloc_gd: - printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n"); + printk(KERN_CRIT "(ide::init_gendisk) Out of memory\n"); return; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-proc.c linux-2.5/drivers/ide/ide-proc.c --- linux-2.5.5/drivers/ide/ide-proc.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/ide/ide-proc.c Fri Mar 1 15:07:38 2002 @@ -127,242 +127,8 @@ int (*via_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_VIA82CXXX */ -static int ide_getxdigit(char c) -{ - int digit; - if (isdigit(c)) - digit = c - '0'; - else if (isxdigit(c)) - digit = tolower(c) - 'a' + 10; - else - digit = -1; - return digit; -} - -static int xx_xx_parse_error (const char *data, unsigned long len, const char *msg) -{ - char errbuf[16]; - int i; - if (len >= sizeof(errbuf)) - len = sizeof(errbuf) - 1; - for (i = 0; i < len; ++i) { - char c = data[i]; - if (!c || c == '\n') - c = '\0'; - else if (iscntrl(c)) - c = '?'; - errbuf[i] = c; - } - errbuf[i] = '\0'; - printk("proc_ide: error: %s: '%s'\n", msg, errbuf); - return -EINVAL; -} - static struct proc_dir_entry * proc_ide_root = NULL; -static int proc_ide_write_config - (struct file *file, const char *buffer, unsigned long count, void *data) -{ - ide_hwif_t *hwif = data; - int for_real = 0; - unsigned long startn = 0, n, flags; - const char *start = NULL, *msg = NULL; - - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - /* - * Skip over leading whitespace - */ - while (count && isspace(*buffer)) { - --count; - ++buffer; - } - /* - * Do one full pass to verify all parameters, - * then do another to actually write the regs. - */ - save_flags(flags); /* all CPUs */ - do { - const char *p; - if (for_real) { - unsigned long timeout = jiffies + (3 * HZ); - ide_hwgroup_t *mygroup = (ide_hwgroup_t *)(hwif->hwgroup); - ide_hwgroup_t *mategroup = NULL; - if (hwif->mate && hwif->mate->hwgroup) - mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup); - cli(); /* all CPUs; ensure all writes are done together */ - while (test_bit(IDE_BUSY, &mygroup->flags) || (mategroup && test_bit(IDE_BUSY, &mategroup->flags))) { - sti(); /* all CPUs */ - if (0 < (signed long)(jiffies - timeout)) { - printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name); - restore_flags(flags); /* all CPUs */ - return -EBUSY; - } - cli(); /* all CPUs */ - } - } - p = buffer; - n = count; - while (n > 0) { - int d, digits; - unsigned int reg = 0, val = 0, is_pci; - start = p; - startn = n--; - switch (*p++) { - case 'R': is_pci = 0; - break; - case 'P': is_pci = 1; -#ifdef CONFIG_BLK_DEV_IDEPCI - if (hwif->pci_dev && !IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) - break; -#endif /* CONFIG_BLK_DEV_IDEPCI */ - msg = "not a PCI device"; - goto parse_error; - default: msg = "expected 'R' or 'P'"; - goto parse_error; - } - digits = 0; - while (n > 0 && (d = ide_getxdigit(*p)) >= 0) { - reg = (reg << 4) | d; - --n; - ++p; - ++digits; - } - if (!digits || (digits > 4) || (is_pci && reg > 0xff)) { - msg = "bad/missing register number"; - goto parse_error; - } - if (n-- == 0 || *p++ != ':') { - msg = "missing ':'"; - goto parse_error; - } - digits = 0; - while (n > 0 && (d = ide_getxdigit(*p)) >= 0) { - val = (val << 4) | d; - --n; - ++p; - ++digits; - } - if (digits != 2 && digits != 4 && digits != 8) { - msg = "bad data, 2/4/8 digits required"; - goto parse_error; - } - if (n > 0 && !isspace(*p)) { - msg = "expected whitespace after data"; - goto parse_error; - } - while (n > 0 && isspace(*p)) { - --n; - ++p; - } -#ifdef CONFIG_BLK_DEV_IDEPCI - if (is_pci && (reg & ((digits >> 1) - 1))) { - msg = "misaligned access"; - goto parse_error; - } -#endif /* CONFIG_BLK_DEV_IDEPCI */ - if (for_real) { -#if 0 - printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? "PCI" : "non-PCI", reg, val, digits); -#endif - if (is_pci) { -#ifdef CONFIG_BLK_DEV_IDEPCI - int rc = 0; - struct pci_dev *dev = hwif->pci_dev; - switch (digits) { - case 2: msg = "byte"; - rc = pci_write_config_byte(dev, reg, val); - break; - case 4: msg = "word"; - rc = pci_write_config_word(dev, reg, val); - break; - case 8: msg = "dword"; - rc = pci_write_config_dword(dev, reg, val); - break; - } - if (rc) { - restore_flags(flags); /* all CPUs */ - printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n", - msg, dev->bus->number, dev->devfn, reg, val); - printk("proc_ide_write_config: error %d\n", rc); - return -EIO; - } -#endif /* CONFIG_BLK_DEV_IDEPCI */ - } else { /* not pci */ -#if !defined(__mc68000__) && !defined(CONFIG_APUS) - -/* - * Geert Uytterhoeven - * - * unless you can explain me what it really does. - * On m68k, we don't have outw() and outl() yet, - * and I need a good reason to implement it. - * - * BTW, IMHO the main remaining portability problem with the IDE driver - * is that it mixes IO (ioport) and MMIO (iomem) access on different platforms. - * - * I think all accesses should be done using - * - * ide_in[bwl](ide_device_instance, offset) - * ide_out[bwl](ide_device_instance, value, offset) - * - * so the architecture specific code can #define ide_{in,out}[bwl] to the - * appropriate function. - * - */ - switch (digits) { - case 2: outb(val, reg); - break; - case 4: outw(val, reg); - break; - case 8: outl(val, reg); - break; - } -#endif /* !__mc68000__ && !CONFIG_APUS */ - } - } - } - } while (!for_real++); - restore_flags(flags); /* all CPUs */ - return count; -parse_error: - restore_flags(flags); /* all CPUs */ - printk("parse error\n"); - return xx_xx_parse_error(start, startn, msg); -} - -static int proc_ide_read_config - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - char *out = page; - int len; - -#ifdef CONFIG_BLK_DEV_IDEPCI - ide_hwif_t *hwif = data; - struct pci_dev *dev = hwif->pci_dev; - if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL) && dev && dev->bus) { - int reg = 0; - - out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n", - dev->bus->number, dev->devfn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel); - do { - byte val; - int rc = pci_read_config_byte(dev, reg, &val); - if (rc) { - printk("proc_ide_read_config: error %d reading bus %02x dev %02x reg 0x%02x\n", - rc, dev->bus->number, dev->devfn, reg); - out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n'); - } else - out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n'); - } while (reg < 0x100); - } else -#endif /* CONFIG_BLK_DEV_IDEPCI */ - out += sprintf(out, "(none)\n"); - len = out - page; - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - - static int ide_getdigit(char c) { int digit; @@ -373,20 +139,6 @@ return digit; } -static int proc_ide_read_drivers - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - char *out = page; - int len; - struct ide_driver_s * driver; - - for (driver = ide_drivers; driver; driver = driver->next) { - out += sprintf(out, "%s\n",driver->name); - } - len = out - page; - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - static int proc_ide_read_imodel (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -450,7 +202,7 @@ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); taskfile.sector_count = 0x01; - taskfile.command = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY ; + taskfile.command = (drive->type == ATA_DISK) ? WIN_IDENTIFY : WIN_PIDENTIFY ; return ide_wait_taskfile(drive, &taskfile, &hobfile, buf); } @@ -594,9 +346,9 @@ int proc_ide_read_capacity (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = data; - ide_driver_t *driver = drive->driver; - int len; + ide_drive_t *drive = data; + struct ata_operations *driver = drive->driver; + int len; if (!driver) len = sprintf(page, "(none)\n"); @@ -629,58 +381,31 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_ide_read_driver - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - ide_drive_t *drive = (ide_drive_t *) data; - ide_driver_t *driver = drive->driver; - int len; - - if (!driver) - len = sprintf(page, "(none)\n"); - else - len = sprintf(page, "%s\n", driver->name); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - -static int proc_ide_write_driver - (struct file *file, const char *buffer, unsigned long count, void *data) -{ - ide_drive_t *drive = data; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (ide_replace_subdriver(drive, buffer)) - return -EINVAL; - return count; -} - static int proc_ide_read_media (char *page, char **start, off_t off, int count, int *eof, void *data) { ide_drive_t *drive = data; - const char *media; + const char *type; int len; - switch (drive->media) { - case ide_disk: media = "disk\n"; + switch (drive->type) { + case ATA_DISK: type = "disk\n"; break; - case ide_cdrom: media = "cdrom\n"; + case ATA_ROM: type = "cdrom\n"; break; - case ide_tape: media = "tape\n"; + case ATA_TAPE: type = "tape\n"; break; - case ide_floppy:media = "floppy\n"; + case ATA_FLOPPY:type = "floppy\n"; break; - default: media = "UNKNOWN\n"; + default: type = "UNKNOWN\n"; break; } - strcpy(page,media); - len = strlen(media); + strcpy(page,type); + len = strlen(type); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static ide_proc_entry_t generic_drive_entries[] = { - { "driver", S_IFREG|S_IRUGO, proc_ide_read_driver, proc_ide_write_driver }, { "identify", S_IFREG|S_IRUSR, proc_ide_read_identify, NULL }, { "media", S_IFREG|S_IRUGO, proc_ide_read_media, NULL }, { "model", S_IFREG|S_IRUGO, proc_ide_read_dmodel, NULL }, @@ -724,7 +449,7 @@ for (d = 0; d < MAX_DRIVES; d++) { ide_drive_t *drive = &hwif->drives[d]; - ide_driver_t *driver = drive->driver; + struct ata_operations *driver = drive->driver; if (!drive->present) continue; @@ -745,35 +470,9 @@ } } -void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct proc_dir_entry *ent; - struct proc_dir_entry *parent = hwif->proc; - char name[64]; - - if (drive->present && !drive->proc) { - drive->proc = proc_mkdir(drive->name, parent); - if (drive->proc) - ide_add_proc_entries(drive->proc, generic_drive_entries, drive); - -/* - * assume that we have these already, however, should test FIXME! - * if (driver) { - * ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive); - * ide_add_proc_entries(drive->proc, driver->proc, drive); - * } - * - */ - sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name); - ent = proc_symlink(drive->name, proc_ide_root, name); - if (!ent) - return; - } -} - -void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) +static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) { - ide_driver_t *driver = drive->driver; + struct ata_operations *driver = drive->driver; if (drive->proc) { if (driver) @@ -799,7 +498,6 @@ static ide_proc_entry_t hwif_entries[] = { { "channel", S_IFREG|S_IRUGO, proc_ide_read_channel, NULL }, - { "config", S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config, proc_ide_write_config }, { "mate", S_IFREG|S_IRUGO, proc_ide_read_mate, NULL }, { "model", S_IFREG|S_IRUGO, proc_ide_read_imodel, NULL }, { NULL, 0, NULL, NULL } @@ -851,9 +549,6 @@ if (!proc_ide_root) return; create_proc_ide_interfaces(); - - create_proc_read_entry("drivers", 0, proc_ide_root, - proc_ide_read_drivers, NULL); #ifdef CONFIG_BLK_DEV_AEC62XX if ((aec62xx_display_info) && (aec62xx_proc)) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-swarm.c linux-2.5/drivers/ide/ide-swarm.c --- linux-2.5.5/drivers/ide/ide-swarm.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/ide/ide-swarm.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Derived loosely from ide-pmac.c, so: + * + * Copyright (C) 1998 Paul Mackerras. + * Copyright (C) 1995-1998 Mark Lord + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void __init swarm_ide_probe(void) +{ + int i; + ide_hwif_t *hwif; + /* + * Find the first untaken slot in hwifs + */ + for (i = 0; i < MAX_HWIFS; i++) { + if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) { + break; + } + } + if (i == MAX_HWIFS) { + printk("No space for SWARM onboard IDE driver in ide_hwifs[]. Not enabled.\n"); + return; + } + + /* Set up our stuff */ + hwif = &ide_hwifs[i]; + hwif->hw.io_ports[IDE_DATA_OFFSET] = SWARM_IDE_REG(0x1f0); + hwif->hw.io_ports[IDE_ERROR_OFFSET] = SWARM_IDE_REG(0x1f1); + hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SWARM_IDE_REG(0x1f2); + hwif->hw.io_ports[IDE_SECTOR_OFFSET] = SWARM_IDE_REG(0x1f3); + hwif->hw.io_ports[IDE_LCYL_OFFSET] = SWARM_IDE_REG(0x1f4); + hwif->hw.io_ports[IDE_HCYL_OFFSET] = SWARM_IDE_REG(0x1f5); + hwif->hw.io_ports[IDE_SELECT_OFFSET] = SWARM_IDE_REG(0x1f6); + hwif->hw.io_ports[IDE_STATUS_OFFSET] = SWARM_IDE_REG(0x1f7); + hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SWARM_IDE_REG(0x3f6); + hwif->hw.io_ports[IDE_IRQ_OFFSET] = SWARM_IDE_REG(0x3f7); +// hwif->hw->ack_intr = swarm_ide_ack_intr; + hwif->hw.irq = SWARM_IDE_INT; + hwif->ideproc = swarm_ideproc; + + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); + hwif->irq = hwif->hw.irq; + printk("SWARM onboard IDE configured as device %i\n", i); +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-tape.c linux-2.5/drivers/ide/ide-tape.c --- linux-2.5.5/drivers/ide/ide-tape.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/ide/ide-tape.c Fri Mar 1 15:07:38 2002 @@ -6098,8 +6098,11 @@ } idetape_chrdevs[minor].drive = NULL; restore_flags (flags); /* all CPUs (overkill?) */ - DRIVER(drive)->busy = 0; - (void) ide_unregister_subdriver (drive); + + /* FIXME: this appears to be totally wrong! */ + ata_ops(drive)->busy = 0; + + ide_unregister_subdriver (drive); drive->driver_data = NULL; devfs_unregister (tape->de_r); devfs_unregister (tape->de_n); @@ -6137,18 +6140,13 @@ #endif -int idetape_init (void); -int idetape_reinit(ide_drive_t *drive); +static int idetape_reinit(ide_drive_t *drive); /* * IDE subdriver functions, registered with ide.c */ -static ide_driver_t idetape_driver = { - name: "ide-tape", - media: ide_tape, - busy: 1, - supports_dma: 1, - supports_dsc_overlap: 1, +static struct ata_operations idetape_driver = { + owner: THIS_MODULE, cleanup: idetape_cleanup, standby: NULL, flushcache: NULL, @@ -6162,7 +6160,6 @@ pre_reset: idetape_pre_reset, capacity: NULL, proc: idetape_proc, - driver_init: idetape_init, driver_reinit: idetape_reinit, }; @@ -6178,90 +6175,10 @@ release: idetape_chrdev_release, }; -int idetape_reinit (ide_drive_t *drive) +/* This will propably just go entierly away... */ +static int idetape_reinit (ide_drive_t *drive) { -#if 0 - idetape_tape_t *tape; - int minor, failed = 0, supported = 0; -/* DRIVER(drive)->busy++; */ - MOD_INC_USE_COUNT; -#if ONSTREAM_DEBUG - printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n"); -#endif - if (!idetape_chrdev_present) - for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ ) - idetape_chrdevs[minor].drive = NULL; - - if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) { - ide_register_module (&idetape_module); - MOD_DEC_USE_COUNT; -#if ONSTREAM_DEBUG - printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); -#endif - return 0; - } - if (!idetape_chrdev_present && - devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) { - printk (KERN_ERR "ide-tape: Failed to register character device interface\n"); - MOD_DEC_USE_COUNT; -#if ONSTREAM_DEBUG - printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); -#endif - return -EBUSY; - } - do { - if (!idetape_identify_device (drive, drive->id)) { - printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name); - continue; - } - if (drive->scsi) { - if (strstr(drive->id->model, "OnStream DI-30")) { - printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model); - } else { - printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name); - continue; - } - } - tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL); - if (tape == NULL) { - printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name); - continue; - } - if (ide_register_subdriver (drive, &idetape_driver)) { - printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name); - kfree (tape); - continue; - } - for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++); - idetape_setup (drive, tape, minor); - idetape_chrdevs[minor].drive = drive; - tape->de_r = - devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT, - HWIF(drive)->major, minor, - S_IFCHR | S_IRUGO | S_IWUGO, - &idetape_fops, NULL); - tape->de_n = - devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT, - HWIF(drive)->major, minor + 128, - S_IFCHR | S_IRUGO | S_IWUGO, - &idetape_fops, NULL); - devfs_register_tape (tape->de_r); - supported++; failed--; - } while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL); - if (!idetape_chrdev_present && !supported) { - devfs_unregister_chrdev (IDETAPE_MAJOR, "ht"); - } else - idetape_chrdev_present = 1; - ide_register_module (&idetape_module); - MOD_DEC_USE_COUNT; -#if ONSTREAM_DEBUG - printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); -#endif - - return 0; -#else return 1; -#endif } MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver"); @@ -6277,7 +6194,6 @@ if (drive != NULL && idetape_cleanup (drive)) printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name); } - ide_unregister_module(&idetape_driver); } /* @@ -6297,8 +6213,8 @@ for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ ) idetape_chrdevs[minor].drive = NULL; - if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) { - ide_register_module (&idetape_driver); + if ((drive = ide_scan_devices(ATA_TAPE, "ide-tape", NULL, failed++)) == NULL) { + revalidate_drives(); MOD_DEC_USE_COUNT; #if ONSTREAM_DEBUG printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); @@ -6352,12 +6268,12 @@ &idetape_fops, NULL); devfs_register_tape (tape->de_r); supported++; failed--; - } while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL); + } while ((drive = ide_scan_devices(ATA_TAPE, "ide-tape", NULL, failed++)) != NULL); if (!idetape_chrdev_present && !supported) { devfs_unregister_chrdev (IDETAPE_MAJOR, "ht"); } else idetape_chrdev_present = 1; - ide_register_module (&idetape_driver); + revalidate_drives(); MOD_DEC_USE_COUNT; #if ONSTREAM_DEBUG printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide-taskfile.c linux-2.5/drivers/ide/ide-taskfile.c --- linux-2.5.5/drivers/ide/ide-taskfile.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/ide/ide-taskfile.c Fri Mar 1 15:07:38 2002 @@ -42,6 +42,24 @@ #define DTF(x...) #endif +/* + * for now, taskfile requests are special :/ + */ +static inline char *ide_map_rq(struct request *rq, unsigned long *flags) +{ + if (rq->bio) + return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq); + else + return rq->buffer + task_rq_offset(rq); +} + +static inline void ide_unmap_rq(struct request *rq, char *to, + unsigned long *flags) +{ + if (rq->bio) + bio_kunmap_irq(to, flags); +} + inline u32 task_read_24 (ide_drive_t *drive) { return (IN_BYTE(IDE_HCYL_REG)<<16) | @@ -630,7 +648,7 @@ if (rq->errors >= ERROR_MAX) { if (drive->driver != NULL) - DRIVER(drive)->end_request(0, HWGROUP(drive)); + ata_ops(drive)->end_request(0, HWGROUP(drive)); else ide_end_request(drive, 0); } else { @@ -878,6 +896,10 @@ } } while (msect); +#if 0 + if (!ide_end_request(1, HWGROUP(drive))) + return ide_stopped; +#endif /* * more data left @@ -1018,11 +1040,11 @@ if (!msect) { nsect = 1; while (rq->current_nr_sectors) { - pBuf = ide_map_rq(rq, &flags); + pBuf = ide_map_buffer(rq, &flags); DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors); drive->io_32bit = 0; taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); - ide_unmap_rq(pBuf, &flags); + ide_unmap_buffer(pBuf, &flags); drive->io_32bit = io_32bit; rq->errors = 0; rq->current_nr_sectors -= nsect; @@ -1137,7 +1159,7 @@ nsect = mcount; mcount -= nsect; - buffer = ide_map_buffer(rq, &flags); + buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq); rq->sector += nsect; rq->nr_sectors -= nsect; rq->current_nr_sectors -= nsect; @@ -1161,7 +1183,7 @@ * re-entering us on the last transfer. */ taskfile_output_data(drive, buffer, nsect * SECTOR_WORDS); - ide_unmap_buffer(buffer, &flags); + bio_kunmap_irq(buffer, &flags); } while (mcount); drive->io_32bit = io_32bit; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide.c linux-2.5/drivers/ide/ide.c --- linux-2.5.5/drivers/ide/ide.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/ide/ide.c Sun Mar 3 17:54:35 2002 @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/ide.c Version 6.31 June 9, 2000 - * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -114,22 +112,15 @@ * Native ATA-100 support * Prep for Cascades Project * Version 6.32 4GB highmem support for DMA, and mapping of those for - * PIO transfer (Jens Axboe) + * PIO transfer (Jens Axboe) * * Some additional driver compile-time options are in ./include/linux/ide.h - * - * To do, in likely order of completion: - * - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f - * */ -#define REVISION "Revision: 6.32" -#define VERSION "Id: ide.c 6.32 2001/05/24" +#define VERSION "7.0.0" #undef REALLY_SLOW_IO /* most systems can safely undef this */ -#define _IDE_C /* Tell ide.h it's really us */ - #include #include #include @@ -153,6 +144,8 @@ #include #include #include +#include +#include #include #include @@ -162,17 +155,100 @@ #include "ide_modes.h" -#ifdef CONFIG_KMOD -#include -#endif /* CONFIG_KMOD */ +/* Constant tables for PIO mode programming: + */ -/* default maximum number of failures */ -#define IDE_DEFAULT_MAX_FAILURES 1 +const ide_pio_timings_t ide_pio_timings[6] = { + { 70, 165, 600 }, /* PIO Mode 0 */ + { 50, 125, 383 }, /* PIO Mode 1 */ + { 30, 100, 240 }, /* PIO Mode 2 */ + { 30, 80, 180 }, /* PIO Mode 3 with IORDY */ + { 25, 70, 120 }, /* PIO Mode 4 with IORDY */ + { 20, 50, 100 } /* PIO Mode 5 with IORDY (nonstandard) */ +}; -static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR }; +/* + * Black list. Some drives incorrectly report their maximal PIO mode, + * at least in respect to CMD640. Here we keep info on some known drives. + */ +static struct ide_pio_info { + const char *name; + int pio; +} ide_pio_blacklist [] = { +/* { "Conner Peripherals 1275MB - CFS1275A", 4 }, */ + { "Conner Peripherals 540MB - CFS540A", 3 }, + + { "WDC AC2700", 3 }, + { "WDC AC2540", 3 }, + { "WDC AC2420", 3 }, + { "WDC AC2340", 3 }, + { "WDC AC2250", 0 }, + { "WDC AC2200", 0 }, + { "WDC AC21200", 4 }, + { "WDC AC2120", 0 }, + { "WDC AC2850", 3 }, + { "WDC AC1270", 3 }, + { "WDC AC1170", 1 }, + { "WDC AC1210", 1 }, + { "WDC AC280", 0 }, +/* { "WDC AC21000", 4 }, */ + { "WDC AC31000", 3 }, + { "WDC AC31200", 3 }, +/* { "WDC AC31600", 4 }, */ + + { "Maxtor 7131 AT", 1 }, + { "Maxtor 7171 AT", 1 }, + { "Maxtor 7213 AT", 1 }, + { "Maxtor 7245 AT", 1 }, + { "Maxtor 7345 AT", 1 }, + { "Maxtor 7546 AT", 3 }, + { "Maxtor 7540 AV", 3 }, + + { "SAMSUNG SHD-3121A", 1 }, + { "SAMSUNG SHD-3122A", 1 }, + { "SAMSUNG SHD-3172A", 1 }, + +/* { "ST51080A", 4 }, + * { "ST51270A", 4 }, + * { "ST31220A", 4 }, + * { "ST31640A", 4 }, + * { "ST32140A", 4 }, + * { "ST3780A", 4 }, + */ + { "ST5660A", 3 }, + { "ST3660A", 3 }, + { "ST3630A", 3 }, + { "ST3655A", 3 }, + { "ST3391A", 3 }, + { "ST3390A", 1 }, + { "ST3600A", 1 }, + { "ST3290A", 0 }, + { "ST3144A", 0 }, + { "ST3491A", 1 }, /* reports 3, should be 1 or 2 (depending on */ + /* drive) according to Seagates FIND-ATA program */ + + { "QUANTUM ELS127A", 0 }, + { "QUANTUM ELS170A", 0 }, + { "QUANTUM LPS240A", 0 }, + { "QUANTUM LPS210A", 3 }, + { "QUANTUM LPS270A", 3 }, + { "QUANTUM LPS365A", 3 }, + { "QUANTUM LPS540A", 3 }, + { "QUANTUM LIGHTNING 540A", 3 }, + { "QUANTUM LIGHTNING 730A", 3 }, + + { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */ + { "QUANTUM FIREBALL_640", 3 }, + { "QUANTUM FIREBALL_1080", 3 }, + { "QUANTUM FIREBALL_1280", 3 }, + { NULL, 0 } +}; + +/* default maximum number of failures */ +#define IDE_DEFAULT_MAX_FAILURES 1 static int idebus_parameter; /* holds the "idebus=" parameter */ -static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */ +int system_bus_speed; /* holds what we think is VESA/PCI bus speed */ static int initializing; /* set while initializing built-in drivers */ /* @@ -196,14 +272,109 @@ int noautodma = 0; /* - * This is the anchor of the single linked list of ide device type drivers. + * This is declared extern in ide.h, for access by other IDE modules: */ -struct ide_driver_s *ide_drivers; +ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */ + /* - * This is declared extern in ide.h, for access by other IDE modules: + * This routine searches the ide_pio_blacklist for an entry + * matching the start/whole of the supplied model name. + * + * Returns -1 if no match found. + * Otherwise returns the recommended PIO mode from ide_pio_blacklist[]. */ -ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */ +int ide_scan_pio_blacklist (char *model) +{ + struct ide_pio_info *p; + + for (p = ide_pio_blacklist; p->name != NULL; p++) { + if (strncmp(p->name, model, strlen(p->name)) == 0) + return p->pio; + } + return -1; +} + +/* + * This routine returns the recommended PIO settings for a given drive, + * based on the drive->id information and the ide_pio_blacklist[]. + * This is used by most chipset support modules when "auto-tuning". + */ + +/* + * Drive PIO mode auto selection + */ +byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d) +{ + int pio_mode; + int cycle_time = 0; + int use_iordy = 0; + struct hd_driveid* id = drive->id; + int overridden = 0; + int blacklisted = 0; + + if (mode_wanted != 255) { + pio_mode = mode_wanted; + } else if (!drive->id) { + pio_mode = 0; + } else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) { + overridden = 1; + blacklisted = 1; + use_iordy = (pio_mode > 2); + } else { + pio_mode = id->tPIO; + if (pio_mode > 2) { /* 2 is maximum allowed tPIO value */ + pio_mode = 2; + overridden = 1; + } + if (id->field_valid & 2) { /* drive implements ATA2? */ + if (id->capability & 8) { /* drive supports use_iordy? */ + use_iordy = 1; + cycle_time = id->eide_pio_iordy; + if (id->eide_pio_modes & 7) { + overridden = 0; + if (id->eide_pio_modes & 4) + pio_mode = 5; + else if (id->eide_pio_modes & 2) + pio_mode = 4; + else + pio_mode = 3; + } + } else { + cycle_time = id->eide_pio; + } + } + +#if 0 + if (drive->id->major_rev_num & 0x0004) printk("ATA-2 "); +#endif + + /* + * Conservative "downgrade" for all pre-ATA2 drives + */ + if (pio_mode && pio_mode < 4) { + pio_mode--; + overridden = 1; +#if 0 + use_iordy = (pio_mode > 2); +#endif + if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time) + cycle_time = 0; /* use standard timing */ + } + } + if (pio_mode > max_mode) { + pio_mode = max_mode; + cycle_time = 0; + } + if (d) { + d->pio_mode = pio_mode; + d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time; + d->use_iordy = use_iordy; + d->overridden = overridden; + d->blacklisted = blacklisted; + } + return pio_mode; +} #if (DISK_RECOVERY_TIME > 0) /* @@ -238,6 +409,11 @@ */ static void init_hwif_data (unsigned int index) { + static const byte ide_major[] = { + IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, + IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR + }; + unsigned int unit; hw_regs_t hw; ide_hwif_t *hwif = &ide_hwifs[index]; @@ -256,16 +432,13 @@ if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) hwif->noprobe = 1; /* may be overridden by ide_setup() */ #endif /* CONFIG_BLK_DEV_HD */ - hwif->major = ide_hwif_to_major[index]; - hwif->name[0] = 'i'; - hwif->name[1] = 'd'; - hwif->name[2] = 'e'; - hwif->name[3] = '0' + index; + hwif->major = ide_major[index]; + sprintf(hwif->name, "ide%d", index); hwif->bus_state = BUSSTATE_ON; for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; - drive->media = ide_disk; + drive->type = ATA_DISK; drive->select.all = (unit<<4)|0xa0; drive->hwif = hwif; drive->ctl = 0x08; @@ -273,9 +446,7 @@ drive->bad_wstat = BAD_W_STAT; drive->special.b.recalibrate = 1; drive->special.b.set_geometry = 1; - drive->name[0] = 'h'; - drive->name[1] = 'd'; - drive->name[2] = 'a' + (index * MAX_DRIVES) + unit; + sprintf(drive->name, "hd%c", 'a' + (index * MAX_DRIVES) + unit); drive->max_failures = IDE_DEFAULT_MAX_FAILURES; init_waitqueue_head(&drive->wqueue); } @@ -313,7 +484,6 @@ ide_init_default_hwifs(); idebus_parameter = 0; - system_bus_speed = 0; } /* @@ -347,30 +517,6 @@ return 0; /* no, it is not a flash memory card */ } -/* - * ide_system_bus_speed() returns what we think is the system VESA/PCI - * bus speed (in MHz). This is used for calculating interface PIO timings. - * The default is 40 for known PCI systems, 50 otherwise. - * The "idebus=xx" parameter can be used to override this value. - * The actual value to be used is computed/displayed the first time through. - */ -int ide_system_bus_speed (void) -{ - if (!system_bus_speed) { - if (idebus_parameter) - system_bus_speed = idebus_parameter; /* user supplied value */ -#ifdef CONFIG_PCI - else if (pci_present()) - system_bus_speed = 33; /* safe default value for PCI */ -#endif /* CONFIG_PCI */ - else - system_bus_speed = 50; /* safe default value for VESA and PCI */ - printk("ide: Assuming %dMHz system bus speed for PIO modes%s\n", system_bus_speed, - idebus_parameter ? "" : "; override with idebus=xx"); - } - return system_bus_speed; -} - int __ide_end_request(ide_drive_t *drive, int uptodate, int nr_secs) { struct request *rq; @@ -436,19 +582,18 @@ } /* - * current_capacity() returns the capacity (in sectors) of a drive - * according to its current geometry/LBA settings. + * The capacity of a drive according to its current geometry/LBA settings in + * sectors. */ unsigned long current_capacity (ide_drive_t *drive) { - if (!drive->present) + if (!drive->present || !drive->driver) return 0; - if (drive->driver != NULL) - return DRIVER(drive)->capacity(drive); - return 0; + return ata_ops(drive)->capacity(drive); } extern struct block_device_operations ide_fops[]; + /* * ide_geninit() is called exactly *once* for each interface. */ @@ -462,7 +607,7 @@ if (!drive->present) continue; - if (drive->media!=ide_disk && drive->media!=ide_floppy) + if (drive->type != ATA_DISK && drive->type != ATA_FLOPPY) continue; register_disk(gd,mk_kdev(hwif->major,unit<driver != NULL) - DRIVER(drive)->pre_reset(drive); + ata_ops(drive)->pre_reset(drive); if (!drive->keep_settings) { if (drive->using_dma) { @@ -614,7 +759,7 @@ __cli(); /* local CPU only */ /* For an ATAPI device, first try an ATAPI SRST. */ - if (drive->media != ide_disk && !do_not_try_atapi) { + if (drive->type != ATA_DISK && !do_not_try_atapi) { pre_reset(drive); SELECT_DRIVE(hwif,drive); udelay (20); @@ -783,7 +928,7 @@ err = GET_ERR(); printk("%s: %s: error=0x%02x", drive->name, msg, err); #if FANCY_STATUS_DUMPS - if (drive->media == ide_disk) { + if (drive->type == ATA_DISK) { printk(" { "); if (err & ABRT_ERR) printk("DriveStatusError "); if (err & ICRC_ERR) printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector "); @@ -842,7 +987,7 @@ { int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS; - if (drive->media != ide_disk) + if (drive->type != ATA_DISK) return; while (i > 0) { u32 buffer[16]; @@ -878,7 +1023,7 @@ if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */ rq->errors |= ERROR_RESET; } else { - if (drive->media == ide_disk && (stat & ERR_STAT)) { + if (drive->type == ATA_DISK && (stat & ERR_STAT)) { /* err has different meaning on cdrom and tape */ if (err == ABRT_ERR) { if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY) @@ -898,8 +1043,9 @@ OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); /* force an abort */ if (rq->errors >= ERROR_MAX) { + /* ATA-PATTERN */ if (drive->driver != NULL) - DRIVER(drive)->end_request(drive, 0); + ata_ops(drive)->end_request(drive, 0); else ide_end_request(drive, 0); } else { @@ -971,7 +1117,7 @@ if (tuneproc != NULL) tuneproc(drive, drive->tune_req); } else if (drive->driver != NULL) { - return DRIVER(drive)->special(drive); + return ata_ops(drive)->special(drive); } else if (s->all) { printk("%s: bad special flag: 0x%02x\n", drive->name, s->all); s->all = 0; @@ -1169,8 +1315,8 @@ block = rq->sector; /* Strange disk manager remap */ - if ((rq->flags & REQ_CMD) && - (drive->media == ide_disk || drive->media == ide_floppy)) { + if ((rq->flags & REQ_CMD) && + (drive->type == ATA_DISK || drive->type == ATA_FLOPPY)) { block += drive->sect0; } /* Yecch - this will shift the entire interval, @@ -1185,7 +1331,7 @@ SELECT_DRIVE(hwif, drive); if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { - printk("%s: drive not ready for command\n", drive->name); + printk(KERN_WARNING "%s: drive not ready for command\n", drive->name); return startstop; } if (!drive->special.all) { @@ -1193,16 +1339,16 @@ return execute_drive_cmd(drive, rq); if (drive->driver != NULL) { - return (DRIVER(drive)->do_request(drive, rq, block)); + return ata_ops(drive)->do_request(drive, rq, block); } - printk("%s: media type %d not supported\n", - drive->name, drive->media); + printk(KERN_WARNING "%s: device type %d not supported\n", + drive->name, drive->type); goto kill_rq; } return do_special(drive); kill_rq: if (drive->driver != NULL) - DRIVER(drive)->end_request(drive, 0); + ata_ops(drive)->end_request(drive, 0); else ide_end_request(drive, 0); return ide_stopped; @@ -1566,7 +1712,7 @@ * drive is ready to accept one, in which case we know the drive is not * trying to interrupt us. And ide_set_handler() is always invoked before * completing the issuance of any new drive command, so we will not be - * accidently invoked as a result of any valid command completion interrupt. + * accidentally invoked as a result of any valid command completion interrupt. * */ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) @@ -1626,8 +1772,8 @@ * so in that case we just ignore it and hope it goes away. */ #ifdef CONFIG_BLK_DEV_IDEPCI - if (IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) -#endif /* CONFIG_BLK_DEV_IDEPCI */ + if (hwif->pci_dev && !hwif->pci_dev->vendor) +#endif { /* * Probably not a shared PCI interrupt, @@ -1639,7 +1785,7 @@ /* * Whack the status register, just in case we have a leftover pending IRQ. */ - (void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); + IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); #endif /* CONFIG_BLK_DEV_IDEPCI */ } goto out_lock; @@ -1832,8 +1978,8 @@ if (res) goto leave; - if (DRIVER(drive)->revalidate) - DRIVER(drive)->revalidate(drive); + if (ata_ops(drive)->revalidate) + ata_ops(drive)->revalidate(drive); leave: drive->busy = 0; @@ -1842,7 +1988,11 @@ return res; } -static void revalidate_drives (void) +/* + * Look again for all drives in the system on all interfaces. This is used + * after a new driver cathegory has been loaded as module. + */ +void revalidate_drives (void) { ide_hwif_t *hwif; ide_drive_t *drive; @@ -1855,7 +2005,7 @@ if (drive->revalidate) { drive->revalidate = 0; if (!initializing) - (void) ide_revalidate_disk(mk_kdev(hwif->major, unit<major, unit<next) - d->driver_init(); revalidate_drives(); } @@ -1891,27 +2038,44 @@ return -ENXIO; if (drive->driver == NULL) ide_driver_module(); + + /* Request a particular device type module. + * + * FIXME: The function which should rather requests the drivers is + * ide_driver_module(), since it seems illogical and even a bit + * dangerous to delay this until open time! + */ + #ifdef CONFIG_KMOD if (drive->driver == NULL) { - if (drive->media == ide_disk) - (void) request_module("ide-disk"); - if (drive->media == ide_cdrom) - (void) request_module("ide-cd"); - if (drive->media == ide_tape) - (void) request_module("ide-tape"); - if (drive->media == ide_floppy) - (void) request_module("ide-floppy"); + switch (drive->type) { + case ATA_DISK: + request_module("ide-disk"); + break; + case ATA_ROM: + request_module("ide-cd"); + break; + case ATA_TAPE: + request_module("ide-tape"); + break; + case ATA_FLOPPY: + request_module("ide-floppy"); + break; #if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) - if (drive->media == ide_scsi) - (void) request_module("ide-scsi"); -#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */ + case ATA_SCSI: + request_module("ide-scsi"); + break; +#endif + default: + /* nothing to be done about it */ ; + } } #endif /* CONFIG_KMOD */ while (drive->busy) sleep_on(&drive->wqueue); drive->usage++; if (drive->driver != NULL) - return DRIVER(drive)->open(inode, filp, drive); + return ata_ops(drive)->open(inode, filp, drive); printk ("%s: driver not present\n", drive->name); drive->usage--; return -ENXIO; @@ -1928,27 +2092,11 @@ if ((drive = get_info_ptr(inode->i_rdev)) != NULL) { drive->usage--; if (drive->driver != NULL) - DRIVER(drive)->release(inode, file, drive); + ata_ops(drive)->release(inode, file, drive); } return 0; } -int ide_replace_subdriver (ide_drive_t *drive, const char *driver) -{ - if (!drive->present || drive->busy || drive->usage) - goto abort; - if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) - goto abort; - strncpy(drive->driver_req, driver, 9); - ide_driver_module(); - drive->driver_req[0] = 0; - ide_driver_module(); - if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver)) - return 0; -abort: - return 1; -} - #ifdef CONFIG_PROC_FS ide_proc_entry_t generic_subdriver_entries[] = { { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL }, @@ -2009,13 +2157,14 @@ hwif = &ide_hwifs[index]; if (!hwif->present) goto abort; + put_device(&hwif->device); for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; if (!drive->present) continue; if (drive->busy || drive->usage) goto abort; - if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) + if (drive->driver != NULL && ata_ops(drive)->cleanup(drive)) goto abort; } hwif->present = 0; @@ -2147,10 +2296,8 @@ hwif->udma_four = old_hwif.udma_four; #ifdef CONFIG_BLK_DEV_IDEPCI hwif->pci_dev = old_hwif.pci_dev; - hwif->pci_devid = old_hwif.pci_devid; #endif /* CONFIG_BLK_DEV_IDEPCI */ hwif->straight8 = old_hwif.straight8; - hwif->hwif_data = old_hwif.hwif_data; abort: restore_flags(flags); /* all CPUs */ } @@ -2406,7 +2553,7 @@ static int set_using_dma (ide_drive_t *drive, int arg) { - if (!drive->driver || !DRIVER(drive)->supports_dma) + if (!drive->driver) return -EPERM; if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc) return -EPERM; @@ -2493,66 +2640,6 @@ #endif /* CONFIG_BLK_DEV_IDECS */ } -int system_bus_clock (void) -{ - return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed )); -} - -int ide_reinit_drive (ide_drive_t *drive) -{ - switch (drive->media) { -#ifdef CONFIG_BLK_DEV_IDECD - case ide_cdrom: - { - extern int ide_cdrom_reinit(ide_drive_t *drive); - if (ide_cdrom_reinit(drive)) - return 1; - break; - } -#endif /* CONFIG_BLK_DEV_IDECD */ -#ifdef CONFIG_BLK_DEV_IDEDISK - case ide_disk: - { - extern int idedisk_reinit(ide_drive_t *drive); - if (idedisk_reinit(drive)) - return 1; - break; - } -#endif /* CONFIG_BLK_DEV_IDEDISK */ -#ifdef CONFIG_BLK_DEV_IDEFLOPPY - case ide_floppy: - { - extern int idefloppy_reinit(ide_drive_t *drive); - if (idefloppy_reinit(drive)) - return 1; - break; - } -#endif /* CONFIG_BLK_DEV_IDEFLOPPY */ -#ifdef CONFIG_BLK_DEV_IDETAPE - case ide_tape: - { - extern int idetape_reinit(ide_drive_t *drive); - if (idetape_reinit(drive)) - return 1; - break; - } -#endif /* CONFIG_BLK_DEV_IDETAPE */ -#ifdef CONFIG_BLK_DEV_IDESCSI -/* - * { - * extern int idescsi_reinit(ide_drive_t *drive); - * if (idescsi_reinit(drive)) - * return 1; - * break; - * } - */ -#endif /* CONFIG_BLK_DEV_IDESCSI */ - default: - return 1; - } - return 0; -} - static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -2594,7 +2681,9 @@ { struct hd_geometry *loc = (struct hd_geometry *) arg; unsigned short bios_cyl = drive->bios_cyl; /* truncate */ - if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; + + if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY)) + return -EINVAL; if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT; if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT; if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT; @@ -2606,7 +2695,9 @@ case HDIO_GETGEO_BIG: { struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; - if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; + + if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY)) + return -EINVAL; if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT; if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT; @@ -2619,7 +2710,8 @@ case HDIO_GETGEO_BIG_RAW: { struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; - if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; + if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY)) + return -EINVAL; if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT; if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT; if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT; @@ -2654,15 +2746,15 @@ case HDIO_DRIVE_TASKFILE: if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; - switch(drive->media) { - case ide_disk: + switch(drive->type) { + case ATA_DISK: return ide_taskfile_ioctl(drive, inode, file, cmd, arg); #ifdef CONFIG_PKT_TASK_IOCTL - case ide_cdrom: - case ide_tape: - case ide_floppy: + case ATA_CDROM: + case ATA_TAPE: + case ATA_FLOPPY: return pkt_taskfile_ioctl(drive, inode, file, cmd, arg); -#endif /* CONFIG_PKT_TASK_IOCTL */ +#endif default: return -ENOMSG; } @@ -2695,12 +2787,11 @@ return 0; case HDIO_SET_NICE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (drive->driver == NULL) - return -EPERM; if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1)))) return -EPERM; drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1; - if (drive->dsc_overlap && !DRIVER(drive)->supports_dsc_overlap) { + /* Only CD-ROM's and tapes support DSC overlap. */ + if (drive->dsc_overlap && !(drive->type == ATA_ROM || drive->type == ATA_TAPE)) { drive->dsc_overlap = 0; return -EPERM; } @@ -2776,7 +2867,7 @@ default: if (drive->driver != NULL) - return DRIVER(drive)->ioctl(drive, inode, file, cmd, arg); + return ata_ops(drive)->ioctl(drive, inode, file, cmd, arg); return -EPERM; } } @@ -2788,7 +2879,7 @@ if ((drive = get_info_ptr(i_rdev)) == NULL) return -ENODEV; if (drive->driver != NULL) - return DRIVER(drive)->media_change(drive); + return ata_ops(drive)->media_change(drive); return 0; } @@ -2972,7 +3063,6 @@ const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1); const char max_hwif = '0' + (MAX_HWIFS - 1); - if (strncmp(s,"hd",2) == 0 && s[2] == '=') /* hd= is for hd.c */ return 0; /* driver and not us */ @@ -3050,7 +3140,7 @@ goto done; case -4: /* "cdrom" */ drive->present = 1; - drive->media = ide_cdrom; + drive->type = ATA_ROM; hwif->noprobe = 0; goto done; case -5: /* "serialize" */ @@ -3087,7 +3177,7 @@ goto bad_option; #endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */ case 3: /* cyl,head,sect */ - drive->media = ide_disk; + drive->type = ATA_DISK; drive->cyl = drive->bios_cyl = vals[0]; drive->head = drive->bios_head = vals[1]; drive->sect = drive->bios_sect = vals[2]; @@ -3323,6 +3413,12 @@ pmac_ide_probe(); } #endif /* CONFIG_BLK_DEV_IDE_PMAC */ +#ifdef CONFIG_BLK_DEV_IDE_SWARM + { + extern void swarm_ide_probe(void); + swarm_ide_probe(); + } +#endif /* CONFIG_BLK_DEV_IDE_SWARM */ #ifdef CONFIG_BLK_DEV_IDE_ICSIDE { extern void icside_init(void); @@ -3389,7 +3485,7 @@ } #endif /* __mc68000__ || CONFIG_APUS */ - (void) ideprobe_init(); + ideprobe_init(); #if defined(__mc68000__) || defined(CONFIG_APUS) if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) { @@ -3404,27 +3500,27 @@ #endif /* - * Attempt to match drivers for the available drives + * Initialize all device type driver modules. */ #ifdef CONFIG_BLK_DEV_IDEDISK - (void) idedisk_init(); -#endif /* CONFIG_BLK_DEV_IDEDISK */ + idedisk_init(); +#endif #ifdef CONFIG_BLK_DEV_IDECD - (void) ide_cdrom_init(); -#endif /* CONFIG_BLK_DEV_IDECD */ + ide_cdrom_init(); +#endif #ifdef CONFIG_BLK_DEV_IDETAPE - (void) idetape_init(); -#endif /* CONFIG_BLK_DEV_IDETAPE */ + idetape_init(); +#endif #ifdef CONFIG_BLK_DEV_IDEFLOPPY - (void) idefloppy_init(); -#endif /* CONFIG_BLK_DEV_IDEFLOPPY */ + idefloppy_init(); +#endif #ifdef CONFIG_BLK_DEV_IDESCSI #ifdef CONFIG_SCSI - (void) idescsi_init(); + idescsi_init(); #else #warning ide scsi-emulation selected but no SCSI-subsystem in kernel #endif -#endif /* CONFIG_BLK_DEV_IDESCSI */ +#endif } static int default_cleanup (ide_drive_t *drive) @@ -3500,7 +3596,10 @@ return 0; } -ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n) +/* + * Lookup IDE devices, which requested a particular deriver + */ +ide_drive_t *ide_scan_devices(byte type, const char *name, struct ata_operations *driver, int n) { unsigned int unit, index, i; @@ -3513,14 +3612,17 @@ char *req = drive->driver_req; if (*req && !strstr(name, req)) continue; - if (drive->present && drive->media == media && drive->driver == driver && ++i > n) + if (drive->present && drive->type == type && drive->driver == driver && ++i > n) return drive; } } return NULL; } -int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver) +/* + * This is in fact registering a drive not a driver. + */ +int ide_register_subdriver(ide_drive_t *drive, struct ata_operations *driver) { unsigned long flags; @@ -3564,18 +3666,24 @@ driver->driver_reinit = default_driver_reinit; restore_flags(flags); /* all CPUs */ + /* FIXME: Check what this magic number is supposed to be about? */ if (drive->autotune != 2) { - if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) { + if (HWIF(drive)->dmaproc != NULL) { + /* - * Force DMAing for the beginning of the check. - * Some chipsets appear to do interesting things, - * if not checked and cleared. + * Force DMAing for the beginning of the check. Some + * chipsets appear to do interesting things, if not + * checked and cleared. + * * PARANOIA!!! */ - (void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive)); - (void) (HWIF(drive)->dmaproc(ide_dma_check, drive)); + + HWIF(drive)->dmaproc(ide_dma_off_quietly, drive); + HWIF(drive)->dmaproc(ide_dma_check, drive); } - drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap); + /* Only CD-ROMs and tape drives support DSC overlap. */ + drive->dsc_overlap = (drive->next != drive + && (drive->type == ATA_ROM || drive->type == ATA_TAPE)); drive->nice1 = 1; } drive->revalidate = 1; @@ -3587,13 +3695,13 @@ return 0; } -int ide_unregister_subdriver (ide_drive_t *drive) +int ide_unregister_subdriver(ide_drive_t *drive) { unsigned long flags; save_flags(flags); /* all CPUs */ cli(); /* all CPUs */ - if (drive->usage || drive->busy || drive->driver == NULL || DRIVER(drive)->busy) { + if (drive->usage || drive->busy || drive->driver == NULL || ata_ops(drive)->busy) { restore_flags(flags); /* all CPUs */ return 1; } @@ -3601,7 +3709,7 @@ pnpide_init(0); #endif /* CONFIG_BLK_DEV_ISAPNP */ #ifdef CONFIG_PROC_FS - ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc); + ide_remove_proc_entries(drive->proc, ata_ops(drive)->proc); ide_remove_proc_entries(drive->proc, generic_subdriver_entries); #endif auto_remove_settings(drive); @@ -3610,30 +3718,29 @@ return 0; } -int ide_register_module (struct ide_driver_s *d) -{ - struct ide_driver_s *p = ide_drivers; - while (p) { - if (p == d) - return 1; - p = p->next; - } - d->next = ide_drivers; - ide_drivers = d; - revalidate_drives(); +/* + * Register an ATA driver for a particular device type. + */ + +int register_ata_driver(unsigned int type, struct ata_operations *driver) +{ return 0; } -void ide_unregister_module (struct ide_driver_s *d) -{ - struct ide_driver_s **p; +EXPORT_SYMBOL(register_ata_driver); - for (p = &ide_drivers; (*p) && (*p) != d; p = &((*p)->next)); - if (*p) - *p = (*p)->next; +/* + * Unregister an ATA driver for a particular device type. + */ + +int unregister_ata_driver(unsigned int type, struct ata_operations *driver) +{ + return 0; } +EXPORT_SYMBOL(unregister_ata_driver); + struct block_device_operations ide_fops[] = {{ owner: THIS_MODULE, open: ide_open, @@ -3644,9 +3751,8 @@ }}; EXPORT_SYMBOL(ide_hwifs); -EXPORT_SYMBOL(ide_register_module); -EXPORT_SYMBOL(ide_unregister_module); EXPORT_SYMBOL(ide_spin_wait_hwgroup); +EXPORT_SYMBOL(revalidate_drives); /* * Probe module @@ -3657,10 +3763,8 @@ EXPORT_SYMBOL(drive_is_flashcard); EXPORT_SYMBOL(ide_timer_expiry); EXPORT_SYMBOL(ide_intr); -EXPORT_SYMBOL(ide_fops); EXPORT_SYMBOL(ide_get_queue); EXPORT_SYMBOL(ide_add_generic_settings); -EXPORT_SYMBOL(ide_devfs_handle); EXPORT_SYMBOL(do_ide_request); /* * Driver module @@ -3668,7 +3772,6 @@ EXPORT_SYMBOL(ide_scan_devices); EXPORT_SYMBOL(ide_register_subdriver); EXPORT_SYMBOL(ide_unregister_subdriver); -EXPORT_SYMBOL(ide_replace_subdriver); EXPORT_SYMBOL(ide_set_handler); EXPORT_SYMBOL(ide_dump_status); EXPORT_SYMBOL(ide_error); @@ -3692,9 +3795,6 @@ EXPORT_SYMBOL(ide_add_proc_entries); EXPORT_SYMBOL(ide_remove_proc_entries); EXPORT_SYMBOL(proc_ide_read_geometry); -EXPORT_SYMBOL(create_proc_ide_interfaces); -EXPORT_SYMBOL(recreate_proc_ide_device); -EXPORT_SYMBOL(destroy_proc_ide_device); #endif EXPORT_SYMBOL(ide_add_setting); EXPORT_SYMBOL(ide_remove_setting); @@ -3706,10 +3806,6 @@ EXPORT_SYMBOL(get_info_ptr); EXPORT_SYMBOL(current_capacity); -EXPORT_SYMBOL(system_bus_clock); - -EXPORT_SYMBOL(ide_reinit_drive); - static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x) { ide_hwif_t *hwif; @@ -3739,10 +3835,10 @@ /* set the drive to standby */ printk("%s ", drive->name); if (event != SYS_RESTART) - if (drive->driver != NULL && DRIVER(drive)->standby(drive)) - continue; + if (drive->driver != NULL && ata_ops(drive)->standby(drive)) + continue; - if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) + if (drive->driver != NULL && ata_ops(drive)->cleanup(drive)) continue; } } @@ -3757,24 +3853,42 @@ }; /* - * This is gets invoked once during initialization, to set *everything* up + * This is the global initialization entry point. */ -int __init ide_init (void) +static int __init ata_module_init(void) { - static char banner_printed; int i; - if (!banner_printed) { - printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n"); - ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL); - system_bus_speed = ide_system_bus_speed(); - banner_printed = 1; - } + printk(KERN_INFO "Uniform Multi-Platform E-IDE driver ver.:" VERSION "\n"); + + ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL); + + /* Initialize system bus speed. + * + * This can be changed by a particular chipse initialization module. + * Otherwise we assume 33MHz as a safe value for PCI bus based systems. + * 50MHz will be assumed for abolitions like VESA, since higher values + * result in more conservative timing setups. + * + * The kernel parameter idebus=XX overrides the default settings. + */ + + system_bus_speed = 50; + if (idebus_parameter) + system_bus_speed = idebus_parameter; +#ifdef CONFIG_PCI + else if (pci_present()) + system_bus_speed = 33; +#endif + + printk("ide: system bus speed %dMHz\n", system_bus_speed); init_ide_data (); initializing = 1; + ide_init_builtin_drivers(); + initializing = 0; for (i = 0; i < MAX_HWIFS; ++i) { @@ -3787,8 +3901,7 @@ return 0; } -#ifdef MODULE -char *options = NULL; +static char *options = NULL; MODULE_PARM(options,"s"); MODULE_LICENSE("GPL"); @@ -3799,40 +3912,44 @@ if (line == NULL || !*line) return; while ((line = next) != NULL) { - if ((next = strchr(line,' ')) != NULL) + if ((next = strchr(line,' ')) != NULL) *next++ = 0; if (!ide_setup(line)) printk ("Unknown option '%s'\n", line); } } -int init_module (void) +static int __init init_ata (void) { parse_options(options); - return ide_init(); + return ata_module_init(); } -void cleanup_module (void) +static void __exit cleanup_ata (void) { int index; unregister_reboot_notifier(&ide_notifier); for (index = 0; index < MAX_HWIFS; ++index) { ide_unregister(index); -#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) +# if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) if (ide_hwifs[index].dma_base) (void) ide_release_dma(&ide_hwifs[index]); -#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ +# endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ } -#ifdef CONFIG_PROC_FS +# ifdef CONFIG_PROC_FS proc_ide_destroy(); -#endif +# endif devfs_unregister (ide_devfs_handle); } -#else /* !MODULE */ +module_init(init_ata); +module_exit(cleanup_ata); + +#ifndef MODULE +/* command line option parser */ __setup("", ide_setup); -#endif /* MODULE */ +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ide_modes.h linux-2.5/drivers/ide/ide_modes.h --- linux-2.5.5/drivers/ide/ide_modes.h Thu Feb 21 17:46:02 2002 +++ linux-2.5/drivers/ide/ide_modes.h Tue Mar 5 13:42:21 2002 @@ -11,9 +11,6 @@ /* * Shared data/functions for determining best PIO mode for an IDE drive. - * Most of this stuff originally lived in cmd640.c, and changes to the - * ide_pio_blacklist[] table should be made with EXTREME CAUTION to avoid - * breaking the fragile cmd640.c support. */ #ifdef CONFIG_BLK_DEV_IDE_MODES @@ -37,200 +34,9 @@ byte blacklisted; unsigned int cycle_time; } ide_pio_data_t; - -#ifndef _IDE_C -int ide_scan_pio_blacklist (char *model); -byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d); +extern int ide_scan_pio_blacklist (char *model); +extern byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d); extern const ide_pio_timings_t ide_pio_timings[6]; - -#else /* _IDE_C */ - -const ide_pio_timings_t ide_pio_timings[6] = { - { 70, 165, 600 }, /* PIO Mode 0 */ - { 50, 125, 383 }, /* PIO Mode 1 */ - { 30, 100, 240 }, /* PIO Mode 2 */ - { 30, 80, 180 }, /* PIO Mode 3 with IORDY */ - { 25, 70, 120 }, /* PIO Mode 4 with IORDY */ - { 20, 50, 100 } /* PIO Mode 5 with IORDY (nonstandard) */ -}; - -/* - * Black list. Some drives incorrectly report their maximal PIO mode, - * at least in respect to CMD640. Here we keep info on some known drives. - */ -static struct ide_pio_info { - const char *name; - int pio; -} ide_pio_blacklist [] = { -/* { "Conner Peripherals 1275MB - CFS1275A", 4 }, */ - { "Conner Peripherals 540MB - CFS540A", 3 }, - - { "WDC AC2700", 3 }, - { "WDC AC2540", 3 }, - { "WDC AC2420", 3 }, - { "WDC AC2340", 3 }, - { "WDC AC2250", 0 }, - { "WDC AC2200", 0 }, - { "WDC AC21200", 4 }, - { "WDC AC2120", 0 }, - { "WDC AC2850", 3 }, - { "WDC AC1270", 3 }, - { "WDC AC1170", 1 }, - { "WDC AC1210", 1 }, - { "WDC AC280", 0 }, -/* { "WDC AC21000", 4 }, */ - { "WDC AC31000", 3 }, - { "WDC AC31200", 3 }, -/* { "WDC AC31600", 4 }, */ - - { "Maxtor 7131 AT", 1 }, - { "Maxtor 7171 AT", 1 }, - { "Maxtor 7213 AT", 1 }, - { "Maxtor 7245 AT", 1 }, - { "Maxtor 7345 AT", 1 }, - { "Maxtor 7546 AT", 3 }, - { "Maxtor 7540 AV", 3 }, - - { "SAMSUNG SHD-3121A", 1 }, - { "SAMSUNG SHD-3122A", 1 }, - { "SAMSUNG SHD-3172A", 1 }, - -/* { "ST51080A", 4 }, - * { "ST51270A", 4 }, - * { "ST31220A", 4 }, - * { "ST31640A", 4 }, - * { "ST32140A", 4 }, - * { "ST3780A", 4 }, - */ - { "ST5660A", 3 }, - { "ST3660A", 3 }, - { "ST3630A", 3 }, - { "ST3655A", 3 }, - { "ST3391A", 3 }, - { "ST3390A", 1 }, - { "ST3600A", 1 }, - { "ST3290A", 0 }, - { "ST3144A", 0 }, - { "ST3491A", 1 }, /* reports 3, should be 1 or 2 (depending on */ - /* drive) according to Seagates FIND-ATA program */ - - { "QUANTUM ELS127A", 0 }, - { "QUANTUM ELS170A", 0 }, - { "QUANTUM LPS240A", 0 }, - { "QUANTUM LPS210A", 3 }, - { "QUANTUM LPS270A", 3 }, - { "QUANTUM LPS365A", 3 }, - { "QUANTUM LPS540A", 3 }, - { "QUANTUM LIGHTNING 540A", 3 }, - { "QUANTUM LIGHTNING 730A", 3 }, - - { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */ - { "QUANTUM FIREBALL_640", 3 }, - { "QUANTUM FIREBALL_1080", 3 }, - { "QUANTUM FIREBALL_1280", 3 }, - { NULL, 0 } -}; - -/* - * This routine searches the ide_pio_blacklist for an entry - * matching the start/whole of the supplied model name. - * - * Returns -1 if no match found. - * Otherwise returns the recommended PIO mode from ide_pio_blacklist[]. - */ -int ide_scan_pio_blacklist (char *model) -{ - struct ide_pio_info *p; - - for (p = ide_pio_blacklist; p->name != NULL; p++) { - if (strncmp(p->name, model, strlen(p->name)) == 0) - return p->pio; - } - return -1; -} - -/* - * This routine returns the recommended PIO settings for a given drive, - * based on the drive->id information and the ide_pio_blacklist[]. - * This is used by most chipset support modules when "auto-tuning". - */ - -/* - * Drive PIO mode auto selection - */ -byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d) -{ - int pio_mode; - int cycle_time = 0; - int use_iordy = 0; - struct hd_driveid* id = drive->id; - int overridden = 0; - int blacklisted = 0; - - if (mode_wanted != 255) { - pio_mode = mode_wanted; - } else if (!drive->id) { - pio_mode = 0; - } else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) { - overridden = 1; - blacklisted = 1; - use_iordy = (pio_mode > 2); - } else { - pio_mode = id->tPIO; - if (pio_mode > 2) { /* 2 is maximum allowed tPIO value */ - pio_mode = 2; - overridden = 1; - } - if (id->field_valid & 2) { /* drive implements ATA2? */ - if (id->capability & 8) { /* drive supports use_iordy? */ - use_iordy = 1; - cycle_time = id->eide_pio_iordy; - if (id->eide_pio_modes & 7) { - overridden = 0; - if (id->eide_pio_modes & 4) - pio_mode = 5; - else if (id->eide_pio_modes & 2) - pio_mode = 4; - else - pio_mode = 3; - } - } else { - cycle_time = id->eide_pio; - } - } - -#if 0 - if (drive->id->major_rev_num & 0x0004) printk("ATA-2 "); #endif - - /* - * Conservative "downgrade" for all pre-ATA2 drives - */ - if (pio_mode && pio_mode < 4) { - pio_mode--; - overridden = 1; -#if 0 - use_iordy = (pio_mode > 2); #endif - if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time) - cycle_time = 0; /* use standard timing */ - } - } - if (pio_mode > max_mode) { - pio_mode = max_mode; - cycle_time = 0; - } - if (d) { - d->pio_mode = pio_mode; - d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time; - d->use_iordy = use_iordy; - d->overridden = overridden; - d->blacklisted = blacklisted; - } - return pio_mode; -} - -#endif /* _IDE_C */ -#endif /* CONFIG_BLK_DEV_IDE_MODES */ -#endif /* _IDE_MODES_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/it8172.c linux-2.5/drivers/ide/it8172.c --- linux-2.5.5/drivers/ide/it8172.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/ide/it8172.c Sun Mar 3 17:54:35 2002 @@ -50,48 +50,53 @@ #if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING) static byte it8172_dma_2_pio (byte xfer_rate); static int it8172_tune_chipset (ide_drive_t *drive, byte speed); -static int it8172_config_drive_for_dma (ide_drive_t *drive); +static int it8172_config_chipset_for_dma (ide_drive_t *drive); static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive); #endif -unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name); void __init ide_init_it8172 (ide_hwif_t *hwif); static void it8172_tune_drive (ide_drive_t *drive, byte pio) { unsigned long flags; - u16 master_data; - u32 slave_data; + u16 drive_enables; + u32 drive_timing; int is_slave = (&HWIF(drive)->drives[1] == drive); - int master_port = 0x40; - int slave_port = 0x44; - pio = ide_get_best_pio_mode(drive, pio, 5, NULL); - pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data); - pci_read_config_dword(HWIF(drive)->pci_dev, slave_port, &slave_data); + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &drive_enables); + pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &drive_timing); /* * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44 * are being left at the default values of 8 PCI clocks (242 nsec * for a 33 MHz clock). These can be safely shortened at higher - * PIO modes. + * PIO modes. The DIOR/DIOW pulse width and recovery times only + * apply to PIO modes, not to the DMA modes. */ + /* + * Enable port 0x44. The IT8172G spec is confused; it calls + * this register the "Slave IDE Timing Register", but in fact, + * it controls timing for both master and slave drives. + */ + drive_enables |= 0x4000; + if (is_slave) { - master_data |= 0x4000; + drive_enables &= 0xc006; if (pio > 1) - /* enable PPE and IE */ - master_data |= 0x0060; + /* enable prefetch and IORDY sample-point */ + drive_enables |= 0x0060; } else { - master_data &= 0xc060; + drive_enables &= 0xc060; if (pio > 1) - /* enable PPE and IE */ - master_data |= 0x0006; + /* enable prefetch and IORDY sample-point */ + drive_enables |= 0x0006; } save_flags(flags); cli(); - pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data); + pci_write_config_word(HWIF(drive)->pci_dev, 0x40, drive_enables); restore_flags(flags); } @@ -160,6 +165,7 @@ case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; case XFER_MW_DMA_2: case XFER_MW_DMA_1: + case XFER_MW_DMA_0: case XFER_SW_DMA_2: break; default: return -1; } @@ -182,7 +188,7 @@ return err; } -static int it8172_config_drive_for_dma (ide_drive_t *drive) +static int it8172_config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; byte speed; @@ -201,10 +207,12 @@ speed = XFER_MW_DMA_2; } else if (id->dma_mword & 0x0002) { speed = XFER_MW_DMA_1; + } else if (id->dma_mword & 0x0001) { + speed = XFER_MW_DMA_0; } else if (id->dma_1word & 0x0004) { speed = XFER_SW_DMA_2; } else { - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 4, NULL); } (void) it8172_tune_chipset(drive, speed); @@ -220,7 +228,7 @@ { switch (func) { case ide_dma_check: - return ide_dmaproc((ide_dma_action_t)it8172_config_drive_for_dma(drive), + return ide_dmaproc((ide_dma_action_t)it8172_config_chipset_for_dma(drive), drive); default : break; @@ -232,7 +240,7 @@ #endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_IT8172_TUNING) */ -unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_it8172 (struct pci_dev *dev) { unsigned char progif; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/ns87415.c linux-2.5/drivers/ide/ns87415.c --- linux-2.5.5/drivers/ide/ns87415.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/ide/ns87415.c Fri Mar 1 15:07:38 2002 @@ -103,7 +103,7 @@ ns87415_prepare_drive(drive, 0); /* DMA failed: select PIO xfer */ return 1; case ide_dma_check: - if (drive->media != ide_disk) + if (drive->type != ATA_DISK) return ide_dmaproc(ide_dma_off_quietly, drive); /* Fallthrough... */ default: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/opti621.c linux-2.5/drivers/ide/opti621.c --- linux-2.5.5/drivers/ide/opti621.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/ide/opti621.c Fri Mar 1 15:07:38 2002 @@ -164,7 +164,7 @@ } } -int cmpt_clk(int time, int bus_speed) +static int cmpt_clk(int time, int bus_speed) /* Returns (rounded up) time in clocks for time in ns, * with bus_speed in MHz. * Example: bus_speed = 40 MHz, time = 80 ns @@ -216,14 +216,13 @@ { if (pio != PIO_NOT_EXIST) { int adr_setup, data_pls; - int bus_speed = system_bus_clock(); adr_setup = ide_pio_timings[pio].setup_time; data_pls = ide_pio_timings[pio].active_time; - clks->address_time = cmpt_clk(adr_setup, bus_speed); - clks->data_time = cmpt_clk(data_pls, bus_speed); + clks->address_time = cmpt_clk(adr_setup, system_bus_speed); + clks->data_time = cmpt_clk(data_pls, system_bus_speed); clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time - - adr_setup-data_pls, bus_speed); + - adr_setup-data_pls, system_bus_speed); if (clks->address_time<1) clks->address_time = 1; if (clks->address_time>4) clks->address_time = 4; if (clks->data_time<1) clks->data_time = 1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/pdc202xx.c linux-2.5/drivers/ide/pdc202xx.c --- linux-2.5.5/drivers/ide/pdc202xx.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/ide/pdc202xx.c Fri Mar 1 15:07:38 2002 @@ -63,7 +63,6 @@ static int pdc202xx_get_info(char *, char **, off_t, int); extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; char *pdc202xx_pio_verbose (u32 drive_pci) @@ -412,7 +411,8 @@ default: return -1; } - if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) return -1; + if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0)) + return -1; pci_read_config_dword(dev, drive_pci, &drive_conf); pci_read_config_byte(dev, (drive_pci), &AP); @@ -820,7 +820,8 @@ } if (jumpbit) { - if (drive->media != ide_disk) return ide_dma_off_quietly; + if (drive->type != ATA_DISK) + return ide_dma_off_quietly; if (id->capability & 4) { /* IORDY_EN & PREFETCH_EN */ OUT_BYTE((iordy + adj), indexreg); OUT_BYTE((IN_BYTE(datareg)|0x03), datareg); @@ -869,13 +870,14 @@ chipset_is_set: - if (drive->media != ide_disk) return ide_dma_off_quietly; + if (drive->type != ATA_DISK) + return ide_dma_off_quietly; pci_read_config_byte(dev, (drive_pci), &AP); if (id->capability & 4) /* IORDY_EN */ pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN); pci_read_config_byte(dev, (drive_pci), &AP); - if (drive->media == ide_disk) /* PREFETCH_EN */ + if (drive->type == ATA_DISK) /* PREFETCH_EN */ pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN); jumpbit_is_set: @@ -1102,7 +1104,7 @@ return 0; } -unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_pdc202xx(struct pci_dev *dev) { unsigned long high_16 = pci_resource_start(dev, 4); byte udma_speed_flag = IN_BYTE(high_16 + 0x001f); @@ -1112,7 +1114,7 @@ if (dev->resource[PCI_ROM_RESOURCE].start) { pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); - printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); + printk("%s: ROM enabled at 0x%08lx\n", dev->name, dev->resource[PCI_ROM_RESOURCE].start); } switch (dev->device) { @@ -1151,7 +1153,7 @@ pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2); /* 0xbc */ if (irq != irq2) { pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */ - printk("%s: pci-config space interrupt mirror fixed.\n", name); + printk("%s: pci-config space interrupt mirror fixed.\n", dev->name); } } break; @@ -1163,14 +1165,14 @@ printk("%s: (U)DMA Burst Bit %sABLED " \ "Primary %s Mode " \ "Secondary %s Mode.\n", - name, + dev->name, (udma_speed_flag & 1) ? "EN" : "DIS", (primary_mode & 1) ? "MASTER" : "PCI", (secondary_mode & 1) ? "MASTER" : "PCI" ); #ifdef CONFIG_PDC202XX_BURST if (!(udma_speed_flag & 1)) { - printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1)); + printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", dev->name, udma_speed_flag, (udma_speed_flag|1)); OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f); printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA"); } @@ -1179,14 +1181,14 @@ #ifdef CONFIG_PDC202XX_MASTER if (!(primary_mode & 1)) { printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ", - name, primary_mode, (primary_mode|1)); + dev->name, primary_mode, (primary_mode|1)); OUT_BYTE(primary_mode|1, high_16 + 0x001a); printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI"); } if (!(secondary_mode & 1)) { printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ", - name, secondary_mode, (secondary_mode|1)); + dev->name, secondary_mode, (secondary_mode|1)); OUT_BYTE(secondary_mode|1, high_16 + 0x001b); printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI"); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/pdc4030.c linux-2.5/drivers/ide/pdc4030.c --- linux-2.5.5/drivers/ide/pdc4030.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/ide/pdc4030.c Fri Mar 1 15:07:38 2002 @@ -1,7 +1,7 @@ /* -*- linux-c -*- - * linux/drivers/ide/pdc4030.c Version 0.90 May 27, 1999 + * linux/drivers/ide/pdc4030.c Version 0.92 Jan 15, 2002 * - * Copyright (C) 1995-1999 Linus Torvalds & authors (see below) + * Copyright (C) 1995-2002 Linus Torvalds & authors (see below) */ /* @@ -37,6 +37,8 @@ * Autodetection code added. * * Version 0.90 Transition to BETA code. No lost/unexpected interrupts + * Version 0.91 Bring in line with new bio code in 2.5.1 + * Version 0.92 Update for IDE driver taskfile changes */ /* @@ -72,8 +74,8 @@ * effects. */ -#define DEBUG_READ -#define DEBUG_WRITE +#undef DEBUG_READ +#undef DEBUG_WRITE #include #include @@ -91,6 +93,10 @@ #include "pdc4030.h" +#if SUPPORT_VLB_SYNC != 1 +#error This driver will not work unless SUPPORT_VLB_SYNC is 1 +#endif + /* * promise_selectproc() is invoked by ide.c * in preparation for access to the specified drive. @@ -230,12 +236,12 @@ hwif->selectproc = hwif2->selectproc = &promise_selectproc; hwif->serialized = hwif2->serialized = 1; -/* Shift the remaining interfaces down by one */ +/* Shift the remaining interfaces up by one */ for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) { ide_hwif_t *h = &ide_hwifs[i]; #ifdef DEBUG - printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i); + printk(KERN_DEBUG "pdc4030: Shifting i/f %d values to i/f %d\n",i-1,i); #endif ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL); memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports)); @@ -332,14 +338,14 @@ if (nsect > sectors_avail) nsect = sectors_avail; sectors_avail -= nsect; - to = ide_map_buffer(rq, &flags); + to = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq); ata_input_data(drive, to, nsect * SECTOR_WORDS); #ifdef DEBUG_READ printk(KERN_DEBUG "%s: promise_read: sectors(%ld-%ld), " "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector, rq->sector+nsect-1, (unsigned long) to, rq->nr_sectors-nsect); #endif - ide_unmap_buffer(to, &flags); + bio_kunmap_irq(to, &flags); rq->sector += nsect; rq->errors = 0; rq->nr_sectors -= nsect; @@ -437,7 +443,7 @@ nsect = mcount; mcount -= nsect; - buffer = ide_map_buffer(rq, &flags); + buffer = bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq); rq->sector += nsect; rq->nr_sectors -= nsect; rq->current_nr_sectors -= nsect; @@ -461,7 +467,7 @@ * re-entering us on the last transfer. */ taskfile_output_data(drive, buffer, nsect<<7); - ide_unmap_buffer(buffer, &flags); + bio_kunmap_irq(buffer, &flags); } while (mcount); return 0; @@ -559,6 +565,13 @@ OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ SELECT_MASK(HWIF(drive), drive, 0); +/* Check that it's a regular command. If not, bomb out early. */ + if (!(rq->flags & REQ_CMD)) { + blk_dump_rq_flags(rq, "pdc4030 bad flags"); + ide_end_request(drive, 0); + return ide_stopped; + } + OUT_BYTE(taskfile->feature, IDE_FEATURE_REG); OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG); /* refers to number of sectors to transfer */ @@ -569,16 +582,8 @@ OUT_BYTE(taskfile->device_head, IDE_SELECT_REG); OUT_BYTE(taskfile->command, IDE_COMMAND_REG); -/* Check that it's a regular command. If not, bomb out early. */ - if (!(rq->flags & REQ_CMD)) { - blk_dump_rq_flags(rq, "pdc4030 bad flags"); - ide_end_request(drive, 0); - return ide_stopped; - } - switch (rq_data_dir(rq)) { case READ: - OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG); /* * The card's behaviour is odd at this point. If the data is * available, DRQ will be true, and no interrupt will be @@ -611,9 +616,7 @@ drive->name); return ide_stopped; - case WRITE: { - ide_startstop_t startstop; - OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG); + case WRITE: /* * Strategy on write is: * look for the DRQ that should have been immediately asserted @@ -630,7 +633,6 @@ __cli(); /* local CPU only */ HWGROUP(drive)->wrq = *rq; /* scratchpad */ return promise_write(drive); - } default: printk(KERN_ERR "pdc4030: command not READ or WRITE! Huh?\n"); @@ -645,6 +647,13 @@ ide_task_t args; memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); + + /* The four drives on the two logical (one physical) interfaces + are distinguished by writing the drive number (0-3) to the + Feature register. + FIXME: Is promise_selectproc now redundant?? + */ + taskfile.feature = (HWIF(drive)->channel << 1) + drive->select.b.unit; taskfile.sector_count = rq->nr_sectors; taskfile.sector_number = block; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/pdcadma.c linux-2.5/drivers/ide/pdcadma.c --- linux-2.5.5/drivers/ide/pdcadma.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/ide/pdcadma.c Fri Mar 1 15:07:38 2002 @@ -34,7 +34,6 @@ static int pdcadma_get_info(char *, char **, off_t, int); extern int (*pdcadma_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; static int pdcadma_get_info (char *buffer, char **addr, off_t offset, int count) @@ -71,7 +70,7 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ -unsigned int __init pci_init_pdcadma (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_pdcadma(struct pci_dev *dev) { #if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) if (!pdcadma_proc) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/pdcraid.c linux-2.5/drivers/ide/pdcraid.c --- linux-2.5.5/drivers/ide/pdcraid.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/ide/pdcraid.c Mon Jan 7 20:47:23 2002 @@ -102,17 +102,17 @@ unsigned int minor; unsigned long sectors; - if (!inode || !inode->i_rdev) + if (!inode || kdev_none(inode->i_rdev)) return -EINVAL; - minor = MINOR(inode->i_rdev)>>SHIFT; + minor = minor(inode->i_rdev)>>SHIFT; switch (cmd) { case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; - sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects; - if (MINOR(inode->i_rdev)&15) + sectors = ataraid_gendisk.part[minor(inode->i_rdev)].nr_sects; + if (minor(inode->i_rdev)&15) return put_user(sectors, (unsigned long *) arg); return put_user(raid[minor].sectors , (unsigned long *) arg); break; @@ -127,7 +127,7 @@ if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT; if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT; if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect, + if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -139,7 +139,7 @@ if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT; if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT; if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT; - if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect, + if (put_user((unsigned)ataraid_gendisk.part[minor(inode->i_rdev)].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; } @@ -463,7 +463,7 @@ major = devlist[devindex].major; minor = devlist[devindex].minor; - bdev = bdget(MKDEV(major,minor)); + bdev = bdget(mk_kdev(major,minor)); if (!bdev) return; @@ -491,7 +491,7 @@ (prom.raid.disk[i].device == prom.raid.device) ) { raid[device].disk[i].bdev = bdev; - raid[device].disk[i].device = MKDEV(major,minor); + raid[device].disk[i].device = mk_kdev(major,minor); raid[device].disk[i].sectors = prom.raid.disk_secs; raid[device].stride = (1<pci_dev, slave_port, &slave_data); slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0); - slave_data = slave_data | ((timings[pio][0] << 2) | (timings[pio][1] - << (HWIF(drive)->index ? 4 : 0))); + slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) + << (HWIF(drive)->index ? 4 : 0)); } else { master_data = master_data & 0xccf8; if (pio > 1) @@ -451,7 +450,7 @@ } #endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */ -unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_piix(struct pci_dev *dev) { #if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) if (!piix_proc) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/qd65xx.c linux-2.5/drivers/ide/qd65xx.c --- linux-2.5.5/drivers/ide/qd65xx.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/ide/qd65xx.c Fri Mar 1 15:07:38 2002 @@ -139,12 +139,12 @@ { byte active_cycle,recovery_cycle; - if (ide_system_bus_speed()<=33) { - active_cycle = 9 - IDE_IN(active_time * ide_system_bus_speed() / 1000 + 1, 2, 9); - recovery_cycle = 15 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 0, 15); + if (system_bus_speed <= 33) { + active_cycle = 9 - IDE_IN(active_time * system_bus_speed / 1000 + 1, 2, 9); + recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_speed / 1000 + 1, 0, 15); } else { - active_cycle = 8 - IDE_IN(active_time * ide_system_bus_speed() / 1000 + 1, 1, 8); - recovery_cycle = 18 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 3, 18); + active_cycle = 8 - IDE_IN(active_time * system_bus_speed / 1000 + 1, 1, 8); + recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_speed / 1000 + 1, 3, 18); } return((recovery_cycle<<4) | 0x08 | active_cycle); @@ -158,8 +158,8 @@ static byte qd6580_compute_timing (int active_time, int recovery_time) { - byte active_cycle = 17-IDE_IN(active_time * ide_system_bus_speed() / 1000 + 1, 2, 17); - byte recovery_cycle = 15-IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 2, 15); + byte active_cycle = 17-IDE_IN(active_time * system_bus_speed / 1000 + 1, 2, 17); + byte recovery_cycle = 15-IDE_IN(recovery_time * system_bus_speed / 1000 + 1, 2, 15); return((recovery_cycle<<4) | active_cycle); } @@ -293,7 +293,7 @@ printk(KERN_INFO "%s: PIO mode%d\n",drive->name,pio); } - if (!HWIF(drive)->channel && drive->media != ide_disk) { + if (!HWIF(drive)->channel && drive->type != ATA_DISK) { qd_write_reg(0x5f,QD_CONTROL_PORT); printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name,HWIF(drive)->name); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/serverworks.c linux-2.5/drivers/ide/serverworks.c --- linux-2.5.5/drivers/ide/serverworks.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/ide/serverworks.c Fri Mar 1 15:07:38 2002 @@ -105,7 +105,6 @@ static int svwks_get_info(char *, char **, off_t, int); extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static int svwks_get_info (char *buffer, char **addr, off_t offset, int count) { @@ -547,7 +546,7 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ -unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_svwks(struct pci_dev *dev) { unsigned int reg; byte btr; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/sis5513.c linux-2.5/drivers/ide/sis5513.c --- linux-2.5.5/drivers/ide/sis5513.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/ide/sis5513.c Fri Mar 1 15:07:38 2002 @@ -238,7 +238,7 @@ byte rw_prefetch = (0x11 << drive->dn); pci_read_config_byte(dev, 0x4b, ®4bh); - if (drive->media != ide_disk) + if (drive->type != ATA_DISK) return; if ((reg4bh & rw_prefetch) != rw_prefetch) @@ -567,7 +567,7 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ -unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_sis5513(struct pci_dev *dev) { struct pci_dev *host; int i = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/sl82c105.c linux-2.5/drivers/ide/sl82c105.c --- linux-2.5.5/drivers/ide/sl82c105.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/ide/sl82c105.c Fri Mar 1 15:07:38 2002 @@ -8,8 +8,6 @@ * Drive tuning added from Rebel.com's kernel sources * -- Russell King (15/11/98) linux@arm.linux.org.uk */ - -#include #include #include #include @@ -225,7 +223,7 @@ /* * Enable the PCI device */ -unsigned int __init pci_init_sl82c105(struct pci_dev *dev, const char *msg) +unsigned int __init pci_init_sl82c105(struct pci_dev *dev) { unsigned char ctrl_stat; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/slc90e66.c linux-2.5/drivers/ide/slc90e66.c --- linux-2.5.5/drivers/ide/slc90e66.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/ide/slc90e66.c Fri Mar 1 15:07:38 2002 @@ -60,7 +60,6 @@ static int slc90e66_get_info(char *, char **, off_t, int); extern int (*slc90e66_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count) @@ -347,7 +346,7 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ -unsigned int __init pci_init_slc90e66 (struct pci_dev *dev, const char *name) +unsigned int __init pci_init_slc90e66(struct pci_dev *dev) { #if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) if (!slc90e66_proc) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/trm290.c linux-2.5/drivers/ide/trm290.c --- linux-2.5.5/drivers/ide/trm290.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/ide/trm290.c Fri Mar 1 15:07:38 2002 @@ -192,7 +192,7 @@ outl(hwif->dmatable_dma|reading|writing, hwif->dma_base); drive->waiting_for_dma = 1; outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */ - if (drive->media != ide_disk) + if (drive->type != ATA_DISK) return 0; ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ide/via82cxxx.c linux-2.5/drivers/ide/via82cxxx.c --- linux-2.5.5/drivers/ide/via82cxxx.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/ide/via82cxxx.c Fri Mar 1 15:07:38 2002 @@ -393,7 +393,7 @@ * and initialize its drive independent registers. */ -unsigned int __init pci_init_via82cxxx(struct pci_dev *dev, const char *name) +unsigned int __init pci_init_via82cxxx(struct pci_dev *dev) { struct pci_dev *isa = NULL; unsigned char t, v; @@ -484,7 +484,7 @@ * Determine system bus clock. */ - via_clock = system_bus_clock() * 1000; + via_clock = system_bus_speed * 1000; switch (via_clock) { case 33000: via_clock = 33333; break; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ieee1394/dv1394.c linux-2.5/drivers/ieee1394/dv1394.c --- linux-2.5.5/drivers/ieee1394/dv1394.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/ieee1394/dv1394.c Tue Feb 26 21:24:48 2002 @@ -100,7 +100,6 @@ #include #include #include -#include #include #include #include @@ -185,78 +184,19 @@ /* Memory management functions */ /*******************************/ -#define MDEBUG(x) do { } while(0) /* Debug memory management */ - -/* [DaveM] I've recoded most of this so that: - * 1) It's easier to tell what is happening - * 2) It's more portable, especially for translating things - * out of vmalloc mapped areas in the kernel. - * 3) Less unnecessary translations happen. - * - * The code used to assume that the kernel vmalloc mappings - * existed in the page tables of every process, this is simply - * not guarenteed. We now use pgd_offset_k which is the - * defined way to get at the kernel page tables. - */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#define page_address(x) (x) -#endif - -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline struct page *uvirt_to_page(pgd_t *pgd, unsigned long adr) -{ - pmd_t *pmd; - pte_t *ptep, pte; - struct page *ret = NULL; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - preempt_disable(); - ptep = pte_offset_map(pmd, adr); - pte = *ptep; - pte_unmap(pte); - preempt_enable(); - if(pte_present(pte)) - ret = pte_page(pte); - } - } - return ret; -} - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved, and for - * handling page faults on the rvmalloc()ed buffer - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) -{ - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = (unsigned long) page_address(uvirt_to_page(pgd_offset_k(va), va)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); - return ret; -} - static void * rvmalloc(unsigned long size) { void * mem; - unsigned long adr, page; - + unsigned long adr; + + size=PAGE_ALIGN(size); mem=vmalloc_32(size); if (mem) { memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -266,13 +206,12 @@ static void rvfree(void * mem, unsigned long size) { - unsigned long adr, page; - + unsigned long adr; + if (mem) { adr=(unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -1166,9 +1105,9 @@ /* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */ for(i = 0; i < video->user_dma.n_pages; i++) { - unsigned long va = VMALLOC_VMADDR( (unsigned long) video->user_buf + i * PAGE_SIZE ); + unsigned long va = (unsigned long) video->user_buf + i * PAGE_SIZE; - video->user_dma.sglist[i].page = uvirt_to_page(pgd_offset_k(va), va); + video->user_dma.sglist[i].page = vmalloc_to_page((void *)va); video->user_dma.sglist[i].length = PAGE_SIZE; } @@ -1492,7 +1431,7 @@ static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long address, int write_access) { unsigned long offset; - unsigned long page, kernel_virt_addr; + unsigned long kernel_virt_addr; struct page *ret = NOPAGE_SIGBUS; struct video_card *video = (struct video_card*) area->vm_private_data; @@ -1510,10 +1449,7 @@ offset = address - area->vm_start; kernel_virt_addr = (unsigned long) video->user_buf + offset; - - page = kvirt_to_pa(kernel_virt_addr); - - ret = virt_to_page(__va(page)); + ret = vmalloc_to_page((void *)kernel_virt_addr); get_page(ret); out: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ieee1394/ieee1394_syms.c linux-2.5/drivers/ieee1394/ieee1394_syms.c --- linux-2.5.5/drivers/ieee1394/ieee1394_syms.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/ieee1394/ieee1394_syms.c Sun Jan 6 19:16:28 2002 @@ -0,0 +1,88 @@ +/* + * IEEE 1394 for Linux + * + * Exported symbols for module usage. + * + * Copyright (C) 1999 Andreas E. Bombe + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include +#include +#include +#include + +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "ieee1394_transactions.h" +#include "ieee1394_hotplug.h" +#include "highlevel.h" +#include "nodemgr.h" + +EXPORT_SYMBOL(hpsb_register_lowlevel); +EXPORT_SYMBOL(hpsb_unregister_lowlevel); +EXPORT_SYMBOL(hpsb_get_host); +EXPORT_SYMBOL(hpsb_inc_host_usage); +EXPORT_SYMBOL(hpsb_dec_host_usage); + +EXPORT_SYMBOL(alloc_hpsb_packet); +EXPORT_SYMBOL(free_hpsb_packet); +EXPORT_SYMBOL(hpsb_send_packet); +EXPORT_SYMBOL(hpsb_reset_bus); +EXPORT_SYMBOL(hpsb_bus_reset); +EXPORT_SYMBOL(hpsb_selfid_received); +EXPORT_SYMBOL(hpsb_selfid_complete); +EXPORT_SYMBOL(hpsb_packet_sent); +EXPORT_SYMBOL(hpsb_packet_received); + +EXPORT_SYMBOL(get_tlabel); +EXPORT_SYMBOL(free_tlabel); +EXPORT_SYMBOL(fill_async_readquad); +EXPORT_SYMBOL(fill_async_readquad_resp); +EXPORT_SYMBOL(fill_async_readblock); +EXPORT_SYMBOL(fill_async_readblock_resp); +EXPORT_SYMBOL(fill_async_writequad); +EXPORT_SYMBOL(fill_async_writeblock); +EXPORT_SYMBOL(fill_async_write_resp); +EXPORT_SYMBOL(fill_async_lock); +EXPORT_SYMBOL(fill_async_lock_resp); +EXPORT_SYMBOL(fill_iso_packet); +EXPORT_SYMBOL(fill_phy_packet); +EXPORT_SYMBOL(hpsb_make_readqpacket); +EXPORT_SYMBOL(hpsb_make_readbpacket); +EXPORT_SYMBOL(hpsb_make_writeqpacket); +EXPORT_SYMBOL(hpsb_make_writebpacket); +EXPORT_SYMBOL(hpsb_make_lockpacket); +EXPORT_SYMBOL(hpsb_make_phypacket); +EXPORT_SYMBOL(hpsb_packet_success); +EXPORT_SYMBOL(hpsb_make_packet); +EXPORT_SYMBOL(hpsb_read); +EXPORT_SYMBOL(hpsb_write); +EXPORT_SYMBOL(hpsb_lock); + +EXPORT_SYMBOL(hpsb_register_highlevel); +EXPORT_SYMBOL(hpsb_unregister_highlevel); +EXPORT_SYMBOL(hpsb_register_addrspace); +EXPORT_SYMBOL(hpsb_listen_channel); +EXPORT_SYMBOL(hpsb_unlisten_channel); +EXPORT_SYMBOL(highlevel_read); +EXPORT_SYMBOL(highlevel_write); +EXPORT_SYMBOL(highlevel_lock); +EXPORT_SYMBOL(highlevel_lock64); +EXPORT_SYMBOL(highlevel_add_host); +EXPORT_SYMBOL(highlevel_remove_host); +EXPORT_SYMBOL(highlevel_host_reset); +EXPORT_SYMBOL(highlevel_add_one_host); + +EXPORT_SYMBOL(hpsb_guid_get_entry); +EXPORT_SYMBOL(hpsb_nodeid_get_entry); +EXPORT_SYMBOL(hpsb_get_host_by_ne); +EXPORT_SYMBOL(hpsb_guid_fill_packet); +EXPORT_SYMBOL(hpsb_register_protocol); +EXPORT_SYMBOL(hpsb_unregister_protocol); +EXPORT_SYMBOL(hpsb_release_unit_directory); + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ieee1394/pcilynx.c linux-2.5/drivers/ieee1394/pcilynx.c --- linux-2.5.5/drivers/ieee1394/pcilynx.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/ieee1394/pcilynx.c Tue Feb 19 16:01:14 2002 @@ -56,7 +56,6 @@ #define PRINTD(level, card, fmt, args...) do {} while (0) #endif - static struct hpsb_host_driver *lynx_driver; static unsigned int card_id; @@ -636,7 +635,7 @@ static int mem_open(struct inode *inode, struct file *file) { - int cid = MINOR(inode->i_rdev); + int cid = minor(inode->i_rdev); enum { t_rom, t_aux, t_ram } type; struct memdata *md; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/ieee1394/video1394.c linux-2.5/drivers/ieee1394/video1394.c --- linux-2.5.5/drivers/ieee1394/video1394.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/ieee1394/video1394.c Tue Feb 26 21:24:48 2002 @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -159,61 +158,35 @@ /* Memory management functions */ /*******************************/ -#define MDEBUG(x) do { } while(0) /* Debug memory management */ - -/* [DaveM] I've recoded most of this so that: - * 1) It's easier to tell what is happening - * 2) It's more portable, especially for translating things - * out of vmalloc mapped areas in the kernel. - * 3) Less unnecessary translations happen. - * - * The code used to assume that the kernel vmalloc mappings - * existed in the page tables of every process, this is simply - * not guaranteed. We now use pgd_offset_k which is the - * defined way to get at the kernel page tables. - */ - -static inline unsigned long uvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - - kva = page_address(vmalloc_to_page(adr)); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); - return ret; -} - static inline unsigned long kvirt_to_bus(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = virt_to_bus((void *)kva); - MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); return ret; } /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); return ret; } static void * rvmalloc(unsigned long size) { void * mem; - unsigned long adr, page; - + unsigned long adr; + + size=PAGE_ALIGN(size); mem=vmalloc_32(size); if (mem) { @@ -222,8 +195,7 @@ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -233,15 +205,14 @@ static void rvfree(void * mem, unsigned long size) { - unsigned long adr, page; - + unsigned long adr; + if (mem) { adr=(unsigned long) mem; - while (size > 0) + while ((long) size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -1381,7 +1352,7 @@ if (video->current_ctx == NULL) { PRINT(KERN_ERR, ohci->id, "Current iso context not set"); } else - res = do_iso_mmap(ohci, video->current_ctx, + res = do_iso_mmap(vma, ohci, video->current_ctx, (char *)vma->vm_start, (unsigned long)(vma->vm_end-vma->vm_start)); unlock_kernel(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/Config.help linux-2.5/drivers/input/Config.help --- linux-2.5.5/drivers/input/Config.help Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/input/Config.help Sun Jan 27 00:32:29 2002 @@ -64,6 +64,18 @@ The module will be called joydev.o. If you want to compile it as a module, say M here and read . +CONFIG_INPUT_TSDEV + Say Y here if you have an application that only can understand the + Compaq touchscreen protocol for absolute pointer data. This is + useful namely for embedded configurations. + + If unsure, say N. + + This driver 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 tsdev.o. If you want to compile it as a + module, say M here and read . + CONFIG_INPUT_EVDEV Say Y here if you want your input device events be accessible under char device 13:64+ - /dev/input/eventX in a generic way. @@ -71,4 +83,18 @@ This driver 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 evdev.o. If you want to compile it as a + module, say M here and read . + +CONFIG_INPUT_EVBUG + Say Y here if you have a problem with the input subsystem and + want all events (keypresses, mouse movements), to be output to + the system log. While this is useful for debugging, it's also + a security threat - your keypresses include your passwords, of + course. + + If unsure, say N. + + This driver 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 joydev.o. If you want to compile it as a module, say M here and read . diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/Config.in linux-2.5/drivers/input/Config.in --- linux-2.5.5/drivers/input/Config.in Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/input/Config.in Sun Jan 20 17:11:45 2002 @@ -13,12 +13,16 @@ int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 fi dep_tristate ' Joystick interface' CONFIG_INPUT_JOYDEV $CONFIG_INPUT +dep_tristate ' Touchscreen interface' CONFIG_INPUT_TSDEV $CONFIG_INPUT dep_tristate ' Event interface' CONFIG_INPUT_EVDEV $CONFIG_INPUT +dep_tristate ' Event debugging' CONFIG_INPUT_EVBUG $CONFIG_INPUT source drivers/input/gameport/Config.in source drivers/input/serio/Config.in if [ "$CONFIG_INPUT" != "n" ]; then + source drivers/input/keyboard/Config.in + source drivers/input/mouse/Config.in source drivers/input/joystick/Config.in fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/Makefile linux-2.5/drivers/input/Makefile --- linux-2.5.5/drivers/input/Makefile Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/input/Makefile Tue Jan 22 13:25:18 2002 @@ -8,7 +8,7 @@ # Objects that export symbols. -mod-subdirs := joystick +mod-subdirs := joystick keyboard mouse export-objs := input.o # Each configuration option enables a list of files. @@ -18,8 +18,21 @@ obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o obj-$(CONFIG_INPUT_EVDEV) += evdev.o +obj-$(CONFIG_INPUT_TSDEV) += tsdev.o +obj-$(CONFIG_INPUT_POWER) += power.o +obj-$(CONFIG_INPUT_EVBUG) += evbug.o subdir-$(CONFIG_INPUT_JOYSTICK) += joystick +subdir-$(CONFIG_INPUT_KEYBOARD) += keyboard +subdir-$(CONFIG_INPUT_MOUSE) += mouse + +ifeq ($(CONFIG_INPUT_KEYBOARD),y) + obj-y += keyboard/keybdrv.o +endif + +ifeq ($(CONFIG_INPUT_MOUSE),y) + obj-y += mouse/mousedrv.o +endif ifeq ($(CONFIG_INPUT_JOYSTICK),y) obj-y += joystick/joydrv.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/evbug.c linux-2.5/drivers/input/evbug.c --- linux-2.5.5/drivers/input/evbug.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/evbug.c Tue Jan 22 17:43:42 2002 @@ -0,0 +1,99 @@ +/* + * $Id: evbug.c,v 1.10 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * Input driver event debug module - dumps all events into syslog + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Input driver event debug module"); +MODULE_LICENSE("GPL"); + +static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value); +} + +static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) +{ + struct input_handle *handle; + + if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + return NULL; + memset(handle, 0, sizeof(struct input_handle)); + + handle->dev = dev; + handle->handler = handler; + + input_open_device(handle); + + printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys); + + return handle; +} + +static void evbug_disconnect(struct input_handle *handle) +{ + printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys); + + input_close_device(handle); + + kfree(handle); +} + +static struct input_device_id evbug_ids[] = { + { driver_info: 1 }, /* Matches all devices */ + { }, /* Terminating zero entry */ +}; + +MODULE_DEVICE_TABLE(input, evbug_ids); + +static struct input_handler evbug_handler = { + event: evbug_event, + connect: evbug_connect, + disconnect: evbug_disconnect, + name: "evbug", + id_table: evbug_ids, +}; + +int __init evbug_init(void) +{ + input_register_handler(&evbug_handler); + return 0; +} + +void __exit evbug_exit(void) +{ + input_unregister_handler(&evbug_handler); +} + +module_init(evbug_init); +module_exit(evbug_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/evdev.c linux-2.5/drivers/input/evdev.c --- linux-2.5.5/drivers/input/evdev.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/input/evdev.c Fri Jan 25 00:37:57 2002 @@ -117,7 +117,7 @@ } kfree(list); - + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/gameport/Config.help linux-2.5/drivers/input/gameport/Config.help --- linux-2.5.5/drivers/input/gameport/Config.help Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/input/gameport/Config.help Sun Jan 27 00:32:29 2002 @@ -43,13 +43,22 @@ The module will be called emu10k1-gp.o. If you want to compile it as a module, say M here and read . -CONFIG_GAMEPORT_PCIGAME - Say Y here if you have an Aureal Vortex 1 or 2 or a Trident - 4DWave NX or DX card and want to use its gameport. +CONFIG_GAMEPORT_VORTEX + Say Y here if you have an Vortex 1 or 2 card and want to use its + gameport. This driver 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 pcigame.o. If you want to compile it as a + The module will be called vortex.o. If you want to compile it as a + module, say M here and read . + +CONFIG_GAMEPORT_VORTEX + Say Y here if you have a ForteMedia FM801 card and want to use its + gameport. + + This driver 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 fm801-gp.o. If you want to compile it as a module, say M here and read . CONFIG_GAMEPORT_CS461X diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/gameport/Config.in linux-2.5/drivers/input/gameport/Config.in --- linux-2.5.5/drivers/input/gameport/Config.in Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/input/gameport/Config.in Mon Jan 21 23:54:13 2002 @@ -14,6 +14,6 @@ dep_tristate ' Classic ISA and PnP gameport support' CONFIG_GAMEPORT_NS558 $CONFIG_GAMEPORT dep_tristate ' PDPI Lightning 4 gamecard support' CONFIG_GAMEPORT_L4 $CONFIG_GAMEPORT dep_tristate ' SB Live and Audigy gameport support' CONFIG_INPUT_EMU10K1 $CONFIG_GAMEPORT -dep_tristate ' Aureal Vortex, Vortex 2 and Trident 4DWave NX/DX gameport support' CONFIG_GAMEPORT_PCIGAME $CONFIG_GAMEPORT +dep_tristate ' Aureal Vortex and Vortex 2 gameport support' CONFIG_GAMEPORT_VORTEX $CONFIG_GAMEPORT dep_tristate ' ForteMedia FM801 gameport support' CONFIG_GAMEPORT_FM801 $CONFIG_GAMEPORT -dep_tristate ' Crystal SoundFusion gameport support' CONFIG_GAMEPORT_CS461x $CONFIG_GAMEPORT +dep_tristate ' Crystal SoundFusion gameport support' CONFIG_GAMEPORT_CS461x $CONFIG_GAMEPORT diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/gameport/Makefile linux-2.5/drivers/input/gameport/Makefile --- linux-2.5.5/drivers/input/gameport/Makefile Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/input/gameport/Makefile Sun Jan 20 17:11:45 2002 @@ -13,11 +13,12 @@ # Each configuration option enables a list of files. obj-$(CONFIG_GAMEPORT) += gameport.o -obj-$(CONFIG_GAMEPORT_CS461X) += cs461x.o +obj-$(CONFIG_GAMEPORT_CS614X) += cs614x.o obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o +obj-$(CONFIG_GAMEPORT_FM801) += fm801-gp.o obj-$(CONFIG_GAMEPORT_L4) += lightning.o obj-$(CONFIG_GAMEPORT_NS558) += ns558.o -obj-$(CONFIG_GAMEPORT_PCIGAME) += pcigame.o +obj-$(CONFIG_GAMEPORT_VORTEX) += vortex.o # The global Rules.make. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/gameport/cs461x.c linux-2.5/drivers/input/gameport/cs461x.c --- linux-2.5.5/drivers/input/gameport/cs461x.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/input/gameport/cs461x.c Tue Feb 26 21:24:48 2002 @@ -25,8 +25,6 @@ #define CS461X_FULL_MAP */ -#define COOKED_MODE - #ifndef PCI_VENDOR_ID_CIRRUS #define PCI_VENDOR_ID_CIRRUS 0x1013 @@ -122,6 +120,9 @@ static unsigned long ba0_addr; static unsigned int *ba0; +static char phys[32]; +static char name[] = "CS416x Gameport"; + #ifdef CS461X_FULL_MAP static unsigned long ba1_addr; static union ba1_t { @@ -158,7 +159,7 @@ static int cs461x_free(struct pci_dev *pdev) { - struct gameport *port = pci_get_drvdata(pdev); + struct gameport *port = (struct gameport *)pdev->driver_data; if(port){ gameport_unregister_port(port); kfree(port); @@ -206,14 +207,11 @@ static int cs461x_gameport_open(struct gameport *gameport, int mode) { switch (mode) { -#ifdef COOKED_MODE - case GAMEPORT_MODE_COOKED: - return 0; -#endif - case GAMEPORT_MODE_RAW: - return 0; - default: - return -1; + case GAMEPORT_MODE_COOKED: + case GAMEPORT_MODE_RAW: + return 0; + default: + return -1; } return 0; } @@ -274,9 +272,7 @@ return -ENOMEM; } #endif - printk(KERN_INFO "CS461x PCI: %lx[%d]\n", - ba0_addr, CS461X_BA0_SIZE); - + if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) { printk(KERN_ERR "Memory allocation failed.\n"); cs461x_free(pdev); @@ -284,22 +280,28 @@ } memset(port, 0, sizeof(struct gameport)); - pci_set_drvdata(pdev, port); + pdev->driver_data = port; port->open = cs461x_gameport_open; - port->read = cs461x_gameport_read; port->trigger = cs461x_gameport_trigger; -#ifdef COOKED_MODE + port->read = cs461x_gameport_read; port->cooked_read = cs461x_gameport_cooked_read; -#endif + + sprintf(phys, "pci%s/gameport0", pdev->slot_name); + + port->name = name; + port->phys = phys; + port->idbus = BUS_PCI; + port->idvendor = pdev->vendor; + port->idproduct = pdev->device; cs461x_pokeBA0(BA0_JSIO, 0xFF); // ? cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW); gameport_register_port(port); - printk(KERN_INFO "gameport%d: CS461x Gameport speed %d kHz\n", - port->number, port->speed); + printk(KERN_INFO "gameport: %s on pci%s speed %d kHz\n", + name, pdev->slot_name, port->speed); return 0; } @@ -310,22 +312,22 @@ } static struct pci_driver cs461x_pci_driver = { - name: "PCI Gameport", + name: "CS461x Gameport", id_table: cs461x_pci_tbl, probe: cs461x_pci_probe, - remove: cs461x_pci_remove, + remove: __devexit_p(cs461x_pci_remove), }; -int __init js_cs461x_init(void) +int __init cs461x_init(void) { return pci_module_init(&cs461x_pci_driver); } -void __exit js_cs461x_exit(void) +void __exit cs461x_exit(void) { pci_unregister_driver(&cs461x_pci_driver); } -module_init(js_cs461x_init); -module_exit(js_cs461x_exit); +module_init(cs461x_init); +module_exit(cs461x_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/gameport/emu10k1-gp.c linux-2.5/drivers/input/gameport/emu10k1-gp.c --- linux-2.5.5/drivers/input/gameport/emu10k1-gp.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/input/gameport/emu10k1-gp.c Tue Feb 26 21:24:48 2002 @@ -1,13 +1,11 @@ /* - * $Id: emu10k1-gp.c,v 1.2 2001/04/24 07:48:56 vojtech Exp $ + * $Id: emu10k1-gp.c,v 1.7 2002/01/03 14:54:00 vojtech Exp $ * * Copyright (c) 2001 Vojtech Pavlik - * - * Sponsored by SuSE */ /* - * EMU10k1 - SB Live! - gameport driver for Linux + * EMU10k1 - SB Live / Audigy - gameport driver for Linux */ /* @@ -27,7 +25,7 @@ * * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -41,6 +39,7 @@ #include MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("EMU10k1 gameport driver"); MODULE_LICENSE("GPL"); struct emu { @@ -48,10 +47,12 @@ struct emu *next; struct gameport gameport; int size; + char phys[32]; }; static struct pci_device_id emu_tbl[] __devinitdata = { - { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live! gameport */ + { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */ + { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */ { 0, } }; @@ -59,56 +60,60 @@ static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - int ioport, iolen; - int rc; - struct emu *port; + int ioemu, iolen; + struct emu *emu; - rc = pci_enable_device(pdev); - if (rc) { - printk(KERN_ERR "emu10k1-gp: Cannot enable emu10k1 gameport (bus %d, devfn %d) error=%d\n", - pdev->bus->number, pdev->devfn, rc); - return rc; - } + if (pci_enable_device(pdev)) + return -EBUSY; - ioport = pci_resource_start(pdev, 0); + ioemu = pci_resource_start(pdev, 0); iolen = pci_resource_len(pdev, 0); - if (!request_region(ioport, iolen, "emu10k1-gp")) + if (!request_region(ioemu, iolen, "emu10k1-gp")) return -EBUSY; - if (!(port = kmalloc(sizeof(struct emu), GFP_KERNEL))) { + if (!(emu = kmalloc(sizeof(struct emu), GFP_KERNEL))) { printk(KERN_ERR "emu10k1-gp: Memory allocation failed.\n"); - release_region(ioport, iolen); + release_region(ioemu, iolen); return -ENOMEM; } - memset(port, 0, sizeof(struct emu)); + memset(emu, 0, sizeof(struct emu)); + + sprintf(emu->phys, "pci%s/gameport0", pdev->slot_name); + + emu->size = iolen; + emu->dev = pdev; + + emu->gameport.io = ioemu; + emu->gameport.name = pdev->name; + emu->gameport.phys = emu->phys; + emu->gameport.idbus = BUS_PCI; + emu->gameport.idvendor = pdev->vendor; + emu->gameport.idproduct = pdev->device; - port->gameport.io = ioport; - port->size = iolen; - port->dev = pdev; - pci_set_drvdata(pdev, port); + pdev->driver_data = emu; - gameport_register_port(&port->gameport); + gameport_register_port(&emu->gameport); - printk(KERN_INFO "gameport%d: Emu10k1 Gameport at %#x size %d speed %d kHz\n", - port->gameport.number, port->gameport.io, iolen, port->gameport.speed); + printk(KERN_INFO "gameport: %s at pci%s speed %d kHz\n", + pdev->name, pdev->slot_name, emu->gameport.speed); return 0; } static void __devexit emu_remove(struct pci_dev *pdev) { - struct emu *port = pci_get_drvdata(pdev); - gameport_unregister_port(&port->gameport); - release_region(port->gameport.io, port->size); - kfree(port); + struct emu *emu = (void *)pdev->driver_data; + gameport_unregister_port(&emu->gameport); + release_region(emu->gameport.io, emu->size); + kfree(emu); } static struct pci_driver emu_driver = { name: "Emu10k1 Gameport", id_table: emu_tbl, probe: emu_probe, - remove: emu_remove, + remove: __devexit_p(emu_remove), }; int __init emu_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/gameport/fm801-gp.c linux-2.5/drivers/input/gameport/fm801-gp.c --- linux-2.5.5/drivers/input/gameport/fm801-gp.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/gameport/fm801-gp.c Sun Jan 20 17:11:45 2002 @@ -0,0 +1,162 @@ +/* + * FM801 gameport driver for Linux + * + * Copyright (c) by Takashi Iwai + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCI_VENDOR_ID_FORTEMEDIA 0x1319 +#define PCI_DEVICE_ID_FM801_GP 0x0802 + +#define HAVE_COOKED + +struct fm801_gp { + struct gameport gameport; + struct resource *res_port; + char phys[32]; + char name[32]; +}; + +#ifdef HAVE_COOKED +static int fm801_gp_cooked_read(struct gameport *gameport, int *axes, int *buttons) +{ + unsigned short w; + + w = inw(gameport->io + 2); + *buttons = (~w >> 14) & 0x03; + axes[0] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5); + w = inw(gameport->io + 4); + axes[1] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5); + w = inw(gameport->io + 6); + *buttons |= ((~w >> 14) & 0x03) << 2; + axes[2] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5); + w = inw(gameport->io + 8); + axes[3] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5); + outw(0xff, gameport->io); /* reset */ + + return 0; +} +#endif + +static int fm801_gp_open(struct gameport *gameport, int mode) +{ + switch (mode) { +#ifdef HAVE_COOKED + case GAMEPORT_MODE_COOKED: + return 0; +#endif + case GAMEPORT_MODE_RAW: + return 0; + default: + return -1; + } + + return 0; +} + +static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id) +{ + struct fm801_gp *gp; + + if (! (gp = kmalloc(sizeof(*gp), GFP_KERNEL))) { + printk("cannot malloc for fm801-gp\n"); + return -1; + } + memset(gp, 0, sizeof(*gp)); + + gp->gameport.open = fm801_gp_open; +#ifdef HAVE_COOKED + gp->gameport.cooked_read = fm801_gp_cooked_read; +#endif + + pci_enable_device(pci); + gp->gameport.io = pci_resource_start(pci, 0); + if ((gp->res_port = request_region(gp->gameport.io, 0x10, "FM801 GP")) == NULL) { + kfree(gp); + printk("unable to grab region 0x%x-0x%x\n", gp->gameport.io, gp->gameport.io + 0x0f); + return -1; + } + + gp->gameport.phys = gp->phys; + gp->gameport.name = gp->name; + gp->gameport.idbus = BUS_PCI; + gp->gameport.idvendor = pci->vendor; + gp->gameport.idproduct = pci->device; + + pci_set_drvdata(pci, gp); + + outb(0x60, gp->gameport.io + 0x0d); /* enable joystick 1 and 2 */ + + gameport_register_port(&gp->gameport); + + printk(KERN_INFO "gameport: %s at pci%s speed %d kHz\n", + pci->name, pci->slot_name, gp->gameport.speed); + + return 0; +} + +static void __devexit fm801_gp_remove(struct pci_dev *pci) +{ + struct fm801_gp *gp = pci_get_drvdata(pci); + if (gp) { + gameport_unregister_port(&gp->gameport); + release_resource(gp->res_port); + kfree(gp); + } +} + +static struct pci_device_id fm801_gp_id_table[] __devinitdata = { + { PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; + +static struct pci_driver fm801_gp_driver = { + name: "FM801 GP", + id_table: fm801_gp_id_table, + probe: fm801_gp_probe, + remove: fm801_gp_remove, +}; + +int __init fm801_gp_init(void) +{ + return pci_module_init(&fm801_gp_driver); +} + +void __exit fm801_gp_exit(void) +{ + pci_unregister_driver(&fm801_gp_driver); +} + +module_init(fm801_gp_init); +module_exit(fm801_gp_exit); + +MODULE_DEVICE_TABLE(pci, fm801_gp_id_table); + +MODULE_AUTHOR("Takashi Iwai "); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/gameport/gameport.c linux-2.5/drivers/input/gameport/gameport.c --- linux-2.5.5/drivers/input/gameport/gameport.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/input/gameport/gameport.c Tue Jan 22 17:43:42 2002 @@ -1,9 +1,7 @@ /* - * $Id: gameport.c,v 1.5 2000/05/29 10:54:53 vojtech Exp $ + * $Id: gameport.c,v 1.17 2001/09/25 10:12:07 vojtech Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1999-2001 Vojtech Pavlik */ /* @@ -26,8 +24,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -40,7 +38,8 @@ #include #include -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Generic gameport layer"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(gameport_register_port); @@ -54,7 +53,6 @@ static struct gameport *gameport_list; static struct gameport_dev *gameport_dev; -static int gameport_number; /* * gameport_measure_speed() measures the gameport i/o speed. @@ -122,7 +120,6 @@ void gameport_register_port(struct gameport *gameport) { - gameport->number = gameport_number++; gameport->next = gameport_list; gameport_list = gameport; @@ -140,8 +137,6 @@ if (gameport->dev && gameport->dev->disconnect) gameport->dev->disconnect(gameport); - - gameport_number--; } void gameport_register_device(struct gameport_dev *dev) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/gameport/lightning.c linux-2.5/drivers/input/gameport/lightning.c --- linux-2.5.5/drivers/input/gameport/lightning.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/input/gameport/lightning.c Tue Jan 22 17:43:42 2002 @@ -1,9 +1,7 @@ /* - * $Id: lightning.c,v 1.13 2001/04/26 10:24:46 vojtech Exp $ + * $Id: lightning.c,v 1.19 2002/01/03 08:55:04 vojtech Exp $ * * Copyright (c) 1998-2001 Vojtech Pavlik - * - * Sponsored by SuSE */ /* @@ -26,8 +24,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -51,14 +49,18 @@ #define L4_BUSY 0x01 #define L4_TIMEOUT 80 /* 80 us */ -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("PDPI Lightning 4 gamecard driver"); MODULE_LICENSE("GPL"); struct l4 { struct gameport gameport; unsigned char port; + char phys[32]; } *l4_port[8]; +char l4_name[] = "PDPI Lightning 4"; + /* * l4_wait_ready() waits for the L4 to become ready. */ @@ -77,7 +79,7 @@ static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons) { - struct l4 *l4 = gameport->private; + struct l4 *l4 = gameport->driver; unsigned char status; int i, result = -1; @@ -110,7 +112,7 @@ static int l4_open(struct gameport *gameport, int mode) { - struct l4 *l4 = gameport->private; + struct l4 *l4 = gameport->driver; if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED) return -1; outb(L4_SELECT_ANALOG, L4_PORT); @@ -188,7 +190,7 @@ { int i, t; int cal[4]; - struct l4 *l4 = gameport->private; + struct l4 *l4 = gameport->driver; if (l4_getcal(l4->port, cal)) return -1; @@ -247,12 +249,18 @@ l4 = l4_port[i * 4 + j] = l4_port[i * 4] + j; l4->port = i * 4 + j; + sprintf(l4->phys, "isa%04x/gameport%d", L4_PORT, 4 * i + j); + gameport = &l4->gameport; - gameport->private = l4; + gameport->driver = l4; gameport->open = l4_open; gameport->cooked_read = l4_cooked_read; gameport->calibrate = l4_calibrate; + gameport->name = l4_name; + gameport->phys = l4->phys; + gameport->idbus = BUS_ISA; + if (!i && !j) gameport->io = L4_PORT; @@ -262,9 +270,7 @@ gameport_register_port(gameport); } - printk(KERN_INFO "gameport%d,%d,%d,%d: PDPI Lightning 4 %s card v%d.%d at %#x\n", - l4_port[i * 4 + 0]->gameport.number, l4_port[i * 4 + 1]->gameport.number, - l4_port[i * 4 + 2]->gameport.number, l4_port[i * 4 + 3]->gameport.number, + printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n", i ? "secondary" : "primary", rev >> 4, rev, L4_PORT); cards++; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/gameport/ns558.c linux-2.5/drivers/input/gameport/ns558.c --- linux-2.5.5/drivers/input/gameport/ns558.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/input/gameport/ns558.c Tue Jan 22 17:43:42 2002 @@ -1,10 +1,8 @@ /* - * $Id: ns558.c,v 1.29 2001/04/24 07:48:56 vojtech Exp $ + * $Id: ns558.c,v 1.41 2001/12/26 21:08:33 jsimmons Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik * Copyright (c) 1999 Brian Gerst - * - * Sponsored by SuSE */ /* @@ -28,7 +26,7 @@ * * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -42,6 +40,7 @@ #include MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Classic gameport (ISA/PnP) driver"); MODULE_LICENSE("GPL"); #define NS558_ISA 1 @@ -56,6 +55,8 @@ struct pci_dev *dev; struct ns558 *next; struct gameport gameport; + char phys[32]; + char name[32]; }; static struct ns558 *ns558; @@ -141,12 +142,21 @@ port->type = NS558_ISA; port->size = (1 << i); port->gameport.io = io & (-1 << i); + port->gameport.phys = port->phys; + port->gameport.name = port->name; + port->gameport.idbus = BUS_ISA; + port->gameport.idvendor = 0x0000; + port->gameport.idproduct = 0x0000; + port->gameport.idversion = 0x0000; + + sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i)); + sprintf(port->name, "NS558 ISA"); request_region(port->gameport.io, (1 << i), "ns558-isa"); gameport_register_port(&port->gameport); - printk(KERN_INFO "gameport%d: NS558 ISA at %#x", port->gameport.number, port->gameport.io); + printk(KERN_INFO "gameport: NS558 ISA at %#x", port->gameport.io); if (port->size > 1) printk(" size %d", port->size); printk(" speed %d kHz\n", port->gameport.speed); @@ -155,17 +165,33 @@ #ifdef __ISAPNP__ +#define NS558_DEVICE(a,b,c,d)\ + card_vendor: ISAPNP_ANY_ID, card_device: ISAPNP_ANY_ID,\ + vendor: ISAPNP_VENDOR(a,b,c), function: ISAPNP_DEVICE(d) + static struct isapnp_device_id pnp_devids[] = { - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x0001), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x2001), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7001), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f), 0 }, + { NS558_DEVICE('@','P','@',0x0001) }, /* ALS 100 */ + { NS558_DEVICE('@','P','@',0x0020) }, /* ALS 200 */ + { NS558_DEVICE('@','P','@',0x1001) }, /* ALS 100+ */ + { NS558_DEVICE('@','P','@',0x2001) }, /* ALS 120 */ + { NS558_DEVICE('A','S','B',0x16fd) }, /* AdLib NSC16 */ + { NS558_DEVICE('A','Z','T',0x3001) }, /* AZT1008 */ + { NS558_DEVICE('C','D','C',0x0001) }, /* Opl3-SAx */ + { NS558_DEVICE('C','S','C',0x0001) }, /* CS4232 */ + { NS558_DEVICE('C','S','C',0x000f) }, /* CS4236 */ + { NS558_DEVICE('C','S','C',0x0101) }, /* CS4327 */ + { NS558_DEVICE('C','T','L',0x7001) }, /* SB16 */ + { NS558_DEVICE('C','T','L',0x7002) }, /* AWE64 */ + { NS558_DEVICE('C','T','L',0x7005) }, /* Vibra16 */ + { NS558_DEVICE('E','N','S',0x2020) }, /* SoundscapeVIVO */ + { NS558_DEVICE('E','S','S',0x0001) }, /* ES1869 */ + { NS558_DEVICE('E','S','S',0x0005) }, /* ES1878 */ + { NS558_DEVICE('E','S','S',0x6880) }, /* ES688 */ + { NS558_DEVICE('I','B','M',0x0012) }, /* CS4232 */ + { NS558_DEVICE('O','P','T',0x0001) }, /* OPTi Audio16 */ + { NS558_DEVICE('Y','M','H',0x0006) }, /* Opl3-SA */ + { NS558_DEVICE('Y','M','H',0x0022) }, /* Opl3-SAx */ + { NS558_DEVICE('P','N','P',0xb02f) }, /* Generic */ { 0, }, }; @@ -203,13 +229,24 @@ port->next = next; port->type = NS558_PNP; - port->gameport.io = ioport; port->size = iolen; port->dev = dev; + port->gameport.io = ioport; + port->gameport.phys = port->phys; + port->gameport.name = port->name; + port->gameport.idbus = BUS_ISAPNP; + port->gameport.idvendor = dev->vendor; + port->gameport.idproduct = dev->device; + port->gameport.idversion = 0x100; + + sprintf(port->phys, "isapnp%d.%d/gameport0", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + sprintf(port->name, "%s", dev->name[0] ? dev->name : "NS558 PnP Gameport"); + gameport_register_port(&port->gameport); - printk(KERN_INFO "gameport%d: NS558 PnP at %#x", port->gameport.number, port->gameport.io); + printk(KERN_INFO "gameport: NS558 PnP at isapnp%d.%d io %#x", + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), port->gameport.io); if (iolen > 1) printk(" size %d", iolen); printk(" speed %d kHz\n", port->gameport.speed); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/gameport/pcigame.c linux-2.5/drivers/input/gameport/pcigame.c --- linux-2.5.5/drivers/input/gameport/pcigame.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/input/gameport/pcigame.c Thu Jan 1 00:00:00 1970 @@ -1,199 +0,0 @@ -/* - * $Id: pcigame.c,v 1.10 2001/04/26 10:24:46 vojtech Exp $ - * - * Copyright (c) 2000-2001 Vojtech Pavlik - * - * Based on the work of: - * Raymond Ingles - * - * Sponsored by SuSE - */ - -/* - * Trident 4DWave and Aureal Vortex gameport driver for Linux - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PCI_VENDOR_ID_AUREAL 0x12eb - -#define PCIGAME_DATA_WAIT 20 /* 20 ms */ - -#define PCIGAME_4DWAVE 0 -#define PCIGAME_VORTEX 1 -#define PCIGAME_VORTEX2 2 - -struct pcigame_data { - int gcr; /* Gameport control register */ - int legacy; /* Legacy port location */ - int axes; /* Axes start */ - int axsize; /* Axis field size */ - int axmax; /* Axis field max value */ - int adcmode; /* Value to enable ADC mode in GCR */ -}; - -static struct pcigame_data pcigame_data[] __devinitdata = -{{ 0x00030, 0x00031, 0x00034, 2, 0xffff, 0x80 }, - { 0x1100c, 0x11008, 0x11010, 4, 0x1fff, 0x40 }, - { 0x2880c, 0x28808, 0x28810, 4, 0x1fff, 0x40 }, - { 0 }}; - -struct pcigame { - struct gameport gameport; - struct pci_dev *dev; - unsigned char *base; - struct pcigame_data *data; -}; - -static unsigned char pcigame_read(struct gameport *gameport) -{ - struct pcigame *pcigame = gameport->private; - return readb(pcigame->base + pcigame->data->legacy); -} - -static void pcigame_trigger(struct gameport *gameport) -{ - struct pcigame *pcigame = gameport->private; - writeb(0xff, pcigame->base + pcigame->data->legacy); -} - -static int pcigame_cooked_read(struct gameport *gameport, int *axes, int *buttons) -{ - struct pcigame *pcigame = gameport->private; - int i; - - *buttons = (~readb(pcigame->base + pcigame->data->legacy) >> 4) & 0xf; - - for (i = 0; i < 4; i++) { - axes[i] = readw(pcigame->base + pcigame->data->axes + i * pcigame->data->axsize); - if (axes[i] == pcigame->data->axmax) axes[i] = -1; - } - - return 0; -} - -static int pcigame_open(struct gameport *gameport, int mode) -{ - struct pcigame *pcigame = gameport->private; - - switch (mode) { - case GAMEPORT_MODE_COOKED: - writeb(pcigame->data->adcmode, pcigame->base + pcigame->data->gcr); - wait_ms(PCIGAME_DATA_WAIT); - return 0; - case GAMEPORT_MODE_RAW: - writeb(0, pcigame->base + pcigame->data->gcr); - return 0; - default: - return -1; - } - - return 0; -} - -static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct pcigame *pcigame; - int i; - - if (!(pcigame = kmalloc(sizeof(struct pcigame), GFP_KERNEL))) - return -1; - memset(pcigame, 0, sizeof(struct pcigame)); - - - pcigame->data = pcigame_data + id->driver_data; - - pcigame->dev = dev; - pci_set_drvdata(dev, pcigame); - - pcigame->gameport.private = pcigame; - pcigame->gameport.fuzz = 64; - - pcigame->gameport.read = pcigame_read; - pcigame->gameport.trigger = pcigame_trigger; - pcigame->gameport.cooked_read = pcigame_cooked_read; - pcigame->gameport.open = pcigame_open; - - for (i = 0; i < 6; i++) - if (~pci_resource_flags(dev, i) & IORESOURCE_IO) - break; - - pci_enable_device(dev); - - pcigame->base = ioremap(pci_resource_start(pcigame->dev, i), - pci_resource_len(pcigame->dev, i)); - - gameport_register_port(&pcigame->gameport); - - printk(KERN_INFO "gameport%d: %s at pci%02x:%02x.%x speed %d kHz\n", - pcigame->gameport.number, dev->name, dev->bus->number, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), pcigame->gameport.speed); - - return 0; -} - -static void __devexit pcigame_remove(struct pci_dev *dev) -{ - struct pcigame *pcigame = pci_get_drvdata(dev); - gameport_unregister_port(&pcigame->gameport); - iounmap(pcigame->base); - kfree(pcigame); -} - -static struct pci_device_id pcigame_id_table[] __devinitdata = -{{ PCI_VENDOR_ID_TRIDENT, 0x2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE }, - { PCI_VENDOR_ID_TRIDENT, 0x2001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE }, - { PCI_VENDOR_ID_AUREAL, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX }, - { PCI_VENDOR_ID_AUREAL, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX2 }, - { 0 }}; - -static struct pci_driver pcigame_driver = { - name: "pcigame", - id_table: pcigame_id_table, - probe: pcigame_probe, - remove: pcigame_remove, -}; - -int __init pcigame_init(void) -{ - return pci_module_init(&pcigame_driver); -} - -void __exit pcigame_exit(void) -{ - pci_unregister_driver(&pcigame_driver); -} - -module_init(pcigame_init); -module_exit(pcigame_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/gameport/vortex.c linux-2.5/drivers/input/gameport/vortex.c --- linux-2.5.5/drivers/input/gameport/vortex.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/gameport/vortex.c Tue Jan 22 17:52:50 2002 @@ -0,0 +1,185 @@ +/* + * $Id: vortex.c,v 1.1 2002/01/03 15:33:39 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * + * Based on the work of: + * Raymond Ingles + */ + +/* + * Trident 4DWave and Aureal Vortex gameport driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver"); +MODULE_LICENSE("GPL"); + +#define VORTEX_GCR 0x0c /* Gameport control register */ +#define VORTEX_LEG 0x08 /* Legacy port location */ +#define VORTEX_AXD 0x10 /* Axes start */ +#define VORTEX_DATA_WAIT 20 /* 20 ms */ + +struct vortex { + struct gameport gameport; + struct pci_dev *dev; + unsigned char *base; + unsigned char *io; + char phys[32]; +}; + +static unsigned char vortex_read(struct gameport *gameport) +{ + struct vortex *vortex = gameport->driver; + return readb(vortex->io + VORTEX_LEG); +} + +static void vortex_trigger(struct gameport *gameport) +{ + struct vortex *vortex = gameport->driver; + writeb(0xff, vortex->io + VORTEX_LEG); +} + +static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons) +{ + struct vortex *vortex = gameport->driver; + int i; + + *buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf; + + for (i = 0; i < 4; i++) { + axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32)); + if (axes[i] == 0x1fff) axes[i] = -1; + } + + return 0; +} + +static int vortex_open(struct gameport *gameport, int mode) +{ + struct vortex *vortex = gameport->driver; + + switch (mode) { + case GAMEPORT_MODE_COOKED: + writeb(0x40, vortex->io + VORTEX_GCR); + wait_ms(VORTEX_DATA_WAIT); + return 0; + case GAMEPORT_MODE_RAW: + writeb(0x00, vortex->io + VORTEX_GCR); + return 0; + default: + return -1; + } + + return 0; +} + +static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct vortex *vortex; + int i; + + if (!(vortex = kmalloc(sizeof(struct vortex), GFP_KERNEL))) + return -1; + memset(vortex, 0, sizeof(struct vortex)); + + vortex->dev = dev; + sprintf(vortex->phys, "pci%s/gameport0", dev->slot_name); + + dev->driver_data = vortex; + + vortex->gameport.driver = vortex; + vortex->gameport.fuzz = 64; + + vortex->gameport.read = vortex_read; + vortex->gameport.trigger = vortex_trigger; + vortex->gameport.cooked_read = vortex_cooked_read; + vortex->gameport.open = vortex_open; + + vortex->gameport.name = dev->name; + vortex->gameport.phys = vortex->phys; + vortex->gameport.idbus = BUS_PCI; + vortex->gameport.idvendor = dev->vendor; + vortex->gameport.idproduct = dev->device; + + for (i = 0; i < 6; i++) + if (~pci_resource_flags(dev, i) & IORESOURCE_IO) + break; + + pci_enable_device(dev); + + vortex->base = ioremap(pci_resource_start(vortex->dev, i), + pci_resource_len(vortex->dev, i)); + vortex->io = vortex->base + id->driver_data; + + gameport_register_port(&vortex->gameport); + + printk(KERN_INFO "gameport: %s at pci%s speed %d kHz\n", + dev->name, dev->slot_name, vortex->gameport.speed); + + return 0; +} + +static void __devexit vortex_remove(struct pci_dev *dev) +{ + struct vortex *vortex = dev->driver_data; + gameport_unregister_port(&vortex->gameport); + iounmap(vortex->base); + kfree(vortex); +} + +static struct pci_device_id vortex_id_table[] __devinitdata = +{{ 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 }, + { 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 }, + { 0 }}; + +static struct pci_driver vortex_driver = { + name: "vortex", + id_table: vortex_id_table, + probe: vortex_probe, + remove: vortex_remove, +}; + +int __init vortex_init(void) +{ + return pci_module_init(&vortex_driver); +} + +void __exit vortex_exit(void) +{ + pci_unregister_driver(&vortex_driver); +} + +module_init(vortex_init); +module_exit(vortex_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/input.c linux-2.5/drivers/input/input.c --- linux-2.5.5/drivers/input/input.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/input/input.c Fri Jan 25 19:43:55 2002 @@ -61,8 +61,6 @@ static struct input_handler *input_handler; static struct input_handler *input_table[8]; static devfs_handle_t input_devfs_handle; -static int input_number; -static long input_devices[NBITS(INPUT_DEVICES)]; #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_bus_input_dir; @@ -454,17 +452,8 @@ * Add the device. */ - if (input_number >= INPUT_DEVICES) { - printk(KERN_WARNING "input: ran out of input device numbers!\n"); - dev->number = input_number; - } else { - dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES); - set_bit(dev->number, input_devices); - } - dev->next = input_dev; input_dev = dev; - input_number++; /* * Notify handlers. @@ -493,7 +482,6 @@ input_devices_state++; wake_up(&input_devices_poll_wait); #endif - } void input_unregister_device(struct input_dev *dev) @@ -509,7 +497,6 @@ if (dev->pm_dev) pm_unregister(dev->pm_dev); - /* * Kill any pending repeat timers. */ @@ -540,7 +527,6 @@ */ input_find_and_remove(struct input_dev, input_dev, dev, next); - input_number--; /* * Notify /proc. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/Config.help linux-2.5/drivers/input/joystick/Config.help --- linux-2.5.5/drivers/input/joystick/Config.help Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/input/joystick/Config.help Sun Jan 27 00:32:29 2002 @@ -67,6 +67,15 @@ The module will be called grip.o. If you want to compile it as a module, say M here and read . +CONFIG_JOYSTICK_GUILLEMOT + Say Y here if you have a Guillemot joystick using a digital + protocol over the PC gameport. + + This driver 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 guillemot.o. If you want to compile it as a + module, say M here and read . + CONFIG_JOYSTICK_INTERACT Say Y here if you have an InterAct gameport or joystick communicating digitally over the gameport. @@ -156,6 +165,15 @@ This driver 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 stinger.o. If you want to compile it as a + module, say M here and read . + +CONFIG_JOYSTICK_TWIDDLER + Say Y here if you have a Handykey Twiddler connected to your + computer's serial port and want to use it as a joystick. + + This driver 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 twidjoy.o. If you want to compile it as a module, say M here and read . CONFIG_JOYSTICK_DB9 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/Config.in linux-2.5/drivers/input/joystick/Config.in --- linux-2.5.5/drivers/input/joystick/Config.in Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/input/joystick/Config.in Sun Jan 20 17:11:45 2002 @@ -10,6 +10,7 @@ dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_JOYSTICK_COBRA $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_JOYSTICK_GF2K $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOYSTICK_GRIP $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT +dep_tristate ' Guillemot joysticks and gamepads' CONFIG_JOYSTICK_GUILLEMOT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_JOYSTICK_INTERACT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_JOYSTICK_SIDEWINDER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOYSTICK_TMDC $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT @@ -21,6 +22,7 @@ dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controllers' CONFIG_JOYSTICK_SPACEORB $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO dep_tristate ' SpaceTec SpaceBall 6dof controllers' CONFIG_JOYSTICK_SPACEBALL $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO dep_tristate ' Gravis Stinger gamepad' CONFIG_JOYSTICK_STINGER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO +dep_tristate ' Twiddler as as joystick' CONFIG_JOYSTICK_TWIDDLER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_JOYSTICK_DB9 $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_JOYSTICK_GAMECON $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/Makefile linux-2.5/drivers/input/joystick/Makefile --- linux-2.5.5/drivers/input/joystick/Makefile Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/input/joystick/Makefile Sun Jan 20 17:11:45 2002 @@ -6,24 +6,6 @@ O_TARGET := joydrv.o -# I-Force may need both USB and RS-232 - -CONFIG_JOYSTICK_IFORCE := n - -ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) - ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y) - CONFIG_JOYSTICK_IFORCE := y - endif -endif - -ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m) - CONFIG_JOYSTICK_IFORCE := m -endif - -ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m) - CONFIG_JOYSTICK_IFORCE := m -endif - # Each configuration option enables a list of files. obj-$(CONFIG_JOYSTICK_A3D) += a3d.o @@ -35,8 +17,9 @@ obj-$(CONFIG_JOYSTICK_GAMECON) += gamecon.o obj-$(CONFIG_JOYSTICK_GF2K) += gf2k.o obj-$(CONFIG_JOYSTICK_GRIP) += grip.o -obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o +obj-$(CONFIG_JOYSTICK_GUILLEMOT) += guillemot.o obj-$(CONFIG_JOYSTICK_INTERACT) += interact.o +obj-$(CONFIG_JOYSTICK_JOYDUMP) += joydump.o obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o @@ -44,7 +27,32 @@ obj-$(CONFIG_JOYSTICK_STINGER) += stinger.o obj-$(CONFIG_JOYSTICK_TMDC) += tmdc.o obj-$(CONFIG_JOYSTICK_TURBOGRAFX) += turbografx.o +obj-$(CONFIG_JOYSTICK_TWIDJOY) += twidjoy.o obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o + +# I-Force may need both USB and RS-232 + +CONFIG_JOYSTICK_IFORCE := n + +ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) + ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y) + CONFIG_JOYSTICK_IFORCE := y + endif +endif + +ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m) + CONFIG_JOYSTICK_IFORCE := m +endif + +ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m) + CONFIG_JOYSTICK_IFORCE := m +endif + +subdir-$(CONFIG_JOYSTICK_IFORCE) += iforce + +ifeq ($(CONFIG_JOYSTICK_IFORCE),y) + obj-y += iforce/iforce-drv.o +endif # The global Rules.make. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/a3d.c linux-2.5/drivers/input/joystick/a3d.c --- linux-2.5.5/drivers/input/joystick/a3d.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/input/joystick/a3d.c Fri Mar 1 14:44:10 2002 @@ -1,9 +1,7 @@ /* - * $Id: a3d.c,v 1.14 2001/04/26 10:24:46 vojtech Exp $ + * $Id: a3d.c,v 1.21 2002/01/22 20:11:50 vojtech Exp $ * * Copyright (c) 1998-2001 Vojtech Pavlik - * - * Sponsored by SuSE */ /* @@ -26,8 +24,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -37,6 +35,10 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("FP-Gaming Assasin 3D joystick driver"); +MODULE_LICENSE("GPL"); + #define A3D_MAX_START 400 /* 400 us */ #define A3D_MAX_STROBE 60 /* 40 us */ #define A3D_DELAY_READ 3 /* 3 ms */ @@ -63,6 +65,8 @@ int used; int reads; int bads; + char phys[32]; + char adcphys[32]; }; /* @@ -190,7 +194,7 @@ int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons) { - struct a3d *a3d = gameport->private; + struct a3d *a3d = gameport->driver; int i; for (i = 0; i < 4; i++) axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1; @@ -205,7 +209,7 @@ int a3d_adc_open(struct gameport *gameport, int mode) { - struct a3d *a3d = gameport->private; + struct a3d *a3d = gameport->driver; if (mode != GAMEPORT_MODE_COOKED) return -1; if (!a3d->used++) @@ -219,7 +223,7 @@ static void a3d_adc_close(struct gameport *gameport) { - struct a3d *a3d = gameport->private; + struct a3d *a3d = gameport->driver; if (!--a3d->used) del_timer(&a3d->timer); } @@ -280,10 +284,12 @@ if (!a3d->mode || a3d->mode > 5) { printk(KERN_WARNING "a3d.c: Unknown A3D device detected " - "(gameport%d, id=%d), contact \n", gameport->number, a3d->mode); + "(%s, id=%d), contact \n", gameport->phys, a3d->mode); goto fail2; } + sprintf(a3d->phys, "%s/input0", gameport->phys); + sprintf(a3d->adcphys, "%s/gameport0", gameport->phys); if (a3d->mode == A3D_MODE_PXL) { @@ -323,17 +329,23 @@ a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y); a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE); - a3d->adc.private = a3d; + a3d->adc.driver = a3d; a3d->adc.open = a3d_adc_open; a3d->adc.close = a3d_adc_close; a3d->adc.cooked_read = a3d_adc_cooked_read; a3d->adc.fuzz = 1; + a3d->adc.name = a3d_names[a3d->mode]; + a3d->adc.phys = a3d->adcphys; + a3d->adc.idbus = BUS_GAMEPORT; + a3d->adc.idvendor = GAMEPORT_ID_VENDOR_MADCATZ; + a3d->adc.idproduct = a3d->mode; + a3d->adc.idversion = 0x0100; + a3d_read(a3d, data); gameport_register_port(&a3d->adc); - printk(KERN_INFO "gameport%d: %s on gameport%d.0\n", - a3d->adc.number, a3d_names[a3d->mode], gameport->number); + printk(KERN_INFO "gameport: %s on %s\n", a3d_names[a3d->mode], gameport->phys); } a3d->dev.private = a3d; @@ -341,14 +353,14 @@ a3d->dev.close = a3d_close; a3d->dev.name = a3d_names[a3d->mode]; + a3d->dev.phys = a3d->phys; a3d->dev.idbus = BUS_GAMEPORT; a3d->dev.idvendor = GAMEPORT_ID_VENDOR_MADCATZ; a3d->dev.idproduct = a3d->mode; a3d->dev.idversion = 0x0100; input_register_device(&a3d->dev); - printk(KERN_INFO "input%d: %s on gameport%d.0\n", - a3d->dev.number, a3d_names[a3d->mode], gameport->number); + printk(KERN_INFO "input: %s on %s\n", a3d_names[a3d->mode], a3d->phys); return; fail2: gameport_close(gameport); @@ -384,5 +396,3 @@ module_init(a3d_init); module_exit(a3d_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/adi.c linux-2.5/drivers/input/joystick/adi.c --- linux-2.5.5/drivers/input/joystick/adi.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/input/joystick/adi.c Fri Mar 1 14:44:37 2002 @@ -1,9 +1,7 @@ /* - * $Id: adi.c,v 1.15 2001/01/09 13:32:39 vojtech Exp $ + * $Id: adi.c,v 1.23 2002/01/22 20:26:17 vojtech Exp $ * - * Copyright (c) 1998-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1998-2001 Vojtech Pavlik */ /* @@ -26,8 +24,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -39,6 +37,10 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Logitech ADI joystick family driver"); +MODULE_LICENSE("GPL"); + /* * Times, array sizes, flags, ids. */ @@ -55,6 +57,7 @@ #define ADI_MIN_ID_LENGTH 66 #define ADI_MAX_NAME_LENGTH 48 #define ADI_MAX_CNAME_LENGTH 16 +#define ADI_MAX_PHYS_LENGTH 32 #define ADI_FLAG_HAT 0x04 #define ADI_FLAG_10BIT 0x08 @@ -118,6 +121,7 @@ short *key; char name[ADI_MAX_NAME_LENGTH]; char cname[ADI_MAX_CNAME_LENGTH]; + char phys[ADI_MAX_PHYS_LENGTH]; unsigned char data[ADI_MAX_LENGTH]; }; @@ -392,7 +396,7 @@ } } -static void adi_init_input(struct adi *adi, struct adi_port *port) +static void adi_init_input(struct adi *adi, struct adi_port *port, int half) { int i, t; char buf[ADI_MAX_NAME_LENGTH]; @@ -403,6 +407,7 @@ sprintf(buf, adi_names[t], adi->id); sprintf(adi->name, "Logitech %s", buf); + sprintf(adi->phys, "%s/input%d", port->gameport->phys, half); adi->abs = adi_abs[t]; adi->key = adi_key[t]; @@ -411,6 +416,7 @@ adi->dev.close = adi_close; adi->dev.name = adi->name; + adi->dev.phys = adi->phys; adi->dev.idbus = BUS_GAMEPORT; adi->dev.idvendor = GAMEPORT_ID_VENDOR_LOGITECH; adi->dev.idproduct = adi->id; @@ -419,7 +425,7 @@ adi->dev.private = port; adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++) + for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) set_bit(adi->abs[i], &adi->dev.absbit); for (i = 0; i < adi->buttons; i++) @@ -432,7 +438,7 @@ if (!adi->length) return; - for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++) { + for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) { t = adi->abs[i]; x = adi->dev.abs[t]; @@ -495,7 +501,7 @@ for (i = 0; i < 2; i++) { adi_id_decode(port->adi + i, port); - adi_init_input(port->adi + i, port); + adi_init_input(port->adi + i, port, i); } if (!port->adi[0].length && !port->adi[1].length) { @@ -514,8 +520,8 @@ if (port->adi[i].length > 0) { adi_init_center(port->adi + i); input_register_device(&port->adi[i].dev); - printk(KERN_INFO "input%d: %s [%s] on gameport%d.%d\n", - port->adi[i].dev.number, port->adi[i].name, port->adi[i].cname, gameport->number, i); + printk(KERN_INFO "input: %s [%s] on %s\n", + port->adi[i].name, port->adi[i].cname, gameport->phys); } } @@ -553,5 +559,3 @@ module_init(adi_init); module_exit(adi_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/amijoy.c linux-2.5/drivers/input/joystick/amijoy.c --- linux-2.5.5/drivers/input/joystick/amijoy.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/input/joystick/amijoy.c Fri Mar 1 14:44:59 2002 @@ -1,9 +1,7 @@ /* - * $Id: amijoy.c,v 1.5 2000/07/21 22:52:24 vojtech Exp $ + * $Id: amijoy.c,v 1.13 2002/01/22 20:26:32 vojtech Exp $ * - * Copyright (c) 1998-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1998-2001 Vojtech Pavlik */ /* @@ -26,8 +24,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -40,13 +38,15 @@ #include #include -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Driver for Amiga joysticks"); MODULE_PARM(amijoy, "1-2i"); MODULE_LICENSE("GPL"); static int amijoy[2] = { 0, 1 }; static int amijoy_used[2] = { 0, 0 }; static struct input_dev amijoy_dev[2]; +static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" }; static char *amijoy_name = "Amiga joystick"; @@ -64,9 +64,9 @@ input_report_key(amijoy_dev + i, BTN_TRIGGER, button); - input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1); + input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1)); data = ~(data ^ (data << 1)); - input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1); + input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1)); } } @@ -133,6 +133,7 @@ } amijoy->dev[i].name = amijoy_name; + amijoy->dev[i].phys = amijoy_phys[i]; amijoy->dev[i].idbus = BUS_AMIGA; amijoy->dev[i].idvendor = 0x0001; amijoy->dev[i].idproduct = 0x0003; @@ -141,7 +142,7 @@ amijoy_dev[i].private = amijoy_used + i; input_register_device(amijoy_dev + i); - printk(KERN_INFO "input%d: %s at joy%ddat\n", amijoy_dev[i].number, amijoy_name, i); + printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i); } return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/analog.c linux-2.5/drivers/input/joystick/analog.c --- linux-2.5.5/drivers/input/joystick/analog.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/input/joystick/analog.c Fri Mar 1 14:46:06 2002 @@ -1,9 +1,7 @@ /* - * $Id: analog.c,v 1.52 2000/06/07 13:07:06 vojtech Exp $ + * $Id: analog.c,v 1.68 2002/01/22 20:18:32 vojtech Exp $ * - * Copyright (c) 1996-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1996-2001 Vojtech Pavlik */ /* @@ -26,8 +24,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -41,8 +39,8 @@ #include #include -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Analog joystick and gamepad driver for Linux"); +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Analog joystick and gamepad driver"); MODULE_LICENSE("GPL"); /* @@ -95,6 +93,7 @@ #define ANALOG_FUZZ_MAGIC 36 /* 36 u*ms/loop */ #define ANALOG_MAX_NAME_LENGTH 128 +#define ANALOG_MAX_PHYS_LENGTH 32 static short analog_axes[] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE }; static short analog_hats[] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; @@ -111,6 +110,7 @@ int mask; short *buttons; char name[ANALOG_MAX_NAME_LENGTH]; + char phys[ANALOG_MAX_PHYS_LENGTH]; }; struct analog_port { @@ -138,15 +138,29 @@ #ifdef __i386__ #define TSC_PRESENT (test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability)) -#define GET_TIME(x) do { if (TSC_PRESENT) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0) +#define GET_TIME(x) do { if (TSC_PRESENT) rdtscl(x); else x = get_time_pit(); } while (0) #define DELTA(x,y) (TSC_PRESENT?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0))) #define TIME_NAME (TSC_PRESENT?"TSC":"PIT") +static unsigned int get_time_pit(void) +{ + extern spinlock_t i8253_lock; + unsigned long flags; + unsigned int count; + + spin_lock_irqsave(&i8253_lock, flags); + outb_p(0x00, 0x43); + count = inb_p(0x40); + count |= inb_p(0x40) << 8; + spin_unlock_irqrestore(&i8253_lock, flags); + + return count; +} #elif __x86_64__ #define GET_TIME(x) rdtscl(x) #define DELTA(x,y) ((y)-(x)) #define TIME_NAME "TSC" #elif __alpha__ -#define GET_TIME(x) ((x) = get_cycles()) +#define GET_TIME(x) do { x = get_cycles(x); } while (0) #define DELTA(x,y) ((y)-(x)) #define TIME_NAME "PCC" #else @@ -418,10 +432,12 @@ int i, j, t, v, w, x, y, z; analog_name(analog); + sprintf(analog->phys, "%s/input%d", port->gameport->phys, index); analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn; analog->dev.name = analog->name; + analog->dev.phys = analog->phys; analog->dev.idbus = BUS_GAMEPORT; analog->dev.idvendor = GAMEPORT_ID_VENDOR_ANALOG; analog->dev.idproduct = analog->mask >> 4; @@ -491,15 +507,14 @@ input_register_device(&analog->dev); - printk(KERN_INFO "input%d: %s at gameport%d.%d", - analog->dev.number, analog->name, port->gameport->number, index); + printk(KERN_INFO "input: %s at %s", analog->name, port->gameport->phys); if (port->cooked) printk(" [ADC port]\n"); else printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME, port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed, - port->speed > 10000 ? "M" : "k", + port->speed > 10000 ? "M" : "k", port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000) : (port->loop * 1000000) / port->speed); } @@ -519,12 +534,13 @@ if ((port->mask & 3) != 3 && port->mask != 0xc) { printk(KERN_WARNING "analog.c: Unknown joystick device found " - "(data=%#x, gameport%d), probably not analog joystick.\n", - port->mask, port->gameport->number); + "(data=%#x, %s), probably not analog joystick.\n", + port->mask, port->gameport->phys); return -1; } - i = port->gameport->number < ANALOG_PORTS ? analog_options[port->gameport->number] : 0xff; + + i = analog_options[0]; /* FIXME !!! - need to specify options for different ports */ analog[0].mask = i & 0xfffff; @@ -604,8 +620,8 @@ gameport_trigger(gameport); while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++; - if (v < (u >> 1) && port->gameport->number < ANALOG_PORTS) { - analog_options[port->gameport->number] |= + if (v < (u >> 1)) { /* FIXME - more than one port */ + analog_options[0] |= /* FIXME - more than one port */ ANALOG_SAITEK | ANALOG_BTNS_CHF | ANALOG_HBTN_CHF | ANALOG_HAT1_CHF; return 0; } @@ -666,9 +682,9 @@ if (port->analog[i].mask) input_unregister_device(&port->analog[i].dev); gameport_close(gameport); - printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on gameport%d failed\n", + printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on %s failed\n", port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0, - port->gameport->number); + port->gameport->phys); kfree(port); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/cobra.c linux-2.5/drivers/input/joystick/cobra.c --- linux-2.5.5/drivers/input/joystick/cobra.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/input/joystick/cobra.c Fri Mar 1 14:46:33 2002 @@ -1,13 +1,11 @@ /* - * $Id: cobra.c,v 1.10 2000/06/08 10:23:45 vojtech Exp $ + * $Id: cobra.c,v 1.19 2002/01/22 20:26:52 vojtech Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1999-2001 Vojtech Pavlik */ /* - * Creative Labd Blaster GamePad Cobra driver for Linux + * Creative Labs Blaster GamePad Cobra driver for Linux */ /* @@ -26,8 +24,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -37,6 +35,10 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Creative Labs Blaster GamePad Cobra driver"); +MODULE_LICENSE("GPL"); + #define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */ #define COBRA_REFRESH_TIME HZ/50 /* 20 ms between reads */ #define COBRA_LENGTH 36 @@ -53,6 +55,7 @@ int reads; int bads; unsigned char exists; + char phys[2][32]; }; static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data) @@ -121,6 +124,7 @@ if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists) cobra->bads++; + else for (i = 0; i < 2; i++) if (cobra->exists & r & (1 << i)) { @@ -177,8 +181,8 @@ for (i = 0; i < 2; i++) if ((cobra->exists >> i) & data[i] & 1) { - printk(KERN_WARNING "cobra.c: Device on gameport%d.%d has the Ext bit set. ID is: %d" - " Contact vojtech@suse.cz\n", gameport->number, i, (data[i] >> 2) & 7); + printk(KERN_WARNING "cobra.c: Device %d on %s has the Ext bit set. ID is: %d" + " Contact vojtech@ucw.cz\n", i, gameport->phys, (data[i] >> 2) & 7); cobra->exists &= ~(1 << i); } @@ -188,11 +192,14 @@ for (i = 0; i < 2; i++) if ((cobra->exists >> i) & 1) { + sprintf(cobra->phys[i], "%s/input%d", gameport->phys, i); + cobra->dev[i].private = cobra; cobra->dev[i].open = cobra_open; cobra->dev[i].close = cobra_close; cobra->dev[i].name = cobra_name; + cobra->dev[i].phys = cobra->phys[i]; cobra->dev[i].idbus = BUS_GAMEPORT; cobra->dev[i].idvendor = GAMEPORT_ID_VENDOR_CREATIVE; cobra->dev[i].idproduct = 0x0008; @@ -208,11 +215,9 @@ cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1; input_register_device(cobra->dev + i); - printk(KERN_INFO "input%d: %s on gameport%d.%d\n", - cobra->dev[i].number, cobra_name, gameport->number, i); + printk(KERN_INFO "input: %s on %s\n", cobra_name, gameport->phys); } - return; fail2: gameport_close(gameport); fail1: kfree(cobra); @@ -248,5 +253,3 @@ module_init(cobra_init); module_exit(cobra_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/db9.c linux-2.5/drivers/input/joystick/db9.c --- linux-2.5.5/drivers/input/joystick/db9.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/input/joystick/db9.c Fri Mar 1 14:46:55 2002 @@ -1,12 +1,10 @@ /* - * $Id: db9.c,v 1.6 2000/06/25 10:57:50 vojtech Exp $ + * $Id: db9.c,v 1.12 2002/01/22 20:27:05 vojtech Exp $ * - * Copyright (c) 1999 Vojtech Pavlik + * Copyright (c) 1999-2001 Vojtech Pavlik * * Based on the work of: * Andree Borrmann Mats Sjövall - * - * Sponsored by SuSE */ /* @@ -29,8 +27,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -40,8 +38,10 @@ #include #include -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver"); MODULE_LICENSE("GPL"); + MODULE_PARM(db9, "2i"); MODULE_PARM(db9_2, "2i"); MODULE_PARM(db9_3, "2i"); @@ -87,6 +87,7 @@ struct pardevice *pd; int mode; int used; + char phys[2][32]; }; static struct db9 *db9_base[3]; @@ -342,11 +343,14 @@ for (i = 0; i < 1 + (db9->mode == DB9_MULTI_0802_2); i++) { + sprintf(db9->phys[i], "%s/input%d", db9->pd->port->name, i); + db9->dev[i].private = db9; db9->dev[i].open = db9_open; db9->dev[i].close = db9_close; db9->dev[i].name = db9_name[db9->mode]; + db9->dev[i].phys = db9->phys[i]; db9->dev[i].idbus = BUS_PARPORT; db9->dev[i].idvendor = 0x0002; db9->dev[i].idproduct = config[1]; @@ -362,8 +366,7 @@ db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1; input_register_device(db9->dev + i); - printk(KERN_INFO "input%d: %s on %s\n", - db9->dev[i].number, db9_name[db9->mode], db9->pd->port->name); + printk(KERN_INFO "input: %s on %s\n", db9->dev[i].name, db9->pd->port->name); } return db9; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/gamecon.c linux-2.5/drivers/input/joystick/gamecon.c --- linux-2.5.5/drivers/input/joystick/gamecon.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/input/joystick/gamecon.c Fri Mar 1 14:47:12 2002 @@ -1,17 +1,15 @@ /* - * $Id: gamecon.c,v 1.14 2001/04/29 22:42:14 vojtech Exp $ + * $Id: gamecon.c,v 1.21 2002/01/22 20:27:27 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik * * Based on the work of: * Andree Borrmann John Dahlstrom * David Kuder Nathan Hand - * - * Sponsored by SuSE */ /* - * NES, SNES, N64, Multi1, Multi2, PSX gamepad driver for Linux + * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux */ /* @@ -30,8 +28,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -41,8 +39,10 @@ #include #include -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver"); MODULE_LICENSE("GPL"); + MODULE_PARM(gc, "2-6i"); MODULE_PARM(gc_2,"2-6i"); MODULE_PARM(gc_3,"2-6i"); @@ -65,6 +65,7 @@ struct timer_list timer; unsigned char pads[GC_MAX + 1]; int used; + char phys[5][32]; }; static struct gc *gc_base[3]; @@ -585,12 +586,15 @@ default: gc->pads[GC_PSX] &= ~gc_status_bit[i]; printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x," - " please report to .\n", psx); + " please report to .\n", psx); } break; } + sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i); + gc->dev[i].name = gc_names[config[i + 1]]; + gc->dev[i].phys = gc->phys[i]; gc->dev[i].idbus = BUS_PARPORT; gc->dev[i].idvendor = 0x0001; gc->dev[i].idproduct = config[i + 1]; @@ -608,7 +612,7 @@ for (i = 0; i < 5; i++) if (gc->pads[0] & gc_status_bit[i]) { input_register_device(gc->dev + i); - printk(KERN_INFO "input%d: %s on %s\n", gc->dev[i].number, gc->dev[i].name, gc->pd->port->name); + printk(KERN_INFO "input: %s on %s\n", gc->dev[i].name, gc->pd->port->name); } return gc; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/gf2k.c linux-2.5/drivers/input/joystick/gf2k.c --- linux-2.5.5/drivers/input/joystick/gf2k.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/input/joystick/gf2k.c Fri Mar 1 14:47:37 2002 @@ -1,9 +1,7 @@ /* - * $Id: gf2k.c,v 1.12 2000/06/04 14:53:44 vojtech Exp $ + * $Id: gf2k.c,v 1.19 2002/01/22 20:27:43 vojtech Exp $ * - * Copyright (c) 1998-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1998-2001 Vojtech Pavlik */ /* @@ -26,8 +24,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -38,6 +36,10 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Genius Flight 2000 joystick driver"); +MODULE_LICENSE("GPL"); + #define GF2K_START 400 /* The time we wait for the first bit [400 us] */ #define GF2K_STROBE 40 /* The time we wait for the first bit [40 us] */ #define GF2K_TIMEOUT 4 /* Wait for everything to settle [4 ms] */ @@ -85,6 +87,7 @@ int used; unsigned char id; unsigned char length; + char phys[32]; }; /* @@ -278,11 +281,13 @@ #endif if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) { - printk(KERN_WARNING "gf2k.c: Not yet supported joystick on gameport%d. [id: %d type:%s]\n", - gameport->number, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]); + printk(KERN_WARNING "gf2k.c: Not yet supported joystick on %s. [id: %d type:%s]\n", + gameport->phys, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]); goto fail2; } + sprintf(gf2k->phys, "%s/input0", gameport->phys); + gf2k->length = gf2k_lens[gf2k->id]; gf2k->dev.private = gf2k; @@ -291,6 +296,7 @@ gf2k->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); gf2k->dev.name = gf2k_names[gf2k->id]; + gf2k->dev.phys = gf2k->phys; gf2k->dev.idbus = BUS_GAMEPORT; gf2k->dev.idvendor = GAMEPORT_ID_VENDOR_GENIUS; gf2k->dev.idproduct = gf2k->id; @@ -323,8 +329,7 @@ } input_register_device(&gf2k->dev); - printk(KERN_INFO "input%d: %s on gameport%d.0\n", - gf2k->dev.number, gf2k_names[gf2k->id], gameport->number); + printk(KERN_INFO "input: %s on %s\n", gf2k_names[gf2k->id], gameport->phys); return; fail2: gameport_close(gameport); @@ -357,5 +362,3 @@ module_init(gf2k_init); module_exit(gf2k_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/grip.c linux-2.5/drivers/input/joystick/grip.c --- linux-2.5.5/drivers/input/joystick/grip.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/input/joystick/grip.c Fri Mar 1 14:47:59 2002 @@ -1,9 +1,7 @@ /* - * $Id: grip.c,v 1.14 2000/06/06 21:13:36 vojtech Exp $ + * $Id: grip.c,v 1.21 2002/01/22 20:27:57 vojtech Exp $ * - * Copyright (c) 1998-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1998-2001 Vojtech Pavlik */ /* @@ -26,8 +24,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -37,6 +35,10 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Gravis GrIP protocol joystick driver"); +MODULE_LICENSE("GPL"); + #define GRIP_MODE_GPP 1 #define GRIP_MODE_BD 2 #define GRIP_MODE_XT 3 @@ -59,6 +61,7 @@ int used; int reads; int bads; + char phys[2][32]; }; static int grip_btn_gpp[] = { BTN_START, BTN_SELECT, BTN_TR2, BTN_Y, 0, BTN_TL2, BTN_A, BTN_B, BTN_X, 0, BTN_TL, BTN_TR, -1 }; @@ -340,12 +343,15 @@ for (i = 0; i < 2; i++) if (grip->mode[i]) { + sprintf(grip->phys[i], "%s/input%d", gameport->phys, i); + grip->dev[i].private = grip; grip->dev[i].open = grip_open; grip->dev[i].close = grip_close; grip->dev[i].name = grip_name[grip->mode[i]]; + grip->dev[i].phys = grip->phys[i]; grip->dev[i].idbus = BUS_GAMEPORT; grip->dev[i].idvendor = GAMEPORT_ID_VENDOR_GRAVIS; grip->dev[i].idproduct = grip->mode[i]; @@ -382,8 +388,8 @@ input_register_device(grip->dev + i); - printk(KERN_INFO "input%d: %s on gameport%d.%d\n", - grip->dev[i].number, grip_name[grip->mode[i]], gameport->number, i); + printk(KERN_INFO "input: %s on %s\n", + grip_name[grip->mode[i]], gameport->phys); } return; @@ -421,5 +427,3 @@ module_init(grip_init); module_exit(grip_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/guillemot.c linux-2.5/drivers/input/joystick/guillemot.c --- linux-2.5.5/drivers/input/joystick/guillemot.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/joystick/guillemot.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,285 @@ +/* + * $Id: guillemot.c,v 1.9 2001/12/10 17:01:44 vojtech Exp $ + * + * Copyright (c) 2001 Vojtech Pavlik + */ + +/* + * Guillemot Digital Interface Protocol driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Guillemot Digital joystick driver"); +MODULE_LICENSE("GPL"); + +#define GUILLEMOT_MAX_START 600 /* 600 us */ +#define GUILLEMOT_MAX_STROBE 60 /* 60 us */ +#define GUILLEMOT_MAX_LENGTH 17 /* 17 bytes */ +#define GUILLEMOT_REFRESH_TIME HZ/50 /* 20 ms */ + +static short guillemot_abs_pad[] = + { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 }; + +static short guillemot_btn_pad[] = + { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_MODE, BTN_SELECT, -1 }; + +static struct { + int x; + int y; +} guillemot_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; + +struct guillemot_type { + unsigned char id; + short *abs; + short *btn; + int hat; + char *name; +}; + +struct guillemot { + struct gameport *gameport; + struct input_dev dev; + struct timer_list timer; + int used; + int bads; + int reads; + struct guillemot_type *type; + unsigned char length; + char phys[32]; +}; + +static struct guillemot_type guillemot_type[] = { + { 0x00, guillemot_abs_pad, guillemot_btn_pad, 1, "Guillemot Pad" }, + { 0 }}; + +/* + * guillemot_read_packet() reads Guillemot joystick data. + */ + +static int guillemot_read_packet(struct gameport *gameport, u8 *data) +{ + unsigned long flags; + unsigned char u, v; + unsigned int t, s; + int i; + + for (i = 0; i < GUILLEMOT_MAX_LENGTH; i++) + data[i] = 0; + + i = 0; + t = gameport_time(gameport, GUILLEMOT_MAX_START); + s = gameport_time(gameport, GUILLEMOT_MAX_STROBE); + + __save_flags(flags); + __cli(); + gameport_trigger(gameport); + v = gameport_read(gameport); + + while (t > 0 && i < GUILLEMOT_MAX_LENGTH * 8) { + t--; + u = v; v = gameport_read(gameport); + if (v & ~u & 0x10) { + data[i >> 3] |= ((v >> 5) & 1) << (i & 7); + i++; + t = s; + } + } + + __restore_flags(flags); + + return i; +} + +/* + * guillemot_timer() reads and analyzes Guillemot joystick data. + */ + +static void guillemot_timer(unsigned long private) +{ + struct guillemot *guillemot = (struct guillemot *) private; + struct input_dev *dev = &guillemot->dev; + u8 data[GUILLEMOT_MAX_LENGTH]; + int i; + + guillemot->reads++; + + if (guillemot_read_packet(guillemot->gameport, data) != GUILLEMOT_MAX_LENGTH * 8 || + data[0] != 0x55 || data[16] != 0xaa) { + guillemot->bads++; + } else { + + for (i = 0; i < 6 && guillemot->type->abs[i] >= 0; i++) + input_report_abs(dev, guillemot->type->abs[i], data[i + 5]); + + if (guillemot->type->hat) { + input_report_abs(dev, ABS_HAT0X, guillemot_hat_to_axis[data[4] >> 4].x); + input_report_abs(dev, ABS_HAT0Y, guillemot_hat_to_axis[data[4] >> 4].y); + } + + for (i = 0; i < 16 && guillemot->type->btn[i] >= 0; i++) + input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1); + } + + mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME); +} + +/* + * guillemot_open() is a callback from the input open routine. + */ + +static int guillemot_open(struct input_dev *dev) +{ + struct guillemot *guillemot = dev->private; + if (!guillemot->used++) + mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME); + return 0; +} + +/* + * guillemot_close() is a callback from the input close routine. + */ + +static void guillemot_close(struct input_dev *dev) +{ + struct guillemot *guillemot = dev->private; + if (!--guillemot->used) + del_timer(&guillemot->timer); +} + +/* + * guillemot_connect() probes for Guillemot joysticks. + */ + +static void guillemot_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct guillemot *guillemot; + u8 data[GUILLEMOT_MAX_LENGTH]; + int i, t; + + if (!(guillemot = kmalloc(sizeof(struct guillemot), GFP_KERNEL))) + return; + memset(guillemot, 0, sizeof(struct guillemot)); + + gameport->private = guillemot; + + guillemot->gameport = gameport; + init_timer(&guillemot->timer); + guillemot->timer.data = (long) guillemot; + guillemot->timer.function = guillemot_timer; + + if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) + goto fail1; + + i = guillemot_read_packet(gameport, data); + + if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa) + goto fail2; + + for (i = 0; guillemot_type[i].name; i++) + if (guillemot_type[i].id == data[11]) + break; + + if (!guillemot_type[i].name) { + printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n", + gameport->phys, data[12], data[13], data[11], data[14], data[15]); + goto fail2; + } + + sprintf(guillemot->phys, "%s/input0", gameport->phys); + + guillemot->type = guillemot_type + i; + + guillemot->dev.private = guillemot; + guillemot->dev.open = guillemot_open; + guillemot->dev.close = guillemot_close; + + guillemot->dev.name = guillemot_type[i].name; + guillemot->dev.phys = guillemot->phys; + guillemot->dev.idbus = BUS_GAMEPORT; + guillemot->dev.idvendor = GAMEPORT_ID_VENDOR_GUILLEMOT; + guillemot->dev.idproduct = guillemot_type[i].id; + guillemot->dev.idversion = (int)data[14] << 8 | data[15]; + + guillemot->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) { + set_bit(t, guillemot->dev.absbit); + guillemot->dev.absmin[t] = 0; + guillemot->dev.absmax[t] = 255; + } + + if (guillemot->type->hat) + for (i = 0; i < 2; i++) { + t = ABS_HAT0X + i; + set_bit(t, guillemot->dev.absbit); + guillemot->dev.absmin[t] = -1; + guillemot->dev.absmax[t] = 1; + } + + for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++) + set_bit(t, guillemot->dev.keybit); + + input_register_device(&guillemot->dev); + printk(KERN_INFO "input: %s ver %d.%02d on %s\n", + guillemot->type->name, data[14], data[15], gameport->phys); + + return; +fail2: gameport_close(gameport); +fail1: kfree(guillemot); +} + +static void guillemot_disconnect(struct gameport *gameport) +{ + struct guillemot *guillemot = gameport->private; + printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys); + input_unregister_device(&guillemot->dev); + gameport_close(gameport); + kfree(guillemot); +} + +static struct gameport_dev guillemot_dev = { + connect: guillemot_connect, + disconnect: guillemot_disconnect, +}; + +int __init guillemot_init(void) +{ + gameport_register_device(&guillemot_dev); + return 0; +} + +void __exit guillemot_exit(void) +{ + gameport_unregister_device(&guillemot_dev); +} + +module_init(guillemot_init); +module_exit(guillemot_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/iforce/Makefile linux-2.5/drivers/input/joystick/iforce/Makefile --- linux-2.5.5/drivers/input/joystick/iforce/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/Makefile Sun Feb 3 18:03:58 2002 @@ -0,0 +1,41 @@ +# +# Makefile for the I-Force driver +# + +O_TARGET := iforce-drv.o + +# I-Force may need both USB and RS-232 + +CONFIG_JOYSTICK_IFORCE := n + +ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) + ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y) + CONFIG_JOYSTICK_IFORCE := y + endif +endif + +ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m) + CONFIG_JOYSTICK_IFORCE := m +endif + +ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m) + CONFIG_JOYSTICK_IFORCE := m +endif + +obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o + +include $(TOPDIR)/Rules.make + +IFORCEOBJS = iforce-ff.o iforce-main.o iforce-packets.o + +ifneq ($(CONFIG_JOYSTICK_IFORCE_232),) + IFORCEOBJS += iforce-serio.o +endif + +ifneq ($(CONFIG_JOYSTICK_IFORCE_USB),) + IFORCEOBJS += iforce-usb.o +endif + +iforce.o: $(IFORCEOBJS) + $(LD) -i $(IFORCEOBJS) -o $@ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/iforce/iforce-ff.c linux-2.5/drivers/input/joystick/iforce/iforce-ff.c --- linux-2.5.5/drivers/input/joystick/iforce/iforce-ff.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce-ff.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,563 @@ +/* + * $Id: iforce-ff.c,v 1.6 2001/11/10 09:45:09 jdeneux Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +/* + * Set the magnitude of a constant force effect + * Return error code + * + * Note: caller must ensure exclusive access to device + */ + +static int make_magnitude_modifier(struct iforce* iforce, + struct resource* mod_chunk, int no_alloc, __s16 level) +{ + unsigned char data[3]; + + if (!no_alloc) { + down(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, + iforce->device_memory.start, iforce->device_memory.end, 2L, + NULL, NULL)) { + up(&iforce->mem_mutex); + return -ENOMEM; + } + up(&iforce->mem_mutex); + } + + data[0] = LO(mod_chunk->start); + data[1] = HI(mod_chunk->start); + data[2] = HIFIX80(level); + + iforce_send_packet(iforce, FF_CMD_MAGNITUDE, data); + + iforce_dump_packet("magnitude: ", FF_CMD_MAGNITUDE, data); + return 0; +} + +/* + * Upload the component of an effect dealing with the period, phase and magnitude + */ + +static int make_period_modifier(struct iforce* iforce, + struct resource* mod_chunk, int no_alloc, + __s16 magnitude, __s16 offset, u16 period, u16 phase) +{ + unsigned char data[7]; + + period = TIME_SCALE(period); + + if (!no_alloc) { + down(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, + iforce->device_memory.start, iforce->device_memory.end, 2L, + NULL, NULL)) { + up(&iforce->mem_mutex); + return -ENOMEM; + } + up(&iforce->mem_mutex); + } + + data[0] = LO(mod_chunk->start); + data[1] = HI(mod_chunk->start); + + data[2] = HIFIX80(magnitude); + data[3] = HIFIX80(offset); + data[4] = HI(phase); + + data[5] = LO(period); + data[6] = HI(period); + + iforce_send_packet(iforce, FF_CMD_PERIOD, data); + + return 0; +} + +/* + * Uploads the part of an effect setting the shape of the force + */ + +static int make_shape_modifier(struct iforce* iforce, + struct resource* mod_chunk, int no_alloc, + u16 attack_duration, __s16 initial_level, + u16 fade_duration, __s16 final_level) +{ + unsigned char data[8]; + + attack_duration = TIME_SCALE(attack_duration); + fade_duration = TIME_SCALE(fade_duration); + + if (!no_alloc) { + down(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, + iforce->device_memory.start, iforce->device_memory.end, 2L, + NULL, NULL)) { + up(&iforce->mem_mutex); + return -ENOMEM; + } + up(&iforce->mem_mutex); + } + + data[0] = LO(mod_chunk->start); + data[1] = HI(mod_chunk->start); + + data[2] = LO(attack_duration); + data[3] = HI(attack_duration); + data[4] = HI(initial_level); + + data[5] = LO(fade_duration); + data[6] = HI(fade_duration); + data[7] = HI(final_level); + + iforce_send_packet(iforce, FF_CMD_SHAPE, data); + + return 0; +} + +/* + * Component of spring, friction, inertia... effects + */ + +static int make_interactive_modifier(struct iforce* iforce, + struct resource* mod_chunk, int no_alloc, + __u16 rsat, __u16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center) +{ + unsigned char data[10]; + + if (!no_alloc) { + down(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, + iforce->device_memory.start, iforce->device_memory.end, 2L, + NULL, NULL)) { + up(&iforce->mem_mutex); + return -ENOMEM; + } + up(&iforce->mem_mutex); + } + + data[0] = LO(mod_chunk->start); + data[1] = HI(mod_chunk->start); + + data[2] = (100*rk)>>15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ + data[3] = (100*lk)>>15; /* This code is incorrect on cpus lacking arith shift */ + + center = (500*center)>>15; + data[4] = LO(center); + data[5] = HI(center); + + db = (1000*db)>>16; + data[6] = LO(db); + data[7] = HI(db); + + data[8] = (100*rsat)>>16; + data[9] = (100*lsat)>>16; + + iforce_send_packet(iforce, FF_CMD_INTERACT, data); + iforce_dump_packet("interactive", FF_CMD_INTERACT, data); + + return 0; +} + +static unsigned char find_button(struct iforce *iforce, signed short button) +{ + int i; + for (i = 1; iforce->type->btn[i] >= 0; i++) + if (iforce->type->btn[i] == button) + return i + 1; + return 0; +} + +/* + * Analyse the changes in an effect, and tell if we need to send an interactive + * parameter packet + */ +static int need_interactive_modifier(struct iforce* iforce, struct ff_effect* new) +{ + int id = new->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + if (new->type != FF_SPRING && new->type != FF_FRICTION) { + printk(KERN_WARNING "iforce.c: bad effect type in need_interactive_modifier\n"); + return FALSE; + } + + return (old->u.interactive.right_saturation != new->u.interactive.right_saturation + || old->u.interactive.left_saturation != new->u.interactive.left_saturation + || old->u.interactive.right_coeff != new->u.interactive.right_coeff + || old->u.interactive.left_coeff != new->u.interactive.left_coeff + || old->u.interactive.deadband != new->u.interactive.deadband + || old->u.interactive.center != new->u.interactive.center); +} + +/* + * Analyse the changes in an effect, and tell if we need to send a magnitude + * parameter packet + */ +static int need_magnitude_modifier(struct iforce* iforce, struct ff_effect* effect) +{ + int id = effect->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + if (effect->type != FF_CONSTANT) { + printk(KERN_WARNING "iforce.c: bad effect type in need_shape_modifier\n"); + return FALSE; + } + + return (old->u.constant.level != effect->u.constant.level); +} + +/* + * Analyse the changes in an effect, and tell if we need to send a shape + * parameter packet + */ +static int need_shape_modifier(struct iforce* iforce, struct ff_effect* effect) +{ + int id = effect->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + switch (effect->type) { + case FF_CONSTANT: + if (old->u.constant.shape.attack_length != effect->u.constant.shape.attack_length + || old->u.constant.shape.attack_level != effect->u.constant.shape.attack_level + || old->u.constant.shape.fade_length != effect->u.constant.shape.fade_length + || old->u.constant.shape.fade_level != effect->u.constant.shape.fade_level) + return TRUE; + break; + + case FF_PERIODIC: + if (old->u.periodic.shape.attack_length != effect->u.periodic.shape.attack_length + || old->u.periodic.shape.attack_level != effect->u.periodic.shape.attack_level + || old->u.periodic.shape.fade_length != effect->u.periodic.shape.fade_length + || old->u.periodic.shape.fade_level != effect->u.periodic.shape.fade_level) + return TRUE; + break; + + default: + printk(KERN_WARNING "iforce.c: bad effect type in need_shape_modifier\n"); + } + + return FALSE; +} + +/* + * Analyse the changes in an effect, and tell if we need to send a periodic + * parameter effect + */ +static int need_period_modifier(struct iforce* iforce, struct ff_effect* new) +{ + int id = new->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + if (new->type != FF_PERIODIC) { + printk(KERN_WARNING "iforce.c: bad effect type in need_periodic_modifier\n"); + return FALSE; + } + + return (old->u.periodic.period != new->u.periodic.period + || old->u.periodic.magnitude != new->u.periodic.magnitude + || old->u.periodic.offset != new->u.periodic.offset + || old->u.periodic.phase != new->u.periodic.phase); +} + +/* + * Analyse the changes in an effect, and tell if we need to send an effect + * packet + */ +static int need_core(struct iforce* iforce, struct ff_effect* new) +{ + int id = new->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + if (old->direction != new->direction + || old->trigger.button != new->trigger.button + || old->trigger.interval != new->trigger.interval + || old->replay.length != new->replay.length + || old->replay.delay != new->replay.delay) + return TRUE; + + return FALSE; +} +/* + * Send the part common to all effects to the device + */ +static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, + u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button, + u16 interval, u16 direction) +{ + unsigned char data[14]; + + duration = TIME_SCALE(duration); + delay = TIME_SCALE(delay); + interval = TIME_SCALE(interval); + + data[0] = LO(id); + data[1] = effect_type; + data[2] = LO(axes) | find_button(iforce, button); + + data[3] = LO(duration); + data[4] = HI(duration); + + data[5] = HI(direction); + + data[6] = LO(interval); + data[7] = HI(interval); + + data[8] = LO(mod_id1); + data[9] = HI(mod_id1); + data[10] = LO(mod_id2); + data[11] = HI(mod_id2); + + data[12] = LO(delay); + data[13] = HI(delay); + + /* Stop effect */ +/* iforce_control_playback(iforce, id, 0);*/ + + iforce_send_packet(iforce, FF_CMD_EFFECT, data); + + /* If needed, restart effect */ + if (test_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[id].flags)) { + /* BUG: perhaps we should replay n times, instead of 1. But we do not know n */ + iforce_control_playback(iforce, id, 1); + } + + return 0; +} + +/* + * Upload a periodic effect to the device + * See also iforce_upload_constant. + */ +int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int is_update) +{ + u8 wave_code; + int core_id = effect->id; + struct iforce_core_effect* core_effect = iforce->core_effects + core_id; + struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); + struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); + int param1_err = 1; + int param2_err = 1; + int core_err = 0; + + if (!is_update || need_period_modifier(iforce, effect)) { + param1_err = make_period_modifier(iforce, mod1_chunk, + is_update, + effect->u.periodic.magnitude, effect->u.periodic.offset, + effect->u.periodic.period, effect->u.periodic.phase); + if (param1_err) return param1_err; + set_bit(FF_MOD1_IS_USED, core_effect->flags); + } + + if (!is_update || need_shape_modifier(iforce, effect)) { + param2_err = make_shape_modifier(iforce, mod2_chunk, + is_update, + effect->u.periodic.shape.attack_length, + effect->u.periodic.shape.attack_level, + effect->u.periodic.shape.fade_length, + effect->u.periodic.shape.fade_level); + if (param2_err) return param2_err; + set_bit(FF_MOD2_IS_USED, core_effect->flags); + } + + switch (effect->u.periodic.waveform) { + case FF_SQUARE: wave_code = 0x20; break; + case FF_TRIANGLE: wave_code = 0x21; break; + case FF_SINE: wave_code = 0x22; break; + case FF_SAW_UP: wave_code = 0x23; break; + case FF_SAW_DOWN: wave_code = 0x24; break; + default: wave_code = 0x20; break; + } + + if (!is_update || need_core(iforce, effect)) { + core_err = make_core(iforce, effect->id, + mod1_chunk->start, + mod2_chunk->start, + wave_code, + 0x20, + effect->replay.length, + effect->replay.delay, + effect->trigger.button, + effect->trigger.interval, + effect->direction); + } + + /* If one of the parameter creation failed, we already returned an + * error code. + * If the core creation failed, we return its error code. + * Else: if one parameter at least was created, we return 0 + * else we return 1; + */ + return core_err < 0 ? core_err : (param1_err && param2_err); +} + +/* + * Upload a constant force effect + * Return value: + * <0 Error code + * 0 Ok, effect created or updated + * 1 effect did not change since last upload, and no packet was therefore sent + */ +int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int is_update) +{ + int core_id = effect->id; + struct iforce_core_effect* core_effect = iforce->core_effects + core_id; + struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); + struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); + int param1_err = 1; + int param2_err = 1; + int core_err = 0; + + if (!is_update || need_magnitude_modifier(iforce, effect)) { + param1_err = make_magnitude_modifier(iforce, mod1_chunk, + is_update, + effect->u.constant.level); + if (param1_err) return param1_err; + set_bit(FF_MOD1_IS_USED, core_effect->flags); + } + + if (!is_update || need_shape_modifier(iforce, effect)) { + param2_err = make_shape_modifier(iforce, mod2_chunk, + is_update, + effect->u.constant.shape.attack_length, + effect->u.constant.shape.attack_level, + effect->u.constant.shape.fade_length, + effect->u.constant.shape.fade_level); + if (param2_err) return param2_err; + set_bit(FF_MOD2_IS_USED, core_effect->flags); + } + + if (!is_update || need_core(iforce, effect)) { + core_err = make_core(iforce, effect->id, + mod1_chunk->start, + mod2_chunk->start, + 0x00, + 0x20, + effect->replay.length, + effect->replay.delay, + effect->trigger.button, + effect->trigger.interval, + effect->direction); + } + + /* If one of the parameter creation failed, we already returned an + * error code. + * If the core creation failed, we return its error code. + * Else: if one parameter at least was created, we return 0 + * else we return 1; + */ + return core_err < 0 ? core_err : (param1_err && param2_err); +} + +/* + * Upload an interactive effect. Those are for example friction, inertia, springs... + */ +int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* effect, int is_update) +{ + int core_id = effect->id; + struct iforce_core_effect* core_effect = iforce->core_effects + core_id; + struct resource* mod_chunk = &(core_effect->mod1_chunk); + u8 type, axes; + u16 mod1, mod2, direction; + int param_err = 1; + int core_err = 0; + + switch (effect->type) { + case FF_SPRING: type = 0x40; break; + case FF_FRICTION: type = 0x41; break; + default: return -1; + } + + if (!is_update || need_interactive_modifier(iforce, effect)) { + param_err = make_interactive_modifier(iforce, mod_chunk, + is_update, + effect->u.interactive.right_saturation, + effect->u.interactive.left_saturation, + effect->u.interactive.right_coeff, + effect->u.interactive.left_coeff, + effect->u.interactive.deadband, + effect->u.interactive.center); + if (param_err) return param_err; + set_bit(FF_MOD1_IS_USED, core_effect->flags); + } + + switch ((test_bit(ABS_X, &effect->u.interactive.axis) || + test_bit(ABS_WHEEL, &effect->u.interactive.axis)) | + (!!test_bit(ABS_Y, &effect->u.interactive.axis) << 1)) { + + case 0: /* Only one axis, choose orientation */ + mod1 = mod_chunk->start; + mod2 = 0xffff; + direction = effect->direction; + axes = 0x20; + break; + + case 1: /* Only X axis */ + mod1 = mod_chunk->start; + mod2 = 0xffff; + direction = 0x5a00; + axes = 0x40; + break; + + case 2: /* Only Y axis */ + mod1 = 0xffff; + mod2 = mod_chunk->start; + direction = 0xb400; + axes = 0x80; + break; + + case 3: /* Both X and Y axes */ + /* TODO: same setting for both axes is not mandatory */ + mod1 = mod_chunk->start; + mod2 = mod_chunk->start; + direction = 0x6000; + axes = 0xc0; + break; + + default: + return -1; + } + + if (!is_update || need_core(iforce, effect)) { + core_err = make_core(iforce, effect->id, + mod1, mod2, + type, axes, + effect->replay.length, effect->replay.delay, + effect->trigger.button, effect->trigger.interval, + direction); + } + + /* If the parameter creation failed, we already returned an + * error code. + * If the core creation failed, we return its error code. + * Else: if a parameter was created, we return 0 + * else we return 1; + */ + return core_err < 0 ? core_err : param_err; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/iforce/iforce-main.c linux-2.5/drivers/input/joystick/iforce/iforce-main.c --- linux-2.5.5/drivers/input/joystick/iforce/iforce-main.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce-main.c Fri Feb 8 11:04:26 2002 @@ -0,0 +1,494 @@ +/* + * $Id: iforce-main.c,v 1.5 2001/11/10 09:46:19 jdeneux Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +MODULE_AUTHOR("Vojtech Pavlik , Johann Deneux "); +MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); +MODULE_LICENSE("GPL"); + +static signed short btn_joystick[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, + BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 }; +static signed short btn_wheel[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, + BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; +static signed short btn_avb_tw[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, + BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 }; +static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; +static signed short abs_joystick2[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_HAT0X, ABS_HAT0Y, -1 }; +static signed short abs_wheel[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 }; +static signed short ff_iforce[] = { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION, + FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, FF_AUTOCENTER, -1 }; + +static struct iforce_device iforce_device[] = { + { 0x044f, 0xa01c, "Thrustmaster Motor Sport GT", btn_wheel, abs_wheel, ff_iforce }, + { 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce }, + { 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce }, + { 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_joystick, abs_joystick2, ff_iforce }, + { 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_wheel, abs_wheel, ff_iforce }, + { 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_avb_tw, abs_wheel, ff_iforce }, + { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, + { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, + { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } +}; + + + +static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct iforce* iforce = (struct iforce*)(dev->private); + unsigned char data[3]; + + printk(KERN_DEBUG "iforce.c: input_event(type = %d, code = %d, value = %d)\n", type, code, value); + + if (type != EV_FF) + return -1; + + switch (code) { + + case FF_GAIN: + + data[0] = value >> 9; + iforce_send_packet(iforce, FF_CMD_GAIN, data); + + return 0; + + case FF_AUTOCENTER: + + data[0] = 0x03; + data[1] = value >> 9; + iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); + + data[0] = 0x04; + data[1] = 0x01; + iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); + + return 0; + + default: /* Play or stop an effect */ + + if (!CHECK_OWNERSHIP(code, iforce)) { + return -1; + } + if (value > 0) { + set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); + } + else { + clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); + } + + iforce_control_playback(iforce, code, value); + return 0; + } + + return -1; +} + +/* + * Function called when an ioctl is performed on the event dev entry. + * It uploads an effect to the device + */ +static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) +{ + struct iforce* iforce = (struct iforce*)(dev->private); + int id; + int ret; + int is_update; + +/* + * If we want to create a new effect, get a free id + */ + if (effect->id == -1) { + + for (id=0; id < FF_EFFECTS_MAX; ++id) + if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break; + + if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max) + return -ENOMEM; + + effect->id = id; + iforce->core_effects[id].owner = current->pid; + iforce->core_effects[id].flags[0] = (1<id, iforce)) return -EACCES; + + /* Parameter type cannot be updated */ + if (effect->type != iforce->core_effects[effect->id].effect.type) + return -EINVAL; + + /* Check the effect is not already being updated */ + if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) { + return -EAGAIN; + } + + is_update = TRUE; + } + +/* + * Upload the effect + */ + switch (effect->type) { + + case FF_PERIODIC: + ret = iforce_upload_periodic(iforce, effect, is_update); + break; + + case FF_CONSTANT: + ret = iforce_upload_constant(iforce, effect, is_update); + break; + + case FF_SPRING: + case FF_FRICTION: + ret = iforce_upload_interactive(iforce, effect, is_update); + break; + + default: + return -EINVAL; + } + if (ret == 0) { + /* A packet was sent, forbid new updates until we are notified + * that the packet was updated + */ + set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags); + } + iforce->core_effects[effect->id].effect = *effect; + return ret; +} + +/* + * Erases an effect: it frees the effect id and mark as unused the memory + * allocated for the parameters + */ +static int iforce_erase_effect(struct input_dev *dev, int effect_id) +{ + struct iforce* iforce = (struct iforce*)(dev->private); + int err = 0; + struct iforce_core_effect* core_effect; + + /* Check who is trying to erase this effect */ + if (iforce->core_effects[effect_id].owner != current->pid) { + printk(KERN_WARNING "iforce.c: %d tried to erase an effect belonging to %d\n", current->pid, iforce->core_effects[effect_id].owner); + return -EACCES; + } + + if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) + return -EINVAL; + + core_effect = iforce->core_effects + effect_id; + + if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) + err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk)); + + if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) + err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk)); + + /*TODO: remember to change that if more FF_MOD* bits are added */ + core_effect->flags[0] = 0; + + return err; +} + +static int iforce_open(struct input_dev *dev) +{ + struct iforce *iforce = dev->private; + + switch (iforce->bus) { +#ifdef IFORCE_USB + case IFORCE_USB: + if (iforce->open++) + break; + iforce->irq.dev = iforce->usbdev; + if (usb_submit_urb(&iforce->irq, GFP_KERNEL)) + return -EIO; + break; +#endif + } + + /* Enable force feedback */ + iforce_send_packet(iforce, FF_CMD_ENABLE, "\004"); + + return 0; +} + +static int iforce_flush(struct input_dev *dev, struct file *file) +{ + struct iforce *iforce = dev->private; + int i; + + /* Erase all effects this process owns */ + for (i=0; iff_effects_max; ++i) { + + if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && + current->pid == iforce->core_effects[i].owner) { + + /* Stop effect */ + input_report_ff(dev, i, 0); + + /* Free ressources assigned to effect */ + if (iforce_erase_effect(dev, i)) { + printk(KERN_WARNING "iforce_flush: (%s) erase effect %d failed\n", dev->phys, i); + } + } + + } + return 0; +} + +static void iforce_close(struct input_dev *dev) +{ + struct iforce *iforce = dev->private; + + printk(KERN_DEBUG "iforce.c: in iforce_close\n"); + + /* Disable force feedback playback */ + iforce_send_packet(iforce, FF_CMD_ENABLE, "\001"); + + + switch (iforce->bus) { +#ifdef IFORCE_USB + case IFORCE_USB: + if (!--iforce->open) + usb_unlink_urb(&iforce->irq); + break; +#endif + } +} + +int iforce_init_device(struct iforce *iforce) +{ + unsigned char c[] = "CEOV"; + char path[64]; + int i; + + init_waitqueue_head(&iforce->wait); + spin_lock_init(&iforce->xmit_lock); + init_MUTEX(&iforce->mem_mutex); + iforce->xmit.buf = iforce->xmit_data; + + iforce->dev.ff_effects_max = 10; + + switch (iforce->bus) { +#ifdef IFORCE_232 + case IFORCE_232: + strcpy(path, iforce->serio->phys); + break; +#endif +#ifdef IFORCE_USB + case IFORCE_USB: + usb_make_path(iforce->usbdev, path, 64); + break; +#endif + } + + sprintf(iforce->phys, "%s/input0", path); + +/* + * Input device fields. + */ + + iforce->dev.idbus = BUS_USB; + iforce->dev.private = iforce; + iforce->dev.name = iforce->phys; + iforce->dev.open = iforce_open; + iforce->dev.close = iforce_close; + iforce->dev.flush = iforce_flush; + iforce->dev.event = iforce_input_event; + iforce->dev.upload_effect = iforce_upload_effect; + iforce->dev.erase_effect = iforce_erase_effect; + +/* + * On-device memory allocation. + */ + + iforce->device_memory.name = "I-Force device effect memory"; + iforce->device_memory.start = 0; + iforce->device_memory.end = 200; + iforce->device_memory.flags = IORESOURCE_MEM; + iforce->device_memory.parent = NULL; + iforce->device_memory.child = NULL; + iforce->device_memory.sibling = NULL; + +/* + * Wait until device ready - until it sends its first response. + */ + + for (i = 0; i < 20; i++) + if (!iforce_get_id_packet(iforce, "O")) + break; + + if (i == 20) { /* 5 seconds */ + printk(KERN_ERR "iforce.c: Timeout waiting for response from device.\n"); + iforce_close(&iforce->dev); + return -1; + } + +/* + * Get device info. + */ + + if (!iforce_get_id_packet(iforce, "M")) + iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, "P")) + iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, "B")) + iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, "N")) + iforce->dev.ff_effects_max = iforce->edata[1]; + + /* Check if the device can store more effects than the driver can really handle */ + if (iforce->dev.ff_effects_max > FF_EFFECTS_MAX) { + printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.c\n", + iforce->dev.ff_effects_max, FF_EFFECTS_MAX); + iforce->dev.ff_effects_max = FF_EFFECTS_MAX; + } + +/* + * Display additional info. + */ + + for (i = 0; c[i]; i++) + if (!iforce_get_id_packet(iforce, c + i)) + iforce_dump_packet("info", iforce->ecmd, iforce->edata); + +/* + * Disable spring, enable force feedback. + * FIXME: We should use iforce_set_autocenter() et al here. + */ + + iforce_send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000"); + +/* + * Find appropriate device entry + */ + + for (i = 0; iforce_device[i].idvendor; i++) + if (iforce_device[i].idvendor == iforce->dev.idvendor && + iforce_device[i].idproduct == iforce->dev.idproduct) + break; + + iforce->type = iforce_device + i; + + sprintf(iforce->name, iforce->type->name, + iforce->dev.idproduct, iforce->dev.idvendor); + +/* + * Set input device bitfields and ranges. + */ + + iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); + + for (i = 0; iforce->type->btn[i] >= 0; i++) { + signed short t = iforce->type->btn[i]; + set_bit(t, iforce->dev.keybit); + if (t != BTN_DEAD) + set_bit(FF_BTN(t), iforce->dev.ffbit); + } + + for (i = 0; iforce->type->abs[i] >= 0; i++) { + + signed short t = iforce->type->abs[i]; + set_bit(t, iforce->dev.absbit); + + switch (t) { + + case ABS_X: + case ABS_Y: + case ABS_WHEEL: + + iforce->dev.absmax[t] = 1920; + iforce->dev.absmin[t] = -1920; + iforce->dev.absflat[t] = 128; + iforce->dev.absfuzz[t] = 16; + + set_bit(FF_ABS(t), iforce->dev.ffbit); + break; + + case ABS_THROTTLE: + case ABS_GAS: + case ABS_BRAKE: + + iforce->dev.absmax[t] = 255; + iforce->dev.absmin[t] = 0; + break; + + case ABS_RUDDER: + iforce->dev.absmax[t] = 127; + iforce->dev.absmin[t] = -128; + break; + + case ABS_HAT0X: + case ABS_HAT0Y: + iforce->dev.absmax[t] = 1; + iforce->dev.absmin[t] = -1; + break; + } + } + + for (i = 0; iforce->type->ff[i] >= 0; i++) + set_bit(iforce->type->ff[i], iforce->dev.ffbit); + +/* + * Register input device. + */ + + input_register_device(&iforce->dev); + + printk(KERN_INFO "input: %s [%d effects, %ld bytes memory] on %s\n", + iforce->dev.name, iforce->dev.ff_effects_max, + iforce->device_memory.end, path); + + return 0; +} + +static int __init iforce_init(void) +{ +#ifdef IFORCE_USB + usb_register(&iforce_usb_driver); +#endif +#ifdef IFORCE_232 + serio_register_device(&iforce_serio_dev); +#endif + return 0; +} + +static void __exit iforce_exit(void) +{ +#ifdef IFORCE_USB + usb_deregister(&iforce_usb_driver); +#endif +#ifdef IFORCE_232 + serio_unregister_device(&iforce_serio_dev); +#endif +} + +module_init(iforce_init); +module_exit(iforce_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/iforce/iforce-packets.c linux-2.5/drivers/input/joystick/iforce/iforce-packets.c --- linux-2.5.5/drivers/input/joystick/iforce/iforce-packets.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce-packets.c Fri Feb 8 11:41:51 2002 @@ -0,0 +1,289 @@ +/* + * $Id: iforce-packets.c,v 1.4 2001/10/28 19:10:24 jdeneux Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +static struct { + __s32 x; + __s32 y; +} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; + + +void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) +{ + int i; + + printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd); + for (i = 0; i < LO(cmd); i++) + printk("%02x ", data[i]); + printk(")\n"); +} + +/* + * Send a packet of bytes to the device + */ +int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) +{ + /* Copy data to buffer */ + int n = LO(cmd); + int c; + int empty; + int head, tail; + unsigned long flags; + +/* + * Update head and tail of xmit buffer + */ + spin_lock_irqsave(&iforce->xmit_lock, flags); + + head = iforce->xmit.head; + tail = iforce->xmit.tail; + + if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) { + printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n"); + spin_unlock_irqrestore(&iforce->xmit_lock, flags); + return -1; + } + + empty = head == tail; + XMIT_INC(iforce->xmit.head, n+2); + +/* + * Store packet in xmit buffer + */ + iforce->xmit.buf[head] = HI(cmd); + XMIT_INC(head, 1); + iforce->xmit.buf[head] = LO(cmd); + XMIT_INC(head, 1); + + c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE); + if (n < c) c=n; + + memcpy(&iforce->xmit.buf[head], + data, + c); + if (n != c) { + memcpy(&iforce->xmit.buf[0], + data + c, + n - c); + } + XMIT_INC(head, n); + + spin_unlock_irqrestore(&iforce->xmit_lock, flags); +/* + * If necessary, start the transmission + */ + switch (iforce->bus) { + +#ifdef IFORCE_232 + case IFORCE_232: + if (empty) + iforce_serial_xmit(iforce); + break; +#endif +#ifdef IFORCE_USB + case IFORCE_USB: + + if (empty & !iforce->out.status) { + iforce_usb_xmit(iforce); + } + break; +#endif + } + return 0; +} + +/* Start or stop an effect */ +int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value) +{ + unsigned char data[3]; + +printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value); + + data[0] = LO(id); + data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0; + data[2] = LO(value); + return iforce_send_packet(iforce, FF_CMD_PLAY, data); +} + +/* Mark an effect that was being updated as ready. That means it can be updated + * again */ +static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) +{ + int i; + for (i=0; idev.ff_effects_max; ++i) { + if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && + (iforce->core_effects[i].mod1_chunk.start == addr || + iforce->core_effects[i].mod2_chunk.start == addr)) { + clear_bit(FF_CORE_UPDATE, iforce->core_effects[i].flags); + return 0; + } + } + printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr); + return -1; +} + +void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) +{ + struct input_dev *dev = &iforce->dev; + int i; + static int being_used = 0; + + if (being_used) + printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used); + being_used++; + +#ifdef IFORCE_232 + if (HI(iforce->expect_packet) == HI(cmd)) { + iforce->expect_packet = 0; + iforce->ecmd = cmd; + memcpy(iforce->edata, data, IFORCE_MAX_LENGTH); + if (waitqueue_active(&iforce->wait)) + wake_up(&iforce->wait); + } +#endif + + if (!iforce->type) { + being_used--; + return; + } + + switch (HI(cmd)) { + + case 0x01: /* joystick position data */ + case 0x03: /* wheel position data */ + + if (HI(cmd) == 1) { + input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); + input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); + if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) + input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); + } else { + input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_GAS, 255 - data[2]); + input_report_abs(dev, ABS_BRAKE, 255 - data[3]); + } + + input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); + input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); + + for (i = 0; iforce->type->btn[i] >= 0; i++) + input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); + + break; + + case 0x02: /* status report */ + input_report_key(dev, BTN_DEAD, data[0] & 0x02); + + /* Check if an effect was just started or stopped */ + i = data[1] & 0x7f; + if (data[1] & 0x80) { + if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { + /* Report play event */ + input_report_ff_status(dev, i, FF_STATUS_PLAYING); + } + } + else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { + /* Report stop event */ + input_report_ff_status(dev, i, FF_STATUS_STOPPED); + } + if (LO(cmd) > 3) { + int j; + for (j=3; jbus) { + +#ifdef IFORCE_USB + case IFORCE_USB: + + iforce->cr.bRequest = packet[0]; + iforce->ctrl.dev = iforce->usbdev; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&iforce->wait, &wait); + + if (usb_submit_urb(&iforce->ctrl, GFP_KERNEL)) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&iforce->wait, &wait); + return -1; + } + + while (timeout && iforce->ctrl.status == -EINPROGRESS) + timeout = schedule_timeout(timeout); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&iforce->wait, &wait); + + if (!timeout) { + usb_unlink_urb(&iforce->ctrl); + return -1; + } + + break; +#endif +#ifdef IFORCE_232 + case IFORCE_232: + + iforce->expect_packet = FF_CMD_QUERY; + iforce_send_packet(iforce, FF_CMD_QUERY, packet); + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&iforce->wait, &wait); + + while (timeout && iforce->expect_packet) + timeout = schedule_timeout(timeout); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&iforce->wait, &wait); + + if (!timeout) { + iforce->expect_packet = 0; + return -1; + } + + break; +#endif + } + + return -(iforce->edata[0] != packet[0]); +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/iforce/iforce-serio.c linux-2.5/drivers/input/joystick/iforce/iforce-serio.c --- linux-2.5.5/drivers/input/joystick/iforce/iforce-serio.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce-serio.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,166 @@ +/* + * $Id: iforce-serio.c,v 1.2 2001/10/16 21:05:57 jdeneux Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +void iforce_serial_xmit(struct iforce *iforce) +{ + unsigned char cs; + int i; + unsigned long flags; + + if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { + set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags); + return; + } + + spin_lock_irqsave(&iforce->xmit_lock, flags); + +again: + if (iforce->xmit.head == iforce->xmit.tail) { + clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); + spin_unlock_irqrestore(&iforce->xmit_lock, flags); + return; + } + + cs = 0x2b; + + serio_write(iforce->serio, 0x2b); + + serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); + cs ^= iforce->xmit.buf[iforce->xmit.tail]; + XMIT_INC(iforce->xmit.tail, 1); + + for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { + serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); + cs ^= iforce->xmit.buf[iforce->xmit.tail]; + XMIT_INC(iforce->xmit.tail, 1); + } + + serio_write(iforce->serio, cs); + + if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) + goto again; + + clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); + + spin_unlock_irqrestore(&iforce->xmit_lock, flags); +} + +static void iforce_serio_write_wakeup(struct serio *serio) +{ + iforce_serial_xmit((struct iforce *)serio->private); +} + +static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct iforce* iforce = serio->private; + + if (!iforce->pkt) { + if (data != 0x2b) { + return; + } + iforce->pkt = 1; + return; + } + + if (!iforce->id) { + if (data > 3 && data != 0xff) { + iforce->pkt = 0; + return; + } + iforce->id = data; + return; + } + + if (!iforce->len) { + if (data > IFORCE_MAX_LENGTH) { + iforce->pkt = 0; + iforce->id = 0; + return; + } + iforce->len = data; + return; + } + + if (iforce->idx < iforce->len) { + iforce->csum += iforce->data[iforce->idx++] = data; + return; + } + + if (iforce->idx == iforce->len) { + iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); + iforce->pkt = 0; + iforce->id = 0; + iforce->len = 0; + iforce->idx = 0; + iforce->csum = 0; + } +} + +static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) +{ + struct iforce *iforce; + if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) + return; + + if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return; + memset(iforce, 0, sizeof(struct iforce)); + + iforce->bus = IFORCE_232; + iforce->serio = serio; + serio->private = iforce; + + if (serio_open(serio, dev)) { + kfree(iforce); + return; + } + + if (iforce_init_device(iforce)) { + serio_close(serio); + kfree(iforce); + return; + } +} + +static void iforce_serio_disconnect(struct serio *serio) +{ + struct iforce* iforce = serio->private; + + input_unregister_device(&iforce->dev); + serio_close(serio); + kfree(iforce); +} + +struct serio_dev iforce_serio_dev = { + write_wakeup: iforce_serio_write_wakeup, + interrupt: iforce_serio_irq, + connect: iforce_serio_connect, + disconnect: iforce_serio_disconnect, +}; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/iforce/iforce-usb.c linux-2.5/drivers/input/joystick/iforce/iforce-usb.c --- linux-2.5.5/drivers/input/joystick/iforce/iforce-usb.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce-usb.c Fri Feb 8 11:42:12 2002 @@ -0,0 +1,165 @@ +/* + * $Id: iforce-usb.c,v 1.3 2001/11/10 09:46:19 jdeneux Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +void iforce_usb_xmit(struct iforce *iforce) +{ + int n, c; + unsigned long flags; + + spin_lock_irqsave(&iforce->xmit_lock, flags); + + if (iforce->xmit.head == iforce->xmit.tail) { + spin_unlock_irqrestore(&iforce->xmit_lock, flags); + return; + } + + ((char *)iforce->out.transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail]; + XMIT_INC(iforce->xmit.tail, 1); + n = iforce->xmit.buf[iforce->xmit.tail]; + XMIT_INC(iforce->xmit.tail, 1); + + iforce->out.transfer_buffer_length = n + 2; + iforce->out.dev = iforce->usbdev; + + /* Copy rest of data then */ + c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE); + if (n < c) c=n; + + memcpy(iforce->out.transfer_buffer + 1, + &iforce->xmit.buf[iforce->xmit.tail], + c); + if (n != c) { + memcpy(iforce->out.transfer_buffer + 1 + c, + &iforce->xmit.buf[0], + n-c); + } + XMIT_INC(iforce->xmit.tail, n); + + if ( (n=usb_submit_urb(&iforce->out, GFP_KERNEL)) ) { + printk(KERN_WARNING "iforce.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n); + } + + spin_unlock_irqrestore(&iforce->xmit_lock, flags); +} + +static void iforce_usb_irq(struct urb *urb) +{ + struct iforce *iforce = urb->context; + if (urb->status) return; + iforce_process_packet(iforce, + (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1); +} + +static void iforce_usb_out(struct urb *urb) +{ + struct iforce *iforce = urb->context; + + if (urb->status) return; + + iforce_usb_xmit(iforce); + + if (waitqueue_active(&iforce->wait)) + wake_up(&iforce->wait); +} + +static void iforce_usb_ctrl(struct urb *urb) +{ + struct iforce *iforce = urb->context; + if (urb->status) return; + iforce->ecmd = 0xff00 | urb->actual_length; + if (waitqueue_active(&iforce->wait)) + wake_up(&iforce->wait); +} + +static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct usb_endpoint_descriptor *epirq, *epout; + struct iforce *iforce; + + epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; + epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1; + + if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL; + memset(iforce, 0, sizeof(struct iforce)); + + iforce->bus = IFORCE_USB; + iforce->usbdev = dev; + + iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; + iforce->cr.wIndex = 0; + iforce->cr.wLength = 16; + + FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), + iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); + + FILL_BULK_URB(&iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress), + iforce + 1, 32, iforce_usb_out, iforce); + + FILL_CONTROL_URB(&iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), + (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce); + + if (iforce_init_device(iforce)) { + kfree(iforce); + return NULL; + } + + return iforce; +} + +static void iforce_usb_disconnect(struct usb_device *dev, void *ptr) +{ + struct iforce *iforce = ptr; + usb_unlink_urb(&iforce->irq); + input_unregister_device(&iforce->dev); + kfree(iforce); +} + +static struct usb_device_id iforce_usb_ids [] = { + { USB_DEVICE(0x044f, 0xa01c) }, /* Thrustmaster Motor Sport GT */ + { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */ + { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */ + { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */ + { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */ + { USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */ + { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ + { USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */ + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, iforce_usb_ids); + +struct usb_driver iforce_usb_driver = { + name: "iforce", + probe: iforce_usb_probe, + disconnect: iforce_usb_disconnect, + id_table: iforce_usb_ids, +}; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/iforce/iforce.h linux-2.5/drivers/input/joystick/iforce/iforce.h --- linux-2.5.5/drivers/input/joystick/iforce/iforce.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/joystick/iforce/iforce.h Tue Feb 19 00:32:14 2002 @@ -0,0 +1,195 @@ +/* + * $Id: iforce.h,v 1.3 2001/10/23 21:20:54 jdeneux Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* FF: This module provides arbitrary resource management routines. + * I use it to manage the device's memory. + * Despite the name of this module, I am *not* going to access the ioports. + */ +#include + +#define IFORCE_MAX_LENGTH 16 + +#if defined(CONFIG_JOYSTICK_IFORCE_232) || defined(CONFIG_JOYSTICK_IFORCE_232_MODULE) +#define IFORCE_232 1 +#endif +#if defined(CONFIG_JOYSTICK_IFORCE_USB) || defined(CONFIG_JOYSTICK_IFORCE_USB_MODULE) +#define IFORCE_USB 2 +#endif + +#define FALSE 0 +#define TRUE 1 + +#define FF_EFFECTS_MAX 32 + +/* Each force feedback effect is made of one core effect, which can be + * associated to at most to effect modifiers + */ +#define FF_MOD1_IS_USED 0 +#define FF_MOD2_IS_USED 1 +#define FF_CORE_IS_USED 2 +#define FF_CORE_IS_PLAYED 3 /* Effect is actually being played */ +#define FF_CORE_SHOULD_PLAY 4 /* User wants the effect to be played */ +#define FF_CORE_UPDATE 5 /* Effect is being updated */ +#define FF_MODCORE_MAX 5 + +#define CHECK_OWNERSHIP(i, iforce) \ + ((i) < FF_EFFECTS_MAX && i >= 0 && \ + test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \ + (current->pid == 0 || \ + (iforce)->core_effects[(i)].owner == current->pid)) + +struct iforce_core_effect { + /* Information about where modifiers are stored in the device's memory */ + struct resource mod1_chunk; + struct resource mod2_chunk; + unsigned long flags[NBITS(FF_MODCORE_MAX)]; + pid_t owner; + /* Used to keep track of parameters of an effect. They are needed + * to know what parts of an effect changed in an update operation. + * We try to send only parameter packets if possible, as sending + * effect parameter requires the effect to be stoped and restarted + */ + struct ff_effect effect; +}; + +#define FF_CMD_EFFECT 0x010e +#define FF_CMD_SHAPE 0x0208 +#define FF_CMD_MAGNITUDE 0x0303 +#define FF_CMD_PERIOD 0x0407 +#define FF_CMD_INTERACT 0x050a + +#define FF_CMD_AUTOCENTER 0x4002 +#define FF_CMD_PLAY 0x4103 +#define FF_CMD_ENABLE 0x4201 +#define FF_CMD_GAIN 0x4301 + +#define FF_CMD_QUERY 0xff01 + +/* Buffer for async write */ +#define XMIT_SIZE 256 +#define XMIT_INC(var, n) (var)+=n; (var)&= XMIT_SIZE -1 +/* iforce::xmit_flags */ +#define IFORCE_XMIT_RUNNING 0 +#define IFORCE_XMIT_AGAIN 1 + +struct iforce_device { + u16 idvendor; + u16 idproduct; + char *name; + signed short *btn; + signed short *abs; + signed short *ff; +}; + +struct iforce { + struct input_dev dev; /* Input device interface */ + struct iforce_device *type; + char name[64]; + char phys[64]; + int open; + int bus; + + unsigned char data[IFORCE_MAX_LENGTH]; + unsigned char edata[IFORCE_MAX_LENGTH]; + u16 ecmd; + u16 expect_packet; + +#ifdef IFORCE_232 + struct serio *serio; /* RS232 transfer */ + int idx, pkt, len, id; + unsigned char csum; +#endif +#ifdef IFORCE_USB + struct usb_device *usbdev; /* USB transfer */ + struct urb irq, out, ctrl; + struct usb_ctrlrequest cr; +#endif + spinlock_t xmit_lock; + /* Buffer used for asynchronous sending of bytes to the device */ + struct circ_buf xmit; + unsigned char xmit_data[XMIT_SIZE]; + long xmit_flags[1]; + + /* Force Feedback */ + wait_queue_head_t wait; + struct resource device_memory; + struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; + struct semaphore mem_mutex; +}; + +/* Get hi and low bytes of a 16-bits int */ +#define HI(a) ((unsigned char)((a) >> 8)) +#define LO(a) ((unsigned char)((a) & 0xff)) + +/* For many parameters, it seems that 0x80 is a special value that should + * be avoided. Instead, we replace this value by 0x7f + */ +#define HIFIX80(a) ((unsigned char)(((a)<0? (a)+255 : (a))>>8)) + +/* Encode a time value */ +#define TIME_SCALE(a) ((a) == 0xffff ? 0xffff : (a) * 1000 / 256) + + +/* Public functions */ +/* iforce-serio.c */ +void iforce_serial_xmit(struct iforce *iforce); + +/* iforce-usb.c */ +void iforce_usb_xmit(struct iforce *iforce); + +/* iforce-main.c */ +int iforce_init_device(struct iforce *iforce); + +/* iforce-packets.c */ +int iforce_control_playback(struct iforce*, u16 id, unsigned int); +void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data); +int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data); +void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ; +int iforce_get_id_packet(struct iforce *iforce, char *packet); + +/* iforce-ff.c */ +int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update); +int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); +int iforce_upload_interactive(struct iforce*, struct ff_effect*, int is_update); + +/* Public variables */ +extern struct serio_dev iforce_serio_dev; +extern struct usb_driver iforce_usb_driver; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/iforce.c linux-2.5/drivers/input/joystick/iforce.c --- linux-2.5.5/drivers/input/joystick/iforce.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/input/joystick/iforce.c Thu Jan 1 00:00:00 1970 @@ -1,1224 +0,0 @@ -/* - * $Id: iforce.c,v 1.56 2001/05/27 14:41:26 jdeneux Exp $ - * - * Copyright (c) 2000-2001 Vojtech Pavlik - * Copyright (c) 2001 Johann Deneux - * - * USB/RS232 I-Force joysticks and wheels. - * - * Sponsored by SuSE - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* FF: This module provides arbitrary resource management routines. - * I use it to manage the device's memory. - * Despite the name of this module, I am *not* going to access the ioports. - */ -#include - -MODULE_AUTHOR("Vojtech Pavlik , Johann Deneux "); -MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); -MODULE_LICENSE("GPL"); - -#define IFORCE_MAX_LENGTH 16 - -#if defined(CONFIG_JOYSTICK_IFORCE_232) || defined(CONFIG_JOYSTICK_IFORCE_232_MODULE) -#define IFORCE_232 1 -#endif -#if defined(CONFIG_JOYSTICK_IFORCE_USB) || defined(CONFIG_JOYSTICK_IFORCE_USB_MODULE) -#define IFORCE_USB 2 -#endif - -#define FF_EFFECTS_MAX 32 - -/* Each force feedback effect is made of one core effect, which can be - * associated to at most to effect modifiers - */ -#define FF_MOD1_IS_USED 0 -#define FF_MOD2_IS_USED 1 -#define FF_CORE_IS_USED 2 -#define FF_CORE_IS_PLAYED 3 -#define FF_MODCORE_MAX 3 - -struct iforce_core_effect { - /* Information about where modifiers are stored in the device's memory */ - struct resource mod1_chunk; - struct resource mod2_chunk; - unsigned long flags[NBITS(FF_MODCORE_MAX)]; -}; - -#define FF_CMD_EFFECT 0x010e -#define FF_CMD_SHAPE 0x0208 -#define FF_CMD_MAGNITUDE 0x0303 -#define FF_CMD_PERIOD 0x0407 -#define FF_CMD_INTERACT 0x050a - -#define FF_CMD_AUTOCENTER 0x4002 -#define FF_CMD_PLAY 0x4103 -#define FF_CMD_ENABLE 0x4201 -#define FF_CMD_GAIN 0x4301 - -#define FF_CMD_QUERY 0xff01 - -static signed short btn_joystick[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, - BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 }; -static signed short btn_wheel[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, - BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; -static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; -static signed short abs_wheel[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 }; -static signed short ff_iforce[] = { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION, - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, FF_AUTOCENTER, -1 }; - -static struct iforce_device { - u16 idvendor; - u16 idproduct; - char *name; - signed short *btn; - signed short *abs; - signed short *ff; -} iforce_device[] = { - { 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce }, - { 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce }, - { 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_joystick, abs_joystick, ff_iforce }, - { 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_wheel, abs_wheel, ff_iforce }, - { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, - { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } -}; - -struct iforce { - struct input_dev dev; /* Input device interface */ - struct iforce_device *type; - char name[64]; - int open; - int bus; - - unsigned char data[IFORCE_MAX_LENGTH]; - unsigned char edata[IFORCE_MAX_LENGTH]; - u16 ecmd; - u16 expect_packet; - -#ifdef IFORCE_232 - struct serio *serio; /* RS232 transfer */ - int idx, pkt, len, id; - unsigned char csum; -#endif -#ifdef IFORCE_USB - struct usb_device *usbdev; /* USB transfer */ - struct urb *irq, *out, *ctrl; - struct usb_ctrlrequest dr; -#endif - /* Force Feedback */ - wait_queue_head_t wait; - struct resource device_memory; - struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; -}; - -static struct { - __s32 x; - __s32 y; -} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; - -/* Get hi and low bytes of a 16-bits int */ -#define HI(a) ((unsigned char)((a) >> 8)) -#define LO(a) ((unsigned char)((a) & 0xff)) - -/* Encode a time value */ -#define TIME_SCALE(a) ((a) == 0xffff ? 0xffff : (a) * 1000 / 256) - -static void dump_packet(char *msg, u16 cmd, unsigned char *data) -{ - int i; - - printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd); - for (i = 0; i < LO(cmd); i++) - printk("%02x ", data[i]); - printk(")\n"); -} - -/* - * Send a packet of bytes to the device - */ -static void send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) -{ - switch (iforce->bus) { - -#ifdef IFORCE_232 - case IFORCE_232: { - - int i; - unsigned char csum = 0x2b ^ HI(cmd) ^ LO(cmd); - - serio_write(iforce->serio, 0x2b); - serio_write(iforce->serio, HI(cmd)); - serio_write(iforce->serio, LO(cmd)); - - for (i = 0; i < LO(cmd); i++) { - serio_write(iforce->serio, data[i]); - csum = csum ^ data[i]; - } - - serio_write(iforce->serio, csum); - return; - } -#endif -#ifdef IFORCE_USB - case IFORCE_USB: { - - DECLARE_WAITQUEUE(wait, current); - int timeout = HZ; /* 1 second */ - - memcpy(iforce->out->transfer_buffer + 1, data, LO(cmd)); - ((char*)iforce->out->transfer_buffer)[0] = HI(cmd); - iforce->out->transfer_buffer_length = LO(cmd) + 2; - iforce->out->dev = iforce->usbdev; - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&iforce->wait, &wait); - - if (usb_submit_urb(iforce->out, GFP_ATOMIC)) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); - return; - } - - while (timeout && iforce->out->status == -EINPROGRESS) - timeout = schedule_timeout(timeout); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); - - if (!timeout) - usb_unlink_urb(iforce->out); - - return; - } -#endif - } -} - -static void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) -{ - struct input_dev *dev = &iforce->dev; - int i; - -#ifdef IFORCE_232 - if (HI(iforce->expect_packet) == HI(cmd)) { - iforce->expect_packet = 0; - iforce->ecmd = cmd; - memcpy(iforce->edata, data, IFORCE_MAX_LENGTH); - if (waitqueue_active(&iforce->wait)) - wake_up(&iforce->wait); - } -#endif - - if (!iforce->type) - return; - - switch (HI(cmd)) { - - case 0x01: /* joystick position data */ - case 0x03: /* wheel position data */ - - if (HI(cmd) == 1) { - input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); - input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); - } else { - input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_GAS, 255 - data[2]); - input_report_abs(dev, ABS_BRAKE, 255 - data[3]); - } - - input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); - input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); - - for (i = 0; iforce->type->btn[i] >= 0; i++) - input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); - - break; - - case 0x02: /* status report */ - - input_report_key(dev, BTN_DEAD, data[0] & 0x02); - break; - } -} - -static int get_id_packet(struct iforce *iforce, char *packet) -{ - DECLARE_WAITQUEUE(wait, current); - int timeout = HZ; /* 1 second */ - - switch (iforce->bus) { - -#ifdef IFORCE_USB - case IFORCE_USB: - - iforce->dr.bRequest = packet[0]; - iforce->ctrl->dev = iforce->usbdev; - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&iforce->wait, &wait); - - if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); - return -1; - } - - while (timeout && iforce->ctrl->status == -EINPROGRESS) - timeout = schedule_timeout(timeout); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); - - if (!timeout) { - usb_unlink_urb(iforce->ctrl); - return -1; - } - - break; -#endif -#ifdef IFORCE_232 - case IFORCE_232: - - iforce->expect_packet = FF_CMD_QUERY; - send_packet(iforce, FF_CMD_QUERY, packet); - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&iforce->wait, &wait); - - while (timeout && iforce->expect_packet) - timeout = schedule_timeout(timeout); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); - - if (!timeout) { - iforce->expect_packet = 0; - return -1; - } - - break; -#endif - } - - return -(iforce->edata[0] != packet[0]); -} - -static int iforce_open(struct input_dev *dev) -{ - struct iforce *iforce = dev->private; - - switch (iforce->bus) { -#ifdef IFORCE_USB - case IFORCE_USB: - if (iforce->open++) - break; - iforce->irq->dev = iforce->usbdev; - if (usb_submit_urb(iforce->irq, GFP_KERNEL)) - return -EIO; - break; -#endif - } - return 0; -} - -static void iforce_close(struct input_dev *dev) -{ - struct iforce *iforce = dev->private; - - switch (iforce->bus) { -#ifdef IFORCE_USB - case IFORCE_USB: - if (!--iforce->open) - usb_unlink_urb(iforce->irq); - break; -#endif - } -} - -/* - * Start or stop playing an effect - */ - -static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) -{ - struct iforce* iforce = (struct iforce*)(dev->private); - unsigned char data[3]; - - printk(KERN_DEBUG "iforce.c: input_event(type = %d, code = %d, value = %d)\n", type, code, value); - - if (type != EV_FF) - return -1; - - switch (code) { - - case FF_GAIN: - - data[0] = value >> 9; - send_packet(iforce, FF_CMD_GAIN, data); - - return 0; - - case FF_AUTOCENTER: - - data[0] = 0x03; - data[1] = value >> 9; - send_packet(iforce, FF_CMD_AUTOCENTER, data); - - data[0] = 0x04; - data[1] = 0x01; - send_packet(iforce, FF_CMD_AUTOCENTER, data); - - return 0; - - default: /* Play an effect */ - - if (code >= iforce->dev.ff_effects_max) - return -1; - - data[0] = LO(code); - data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0; - data[2] = LO(value); - send_packet(iforce, FF_CMD_PLAY, data); - - return 0; - } - - return -1; -} - -/* - * Set the magnitude of a constant force effect - * Return error code - * - * Note: caller must ensure exclusive access to device - */ - -static int make_magnitude_modifier(struct iforce* iforce, - struct resource* mod_chunk, __s16 level) -{ - unsigned char data[3]; - - if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, - iforce->device_memory.start, iforce->device_memory.end, 2L, - NULL, NULL)) { - return -ENOMEM; - } - - data[0] = LO(mod_chunk->start); - data[1] = HI(mod_chunk->start); - data[2] = HI(level); - - send_packet(iforce, FF_CMD_MAGNITUDE, data); - - return 0; -} - -/* - * Upload the component of an effect dealing with the period, phase and magnitude - */ - -static int make_period_modifier(struct iforce* iforce, struct resource* mod_chunk, - __s16 magnitude, __s16 offset, u16 period, u16 phase) -{ - unsigned char data[7]; - - period = TIME_SCALE(period); - - if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, - iforce->device_memory.start, iforce->device_memory.end, 2L, - NULL, NULL)) { - return -ENOMEM; - } - - data[0] = LO(mod_chunk->start); - data[1] = HI(mod_chunk->start); - - data[2] = HI(magnitude); - data[3] = HI(offset); - data[4] = HI(phase); - - data[5] = LO(period); - data[6] = HI(period); - - send_packet(iforce, FF_CMD_PERIOD, data); - - return 0; -} - -/* - * Uploads the part of an effect setting the shape of the force - */ - -static int make_shape_modifier(struct iforce* iforce, struct resource* mod_chunk, - u16 attack_duration, __s16 initial_level, - u16 fade_duration, __s16 final_level) -{ - unsigned char data[8]; - - attack_duration = TIME_SCALE(attack_duration); - fade_duration = TIME_SCALE(fade_duration); - - if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, - iforce->device_memory.start, iforce->device_memory.end, 2L, - NULL, NULL)) { - return -ENOMEM; - } - - data[0] = LO(mod_chunk->start); - data[1] = HI(mod_chunk->start); - - data[2] = LO(attack_duration); - data[3] = HI(attack_duration); - data[4] = HI(initial_level); - - data[5] = LO(fade_duration); - data[6] = HI(fade_duration); - data[7] = HI(final_level); - - send_packet(iforce, FF_CMD_SHAPE, data); - - return 0; -} - -/* - * Component of spring, friction, inertia... effects - */ - -static int make_interactive_modifier(struct iforce* iforce, - struct resource* mod_chunk, - __s16 rsat, __s16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center) -{ - unsigned char data[10]; - - if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, - iforce->device_memory.start, iforce->device_memory.end, 2L, - NULL, NULL)) { - return -ENOMEM; - } - - data[0] = LO(mod_chunk->start); - data[1] = HI(mod_chunk->start); - - data[2] = HI(rk); - data[3] = HI(lk); - - data[4] = LO(center); - data[5] = HI(center); - - data[6] = LO(db); - data[7] = HI(db); - - data[8] = HI(rsat); - data[9] = HI(lsat); - - send_packet(iforce, FF_CMD_INTERACT, data); - - return 0; -} - -static unsigned char find_button(struct iforce *iforce, signed short button) -{ - int i; - for (i = 1; iforce->type->btn[i] >= 0; i++) - if (iforce->type->btn[i] == button) - return i + 1; - return 0; -} - -/* - * Send the part common to all effects to the device - */ - -static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, - u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button, - u16 interval, u16 direction) -{ - unsigned char data[14]; - - duration = TIME_SCALE(duration); - delay = TIME_SCALE(delay); - interval = TIME_SCALE(interval); - - data[0] = LO(id); - data[1] = effect_type; - data[2] = LO(axes) | find_button(iforce, button); - - data[3] = LO(duration); - data[4] = HI(duration); - - data[5] = HI(direction); - - data[6] = LO(interval); - data[7] = HI(interval); - - data[8] = LO(mod_id1); - data[9] = HI(mod_id1); - data[10] = LO(mod_id2); - data[11] = HI(mod_id2); - - data[12] = LO(delay); - data[13] = HI(delay); - - send_packet(iforce, FF_CMD_EFFECT, data); - - return 0; -} - -/* - * Upload a periodic effect to the device - */ - -static int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect) -{ - u8 wave_code; - int core_id = effect->id; - struct iforce_core_effect* core_effect = iforce->core_effects + core_id; - struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); - struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); - int err = 0; - - err = make_period_modifier(iforce, mod1_chunk, - effect->u.periodic.magnitude, effect->u.periodic.offset, - effect->u.periodic.period, effect->u.periodic.phase); - if (err) return err; - set_bit(FF_MOD1_IS_USED, core_effect->flags); - - err = make_shape_modifier(iforce, mod2_chunk, - effect->u.periodic.shape.attack_length, - effect->u.periodic.shape.attack_level, - effect->u.periodic.shape.fade_length, - effect->u.periodic.shape.fade_level); - if (err) return err; - set_bit(FF_MOD2_IS_USED, core_effect->flags); - - switch (effect->u.periodic.waveform) { - case FF_SQUARE: wave_code = 0x20; break; - case FF_TRIANGLE: wave_code = 0x21; break; - case FF_SINE: wave_code = 0x22; break; - case FF_SAW_UP: wave_code = 0x23; break; - case FF_SAW_DOWN: wave_code = 0x24; break; - default: wave_code = 0x20; break; - } - - err = make_core(iforce, effect->id, - mod1_chunk->start, - mod2_chunk->start, - wave_code, - 0x20, - effect->replay.length, - effect->replay.delay, - effect->trigger.button, - effect->trigger.interval, - effect->direction); - - return err; -} - -/* - * Upload a constant force effect - */ -static int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect) -{ - int core_id = effect->id; - struct iforce_core_effect* core_effect = iforce->core_effects + core_id; - struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); - struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); - int err = 0; - - printk(KERN_DEBUG "iforce.c: make constant effect\n"); - - err = make_magnitude_modifier(iforce, mod1_chunk, effect->u.constant.level); - if (err) return err; - set_bit(FF_MOD1_IS_USED, core_effect->flags); - - err = make_shape_modifier(iforce, mod2_chunk, - effect->u.constant.shape.attack_length, - effect->u.constant.shape.attack_level, - effect->u.constant.shape.fade_length, - effect->u.constant.shape.fade_level); - if (err) return err; - set_bit(FF_MOD2_IS_USED, core_effect->flags); - - err = make_core(iforce, effect->id, - mod1_chunk->start, - mod2_chunk->start, - 0x00, - 0x20, - effect->replay.length, - effect->replay.delay, - effect->trigger.button, - effect->trigger.interval, - effect->direction); - - return err; -} - -/* - * Upload an interactive effect. Those are for example friction, inertia, springs... - */ -static int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* effect) -{ - int core_id = effect->id; - struct iforce_core_effect* core_effect = iforce->core_effects + core_id; - struct resource* mod_chunk = &(core_effect->mod1_chunk); - u8 type, axes; - u16 mod1, mod2, direction; - int err = 0; - - printk(KERN_DEBUG "iforce.c: make interactive effect\n"); - - switch (effect->type) { - case FF_SPRING: type = 0x40; break; - case FF_FRICTION: type = 0x41; break; - default: return -1; - } - - err = make_interactive_modifier(iforce, mod_chunk, - effect->u.interactive.right_saturation, - effect->u.interactive.left_saturation, - effect->u.interactive.right_coeff, - effect->u.interactive.left_coeff, - effect->u.interactive.deadband, - effect->u.interactive.center); - if (err) return err; - set_bit(FF_MOD1_IS_USED, core_effect->flags); - - switch ((test_bit(ABS_X, &effect->u.interactive.axis) || - test_bit(ABS_WHEEL, &effect->u.interactive.axis)) | - (!!test_bit(ABS_Y, &effect->u.interactive.axis) << 1)) { - - case 0: /* Only one axis, choose orientation */ - mod1 = mod_chunk->start; - mod2 = 0xffff; - direction = effect->direction; - axes = 0x20; - break; - - case 1: /* Only X axis */ - mod1 = mod_chunk->start; - mod2 = 0xffff; - direction = 0x5a00; - axes = 0x40; - break; - - case 2: /* Only Y axis */ - mod1 = 0xffff; - mod2 = mod_chunk->start; - direction = 0xb400; - axes = 0x80; - break; - - case 3: /* Both X and Y axes */ - /* TODO: same setting for both axes is not mandatory */ - mod1 = mod_chunk->start; - mod2 = mod_chunk->start; - direction = 0x6000; - axes = 0xc0; - break; - - default: - return -1; - } - - err = make_core(iforce, effect->id, - mod1, mod2, - type, axes, - effect->replay.length, effect->replay.delay, - effect->trigger.button, effect->trigger.interval, - direction); - - return err; -} - -/* - * Function called when an ioctl is performed on the event dev entry. - * It uploads an effect to the device - */ -static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) -{ - struct iforce* iforce = (struct iforce*)(dev->private); - int id; - - printk(KERN_DEBUG "iforce.c: upload effect\n"); - -/* - * Get a free id - */ - - for (id=0; id < FF_EFFECTS_MAX; ++id) - if (!test_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break; - - if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max) - return -ENOMEM; - - effect->id = id; - set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags); - -/* - * Upload the effect - */ - - switch (effect->type) { - - case FF_PERIODIC: - return iforce_upload_periodic(iforce, effect); - - case FF_CONSTANT: - return iforce_upload_constant(iforce, effect); - - case FF_SPRING: - case FF_FRICTION: - return iforce_upload_interactive(iforce, effect); - - default: - return -1; - } -} - -/* - * Erases an effect: it frees the effect id and mark as unused the memory - * allocated for the parameters - */ -static int iforce_erase_effect(struct input_dev *dev, int effect_id) -{ - struct iforce* iforce = (struct iforce*)(dev->private); - int err = 0; - struct iforce_core_effect* core_effect; - - printk(KERN_DEBUG "iforce.c: erase effect %d\n", effect_id); - - if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) - return -EINVAL; - - core_effect = iforce->core_effects + effect_id; - - if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) - err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk)); - - if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) - err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk)); - - /*TODO: remember to change that if more FF_MOD* bits are added */ - core_effect->flags[0] = 0; - - return err; -} -static int iforce_init_device(struct iforce *iforce) -{ - unsigned char c[] = "CEOV"; - int i; - - init_waitqueue_head(&iforce->wait); - iforce->dev.ff_effects_max = 10; - -/* - * Input device fields. - */ - - iforce->dev.idbus = BUS_USB; - iforce->dev.private = iforce; - iforce->dev.name = iforce->name; - iforce->dev.open = iforce_open; - iforce->dev.close = iforce_close; - iforce->dev.event = iforce_input_event; - iforce->dev.upload_effect = iforce_upload_effect; - iforce->dev.erase_effect = iforce_erase_effect; - -/* - * On-device memory allocation. - */ - - iforce->device_memory.name = "I-Force device effect memory"; - iforce->device_memory.start = 0; - iforce->device_memory.end = 200; - iforce->device_memory.flags = IORESOURCE_MEM; - iforce->device_memory.parent = NULL; - iforce->device_memory.child = NULL; - iforce->device_memory.sibling = NULL; - -/* - * Wait until device ready - until it sends its first response. - */ - - for (i = 0; i < 20; i++) - if (!get_id_packet(iforce, "O")) - break; - - if (i == 20) { /* 5 seconds */ - printk(KERN_ERR "iforce.c: Timeout waiting for response from device.\n"); - iforce_close(&iforce->dev); - return -1; - } - -/* - * Get device info. - */ - - if (!get_id_packet(iforce, "M")) - iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1]; - if (!get_id_packet(iforce, "P")) - iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1]; - if (!get_id_packet(iforce, "B")) - iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; - if (!get_id_packet(iforce, "N")) - iforce->dev.ff_effects_max = iforce->edata[1]; - -/* - * Display additional info. - */ - - for (i = 0; c[i]; i++) - if (!get_id_packet(iforce, c + i)) - dump_packet("info", iforce->ecmd, iforce->edata); - -/* - * Disable spring, enable force feedback. - * FIXME: We should use iforce_set_autocenter() et al here. - */ - - send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000"); - send_packet(iforce, FF_CMD_ENABLE, "\004"); - -/* - * Find appropriate device entry - */ - - for (i = 0; iforce_device[i].idvendor; i++) - if (iforce_device[i].idvendor == iforce->dev.idvendor && - iforce_device[i].idproduct == iforce->dev.idproduct) - break; - - iforce->type = iforce_device + i; - - sprintf(iforce->name, iforce->type->name, - iforce->dev.idproduct, iforce->dev.idvendor); - -/* - * Set input device bitfields and ranges. - */ - - iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF); - - for (i = 0; iforce->type->btn[i] >= 0; i++) { - signed short t = iforce->type->btn[i]; - set_bit(t, iforce->dev.keybit); - if (t != BTN_DEAD) - set_bit(FF_BTN(t), iforce->dev.ffbit); - } - - for (i = 0; iforce->type->abs[i] >= 0; i++) { - - signed short t = iforce->type->abs[i]; - set_bit(t, iforce->dev.absbit); - - switch (t) { - - case ABS_X: - case ABS_Y: - case ABS_WHEEL: - - iforce->dev.absmax[t] = 1920; - iforce->dev.absmin[t] = -1920; - iforce->dev.absflat[t] = 128; - iforce->dev.absfuzz[t] = 16; - - set_bit(FF_ABS(t), iforce->dev.ffbit); - break; - - case ABS_THROTTLE: - case ABS_GAS: - case ABS_BRAKE: - - iforce->dev.absmax[t] = 255; - iforce->dev.absmin[t] = 0; - break; - - case ABS_HAT0X: - case ABS_HAT0Y: - iforce->dev.absmax[t] = 1; - iforce->dev.absmin[t] = -1; - break; - } - } - - for (i = 0; iforce->type->ff[i] >= 0; i++) - set_bit(iforce->type->ff[i], iforce->dev.ffbit); - -/* - * Register input device. - */ - - input_register_device(&iforce->dev); - - return 0; -} - -#ifdef IFORCE_USB - -static void iforce_usb_irq(struct urb *urb) -{ - struct iforce *iforce = urb->context; - if (urb->status) return; - iforce_process_packet(iforce, - (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1); -} - -static void iforce_usb_out(struct urb *urb) -{ - struct iforce *iforce = urb->context; - if (urb->status) return; - if (waitqueue_active(&iforce->wait)) - wake_up(&iforce->wait); -} - -static void iforce_usb_ctrl(struct urb *urb) -{ - struct iforce *iforce = urb->context; - if (urb->status) return; - iforce->ecmd = 0xff00 | urb->actual_length; - if (waitqueue_active(&iforce->wait)) - wake_up(&iforce->wait); -} - -static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum, - const struct usb_device_id *id) -{ - struct usb_endpoint_descriptor *epirq, *epout; - struct iforce *iforce; - - epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; - epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1; - - if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL; - memset(iforce, 0, sizeof(struct iforce)); - - iforce->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!iforce->irq) { - kfree(iforce); - return NULL; - } - iforce->out = usb_alloc_urb(0, GFP_KERNEL); - if (!iforce->out) { - usb_free_urb(iforce->irq); - kfree(iforce); - return NULL; - } - iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL); - if (!iforce->ctrl) { - usb_free_urb(iforce->out); - usb_free_urb(iforce->irq); - kfree(iforce); - return NULL; - } - - iforce->bus = IFORCE_USB; - iforce->usbdev = dev; - - iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; - iforce->dr.wIndex = 0; - iforce->dr.wLength = 16; - - FILL_INT_URB(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), - iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); - - FILL_BULK_URB(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress), - iforce + 1, 32, iforce_usb_out, iforce); - - FILL_CONTROL_URB(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), - (void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce); - - if (iforce_init_device(iforce)) { - usb_free_urb(iforce->ctrl); - usb_free_urb(iforce->out); - usb_free_urb(iforce->irq); - kfree(iforce); - return NULL; - } - - printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on usb%d:%d.%d\n", - iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max, - iforce->device_memory.end, dev->bus->busnum, dev->devnum, ifnum); - - return iforce; -} - -static void iforce_usb_disconnect(struct usb_device *dev, void *ptr) -{ - struct iforce *iforce = ptr; - usb_unlink_urb(iforce->irq); - input_unregister_device(&iforce->dev); - usb_free_urb(iforce->ctrl); - usb_free_urb(iforce->out); - usb_free_urb(iforce->irq); - kfree(iforce); -} - -static struct usb_device_id iforce_usb_ids [] = { - { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */ - { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */ - { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */ - { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */ - { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, iforce_usb_ids); - -static struct usb_driver iforce_usb_driver = { - name: "iforce", - probe: iforce_usb_probe, - disconnect: iforce_usb_disconnect, - id_table: iforce_usb_ids, -}; - -#endif - -#ifdef IFORCE_232 - -static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags) -{ - struct iforce* iforce = serio->private; - - if (!iforce->pkt) { - if (data != 0x2b) { - return; - } - iforce->pkt = 1; - return; - } - - if (!iforce->id) { - if (data > 3 && data != 0xff) { - iforce->pkt = 0; - return; - } - iforce->id = data; - return; - } - - if (!iforce->len) { - if (data > IFORCE_MAX_LENGTH) { - iforce->pkt = 0; - iforce->id = 0; - return; - } - iforce->len = data; - return; - } - - if (iforce->idx < iforce->len) { - iforce->csum += iforce->data[iforce->idx++] = data; - return; - } - - if (iforce->idx == iforce->len) { - iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); - iforce->pkt = 0; - iforce->id = 0; - iforce->len = 0; - iforce->idx = 0; - iforce->csum = 0; - } -} - -static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) -{ - struct iforce *iforce; - if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) - return; - - if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return; - memset(iforce, 0, sizeof(struct iforce)); - - iforce->bus = IFORCE_232; - iforce->serio = serio; - serio->private = iforce; - - if (serio_open(serio, dev)) { - kfree(iforce); - return; - } - - if (iforce_init_device(iforce)) { - serio_close(serio); - kfree(iforce); - return; - } - - printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on serio%d\n", - iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max, - iforce->device_memory.end, serio->number); -} - -static void iforce_serio_disconnect(struct serio *serio) -{ - struct iforce* iforce = serio->private; - - input_unregister_device(&iforce->dev); - serio_close(serio); - kfree(iforce); -} - -static struct serio_dev iforce_serio_dev = { - interrupt: iforce_serio_irq, - connect: iforce_serio_connect, - disconnect: iforce_serio_disconnect, -}; - -#endif - -static int __init iforce_init(void) -{ -#ifdef IFORCE_USB - usb_register(&iforce_usb_driver); -#endif -#ifdef IFORCE_232 - serio_register_device(&iforce_serio_dev); -#endif - return 0; -} - -static void __exit iforce_exit(void) -{ -#ifdef IFORCE_USB - usb_deregister(&iforce_usb_driver); -#endif -#ifdef IFORCE_232 - serio_unregister_device(&iforce_serio_dev); -#endif -} - -module_init(iforce_init); -module_exit(iforce_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/interact.c linux-2.5/drivers/input/joystick/interact.c --- linux-2.5.5/drivers/input/joystick/interact.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/input/joystick/interact.c Fri Mar 1 14:48:17 2002 @@ -1,12 +1,10 @@ /* - * $Id: interact.c,v 1.8 2000/05/29 11:19:51 vojtech Exp $ + * $Id: interact.c,v 1.16 2002/01/22 20:28:25 vojtech Exp $ * - * Copyright (c) 2000 Vojtech Pavlik + * Copyright (c) 2001 Vojtech Pavlik * * Based on the work of: * Toby Deshane - * - * Sponsored by SuSE */ /* @@ -29,8 +27,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -41,6 +39,10 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("InterAct digital joystick driver"); +MODULE_LICENSE("GPL"); + #define INTERACT_MAX_START 400 /* 400 us */ #define INTERACT_MAX_STROBE 40 /* 40 us */ #define INTERACT_MAX_LENGTH 32 /* 32 bits */ @@ -58,6 +60,7 @@ int reads; unsigned char type; unsigned char length; + char phys[32]; }; static short interact_abs_hhfx[] = @@ -137,40 +140,41 @@ if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) { interact->bads++; - } else + } else { - for (i = 0; i < 3; i++) - data[i] <<= INTERACT_MAX_LENGTH - interact->length; + for (i = 0; i < 3; i++) + data[i] <<= INTERACT_MAX_LENGTH - interact->length; - switch (interact->type) { + switch (interact->type) { - case INTERACT_TYPE_HHFX: + case INTERACT_TYPE_HHFX: - for (i = 0; i < 4; i++) - input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff); + for (i = 0; i < 4; i++) + input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff); - for (i = 0; i < 2; i++) - input_report_abs(dev, ABS_HAT0Y - i, - ((data[1] >> ((i << 1) + 17)) & 1) - ((data[1] >> ((i << 1) + 16)) & 1)); + for (i = 0; i < 2; i++) + input_report_abs(dev, ABS_HAT0Y - i, + ((data[1] >> ((i << 1) + 17)) & 1) - ((data[1] >> ((i << 1) + 16)) & 1)); - for (i = 0; i < 8; i++) - input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1); + for (i = 0; i < 8; i++) + input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1); - for (i = 0; i < 4; i++) - input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1); + for (i = 0; i < 4; i++) + input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1); - break; + break; - case INTERACT_TYPE_PP8D: + case INTERACT_TYPE_PP8D: - for (i = 0; i < 2; i++) - input_report_abs(dev, interact_abs_pp8d[i], - ((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1)); + for (i = 0; i < 2; i++) + input_report_abs(dev, interact_abs_pp8d[i], + ((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1)); - for (i = 0; i < 8; i++) - input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1); + for (i = 0; i < 8; i++) + input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1); - break; + break; + } } mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME); @@ -235,11 +239,13 @@ break; if (!interact_type[i].length) { - printk(KERN_WARNING "interact.c: Unknown joystick on gameport%d. [len %d d0 %08x d1 %08x i2 %08x]\n", - gameport->number, i, data[0], data[1], data[2]); + printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x i2 %08x]\n", + gameport->phys, i, data[0], data[1], data[2]); goto fail2; } + sprintf(interact->phys, "%s/input0", gameport->phys); + interact->type = i; interact->length = interact_type[i].length; @@ -248,6 +254,7 @@ interact->dev.close = interact_close; interact->dev.name = interact_type[i].name; + interact->dev.phys = interact->phys; interact->dev.idbus = BUS_GAMEPORT; interact->dev.idvendor = GAMEPORT_ID_VENDOR_INTERACT; interact->dev.idproduct = interact_type[i].id; @@ -270,8 +277,8 @@ set_bit(t, interact->dev.keybit); input_register_device(&interact->dev); - printk(KERN_INFO "input%d: %s on gameport%d.0\n", - interact->dev.number, interact_type[interact->type].name, gameport->number); + printk(KERN_INFO "input: %s on %s\n", + interact_type[interact->type].name, gameport->phys); return; fail2: gameport_close(gameport); @@ -304,5 +311,3 @@ module_init(interact_init); module_exit(interact_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/joydump.c linux-2.5/drivers/input/joystick/joydump.c --- linux-2.5.5/drivers/input/joystick/joydump.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/joystick/joydump.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,152 @@ +/* + * $Id: joydump.c,v 1.6 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1996-2001 Vojtech Pavlik + */ + +/* + * This is just a very simple driver that can dump the data + * out of the joystick port into the syslog ... + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Gameport data dumper module"); +MODULE_LICENSE("GPL"); + +#define BUF_SIZE 256 + +struct joydump { + unsigned int time; + unsigned char data; +}; + +static void __devinit joydump_connect(struct gameport *gameport, struct gameport_dev *dev) +{ + struct joydump buf[BUF_SIZE]; + int axes[4], buttons; + int i, j, t, timeout; + unsigned long flags; + unsigned char u; + + printk(KERN_INFO "joydump: ,------------------- START ------------------.\n"); + printk(KERN_INFO "joydump: | Dumping gameport%s.\n", gameport->phys); + printk(KERN_INFO "joydump: | Speed: %4d kHz. |\n", gameport->speed); + + if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) { + + printk(KERN_INFO "joydump: | Raw mode not available - trying cooked. |\n"); + + if (gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) { + + printk(KERN_INFO "joydump: | Cooked not available either. Failing. |\n"); + printk(KERN_INFO "joydump: `-------------------- END -------------------'\n"); + return; + } + + gameport_cooked_read(gameport, axes, &buttons); + + for (i = 0; i < 4; i++) + printk(KERN_INFO "joydump: | Axis %d: %4d. |\n", i, axes[i]); + printk(KERN_INFO "joydump: | Buttons %02x. |\n", buttons); + printk(KERN_INFO "joydump: `-------------------- END -------------------'\n"); + } + + timeout = gameport_time(gameport, 10000); /* 10 ms */ + t = 0; + i = 1; + + save_flags(flags); + cli(); + + u = gameport_read(gameport); + + buf[0].data = u; + buf[0].time = t; + + gameport_trigger(gameport); + + while (i < BUF_SIZE && t < timeout) { + + buf[i].data = gameport_read(gameport); + + if (buf[i].data ^ u) { + u = buf[i].data; + buf[i].time = t; + i++; + } + t++; + } + + restore_flags(flags); + +/* + * Dump data. + */ + + t = i; + + printk(KERN_INFO "joydump: >------------------- DATA -------------------<\n"); + printk(KERN_INFO "joydump: | index: %3d delta: %3d.%02d us data: ", 0, 0, 0); + for (j = 7; j >= 0; j--) + printk("%d",(buf[0].data >> j) & 1); + printk(" |\n"); + for (i = 1; i < t; i++) { + printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ", + i, buf[i].time - buf[i-1].time); + for (j = 7; j >= 0; j--) + printk("%d",(buf[i].data >> j) & 1); + printk(" |\n"); + } + + printk(KERN_INFO "joydump: `-------------------- END -------------------'\n"); +} + +static void __devexit joydump_disconnect(struct gameport *gameport) +{ + gameport_close(gameport); +} + +static struct gameport_dev joydump_dev = { + connect: joydump_connect, + disconnect: joydump_disconnect, +}; + +static int __init joydump_init(void) +{ + gameport_register_device(&joydump_dev); + return 0; +} + +static void __exit joydump_exit(void) +{ + gameport_unregister_device(&joydump_dev); +} + +module_init(joydump_init); +module_exit(joydump_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/magellan.c linux-2.5/drivers/input/joystick/magellan.c --- linux-2.5.5/drivers/input/joystick/magellan.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/input/joystick/magellan.c Fri Mar 1 14:48:41 2002 @@ -1,9 +1,7 @@ /* - * $Id: magellan.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $ + * $Id: magellan.c,v 1.16 2002/01/22 20:28:39 vojtech Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1999-2001 Vojtech Pavlik */ /* @@ -27,7 +25,7 @@ * * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -37,15 +35,19 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Magellan and SpaceMouse 6dof controller driver"); +MODULE_LICENSE("GPL"); + /* * Definitions & global arrays. */ #define MAGELLAN_MAX_LENGTH 32 -static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8}; -static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ}; -static char *magellan_name = "LogiCad3D Magellan"; +static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 }; +static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; +static char *magellan_name = "LogiCad3D Magellan / SpaceMouse"; /* * Per-Magellan data. @@ -55,6 +57,7 @@ struct input_dev dev; int idx; unsigned char data[MAGELLAN_MAX_LENGTH]; + char phys[32]; }; /* @@ -162,8 +165,11 @@ magellan->dev.absmax[t] = 360; } + sprintf(magellan->phys, "%s/input0", serio->phys); + magellan->dev.private = magellan; magellan->dev.name = magellan_name; + magellan->dev.phys = magellan->phys; magellan->dev.idbus = BUS_RS232; magellan->dev.idvendor = SERIO_MAGELLAN; magellan->dev.idproduct = 0x0001; @@ -178,7 +184,7 @@ input_register_device(&magellan->dev); - printk(KERN_INFO "input%d: %s on serio%d\n", magellan->dev.number, magellan_name, serio->number); + printk(KERN_INFO "input: %s on %s\n", magellan_name, serio->phys); } /* @@ -208,5 +214,3 @@ module_init(magellan_init); module_exit(magellan_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/sidewinder.c linux-2.5/drivers/input/joystick/sidewinder.c --- linux-2.5.5/drivers/input/joystick/sidewinder.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/input/joystick/sidewinder.c Fri Mar 1 14:49:10 2002 @@ -1,9 +1,7 @@ /* - * $Id: sidewinder.c,v 1.20 2001/05/19 08:14:54 vojtech Exp $ + * $Id: sidewinder.c,v 1.29 2002/01/22 20:28:51 vojtech Exp $ * * Copyright (c) 1998-2001 Vojtech Pavlik - * - * Sponsored by SuSE */ /* @@ -26,8 +24,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -38,12 +36,16 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Microsoft SideWinder joystick family driver"); +MODULE_LICENSE("GPL"); + /* * These are really magic values. Changing them can make a problem go away, * as well as break everything. */ -#undef SW_DEBUG +#define SW_DEBUG #define SW_START 400 /* The time we wait for the first bit [400 us] */ #define SW_STROBE 45 /* Max time per bit [45 us] */ @@ -114,6 +116,7 @@ struct timer_list timer; struct input_dev dev[4]; char name[64]; + char phys[4][32]; int length; int type; int bits; @@ -411,8 +414,8 @@ if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) { /* Broken packet, try to fix */ if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) { /* Last init failed, 1 bit mode */ - printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on gameport%d" - " - going to reinitialize.\n", sw->gameport->number); + printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on %s" + " - going to reinitialize.\n", sw->gameport->phys); sw->fail = SW_FAIL; /* Reinitialize */ i = 128; /* Bogus value */ } @@ -437,8 +440,8 @@ if (sw->type == SW_ID_3DP && sw->length == 66 /* Many packets OK */ && sw->ok > SW_OK) { - printk(KERN_INFO "sidewinder.c: No more trouble on gameport%d" - " - enabling optimization again.\n", sw->gameport->number); + printk(KERN_INFO "sidewinder.c: No more trouble on %s" + " - enabling optimization again.\n", sw->gameport->phys); sw->length = 22; } @@ -450,15 +453,15 @@ if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) { /* Consecutive bad packets */ - printk(KERN_INFO "sidewinder.c: Many bit errors on gameport%d" - " - disabling optimization.\n", sw->gameport->number); + printk(KERN_INFO "sidewinder.c: Many bit errors on %s" + " - disabling optimization.\n", sw->gameport->phys); sw->length = 66; } if (sw->fail < SW_FAIL) return -1; /* Not enough, don't reinitialize yet */ - printk(KERN_WARNING "sidewinder.c: Too many bit errors on gameport%d" - " - reinitializing joystick.\n", sw->gameport->number); + printk(KERN_WARNING "sidewinder.c: Too many bit errors on %s" + " - reinitializing joystick.\n", sw->gameport->phys); if (!i && sw->type == SW_ID_3DP) { /* 3D Pro can be in analog mode */ udelay(3 * SW_TIMEOUT); @@ -582,8 +585,8 @@ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) goto fail1; - dbg("Init 0: Opened gameport %d, io %#x, speed %d", - gameport->number, gameport->io, gameport->speed); + dbg("Init 0: Opened %s, io %#x, speed %d", + gameport->phys, gameport->io, gameport->speed); i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read normal packet */ m |= sw_guess_mode(buf, i); /* Data packet (1-bit) can carry mode info [FSP] */ @@ -673,7 +676,7 @@ if (sw->type == -1) { printk(KERN_WARNING "sidewinder.c: unknown joystick device detected " - "on gameport%d, contact \n", gameport->number); + "on %s, contact \n", gameport->phys); sw_print_packet("ID", j * 3, idbuf, 3); sw_print_packet("Data", i * m, buf, m); goto fail2; @@ -691,6 +694,7 @@ int bits, code; sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]); + sprintf(sw->phys[i], "%s/input%d", gameport->phys, i); sw->dev[i].private = sw; @@ -698,6 +702,7 @@ sw->dev[i].close = sw_close; sw->dev[i].name = sw->name; + sw->dev[i].phys = sw->phys[i]; sw->dev[i].idbus = BUS_GAMEPORT; sw->dev[i].idvendor = GAMEPORT_ID_VENDOR_MICROSOFT; sw->dev[i].idproduct = sw->type; @@ -719,8 +724,8 @@ set_bit(code, sw->dev[i].keybit); input_register_device(sw->dev + i); - printk(KERN_INFO "input%d: %s%s on gameport%d.%d [%d-bit id %d data %d]\n", - sw->dev[i].number, sw->name, comment, gameport->number, i, m, l, k); + printk(KERN_INFO "input: %s%s on %s [%d-bit id %d data %d]\n", + sw->name, comment, gameport->phys, m, l, k); } return; @@ -757,5 +762,3 @@ module_init(sw_init); module_exit(sw_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/spaceball.c linux-2.5/drivers/input/joystick/spaceball.c --- linux-2.5.5/drivers/input/joystick/spaceball.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/input/joystick/spaceball.c Fri Mar 1 14:49:40 2002 @@ -1,17 +1,15 @@ /* - * $Id: spaceball.c,v 1.8 2000/11/23 11:42:39 vojtech Exp $ + * $Id: spaceball.c,v 1.17 2002/01/22 20:29:03 vojtech Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik + * Copyright (c) 1999-2001 Vojtech Pavlik * * Based on the work of: * David Thompson * Joseph Krahn - * - * Sponsored by SuSE */ /* - * SpaceTec SpaceBall 4000 FLX driver for Linux + * SpaceTec SpaceBall 2003/3003/4000 FLX driver for Linux */ /* @@ -30,8 +28,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -41,13 +39,29 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("SpaceTec SpaceBall 2003/3003/4000 FLX driver"); +MODULE_LICENSE("GPL"); + /* * Constants. */ -#define JS_SBALL_MAX_LENGTH 128 +#define SPACEBALL_MAX_LENGTH 128 +#define SPACEBALL_MAX_ID 8 + +#define SPACEBALL_1003 1 +#define SPACEBALL_2003B 3 +#define SPACEBALL_2003C 4 +#define SPACEBALL_3003C 7 +#define SPACEBALL_4000FLX 8 +#define SPACEBALL_4000FLX_L 9 + static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY }; -static char *spaceball_name = "SpaceTec SpaceBall 4000 FLX"; +static char *spaceball_names[] = { + "?", "SpaceTec SpaceBall 1003", "SpaceTec SpaceBall 2003", "SpaceTec SpaceBall 2003B", + "SpaceTec SpaceBall 2003C", "SpaceTec SpaceBall 3003", "SpaceTec SpaceBall SpaceController", + "SpaceTec SpaceBall 3003C", "SpaceTec SpaceBall 4000FLX", "SpaceTec SpaceBall 4000FLX Lefty" }; /* * Per-Ball data. @@ -58,7 +72,8 @@ struct serio *serio; int idx; int escape; - unsigned char data[JS_SBALL_MAX_LENGTH]; + unsigned char data[SPACEBALL_MAX_LENGTH]; + char phys[32]; }; /* @@ -74,35 +89,53 @@ if (spaceball->idx < 2) return; - printk("%c %d\n", spaceball->data[0], spaceball->idx); - switch (spaceball->data[0]) { - case '@': /* Reset packet */ - spaceball->data[spaceball->idx - 1] = 0; - for (i = 1; i < spaceball->idx && spaceball->data[i] == ' '; i++); - printk(KERN_INFO "input%d: %s [%s] on serio%d\n", - spaceball->dev.number, spaceball_name, spaceball->data + i, spaceball->serio->number); - break; - case 'D': /* Ball data */ if (spaceball->idx != 15) return; - for (i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) input_report_abs(dev, spaceball_axes[i], (__s16)((data[2 * i + 3] << 8) | data[2 * i + 2])); - } break; - case '.': /* Button data, part2 */ + case 'K': /* Button data */ if (spaceball->idx != 3) return; - input_report_key(dev, BTN_0, data[2] & 1); - input_report_key(dev, BTN_1, data[2] & 2); + input_report_key(dev, BTN_1, (data[2] & 0x01) || (data[2] & 0x20)); + input_report_key(dev, BTN_2, data[2] & 0x02); + input_report_key(dev, BTN_3, data[2] & 0x04); + input_report_key(dev, BTN_4, data[2] & 0x08); + input_report_key(dev, BTN_5, data[1] & 0x01); + input_report_key(dev, BTN_6, data[1] & 0x02); + input_report_key(dev, BTN_7, data[1] & 0x04); + input_report_key(dev, BTN_8, data[1] & 0x10); break; - case '?': /* Error packet */ + case '.': /* Advanced button data */ + if (spaceball->idx != 3) return; + input_report_key(dev, BTN_1, data[2] & 0x01); + input_report_key(dev, BTN_2, data[2] & 0x02); + input_report_key(dev, BTN_3, data[2] & 0x04); + input_report_key(dev, BTN_4, data[2] & 0x08); + input_report_key(dev, BTN_5, data[2] & 0x10); + input_report_key(dev, BTN_6, data[2] & 0x20); + input_report_key(dev, BTN_7, data[2] & 0x80); + input_report_key(dev, BTN_8, data[1] & 0x01); + input_report_key(dev, BTN_9, data[1] & 0x02); + input_report_key(dev, BTN_A, data[1] & 0x04); + input_report_key(dev, BTN_B, data[1] & 0x08); + input_report_key(dev, BTN_C, data[1] & 0x10); + input_report_key(dev, BTN_MODE, data[1] & 0x20); + break; + + case 'E': /* Device error */ spaceball->data[spaceball->idx - 1] = 0; printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1); break; + + case '?': /* Bad command packet */ + spaceball->data[spaceball->idx - 1] = 0; + printk(KERN_ERR "spaceball: Bad command. [%s]\n", spaceball->data + 1); + break; } } @@ -136,11 +169,9 @@ data &= 0x1f; } default: - if (spaceball->escape) { + if (spaceball->escape) spaceball->escape = 0; - printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x (%c)\n", data, data); - } - if (spaceball->idx < JS_SBALL_MAX_LENGTH) + if (spaceball->idx < SPACEBALL_MAX_LENGTH) spaceball->data[spaceball->idx++] = data; return; } @@ -167,9 +198,12 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev) { struct spaceball *spaceball; - int i, t; + int i, t, id; - if (serio->type != (SERIO_RS232 | SERIO_SPACEBALL)) + if ((serio->type & ~SERIO_ID) != (SERIO_RS232 | SERIO_SPACEBALL)) + return; + + if ((id = (serio->type & SERIO_ID) >> 8) > SPACEBALL_MAX_ID) return; if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL))) @@ -177,7 +211,18 @@ memset(spaceball, 0, sizeof(struct spaceball)); spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - spaceball->dev.keybit[LONG(BTN_0)] = BIT(BTN_0) | BIT(BTN_1); + + switch (id) { + case SPACEBALL_4000FLX: + case SPACEBALL_4000FLX_L: + spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_9); + spaceball->dev.keybit[LONG(BTN_A)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_MODE); + default: + spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) + | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7) | BIT(BTN_8); + case SPACEBALL_3003C: + spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_1) | BIT(BTN_8); + } for (i = 0; i < 6; i++) { t = spaceball_axes[i]; @@ -191,10 +236,13 @@ spaceball->serio = serio; spaceball->dev.private = spaceball; - spaceball->dev.name = spaceball_name; + sprintf(spaceball->phys, "%s/input0", serio->phys); + + spaceball->dev.name = spaceball_names[id]; + spaceball->dev.phys = spaceball->phys; spaceball->dev.idbus = BUS_RS232; spaceball->dev.idvendor = SERIO_SPACEBALL; - spaceball->dev.idproduct = 0x0001; + spaceball->dev.idproduct = id; spaceball->dev.idversion = 0x0100; serio->private = spaceball; @@ -205,6 +253,9 @@ } input_register_device(&spaceball->dev); + + printk(KERN_INFO "input: %s on serio%s\n", + spaceball_names[id], serio->phys); } /* @@ -234,5 +285,3 @@ module_init(spaceball_init); module_exit(spaceball_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/spaceorb.c linux-2.5/drivers/input/joystick/spaceorb.c --- linux-2.5.5/drivers/input/joystick/spaceorb.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/input/joystick/spaceorb.c Fri Mar 1 14:50:10 2002 @@ -1,12 +1,10 @@ /* - * $Id: spaceorb.c,v 1.7 2000/05/29 11:19:51 vojtech Exp $ + * $Id: spaceorb.c,v 1.15 2002/01/22 20:29:19 vojtech Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik + * Copyright (c) 1999-2001 Vojtech Pavlik * * Based on the work of: * David Thompson - * - * Sponsored by SuSE */ /* @@ -29,8 +27,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -40,15 +38,19 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("SpaceTec SpaceOrb 360 and Avenger 6dof controller driver"); +MODULE_LICENSE("GPL"); + /* * Constants. */ #define SPACEORB_MAX_LENGTH 64 -static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A, BTN_MODE}; -static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ}; -static char *spaceorb_name = "SpaceTec SpaceOrb 360"; +static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A }; +static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; +static char *spaceorb_name = "SpaceTec SpaceOrb 360 / Avenger"; /* * Per-Orb data. @@ -59,6 +61,7 @@ struct serio *serio; int idx; unsigned char data[SPACEORB_MAX_LENGTH]; + char phys[32]; }; static unsigned char spaceorb_xor[] = "SpaceWare"; @@ -88,8 +91,8 @@ case 'R': /* Reset packet */ spaceorb->data[spaceorb->idx - 1] = 0; for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++); - printk(KERN_INFO "input%d: %s [%s] on serio%d\n", - spaceorb->dev.number, spaceorb_name, spaceorb->data + i, spaceorb->serio->number); + printk(KERN_INFO "input: %s [%s] on %s\n", + spaceorb_name, spaceorb->data + i, spaceorb->serio->phys); break; case 'D': /* Ball + button data */ @@ -103,7 +106,7 @@ axes[5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3); for (i = 0; i < 6; i++) input_report_abs(dev, spaceorb_axes[i], axes[i] - ((axes[i] & 0x200) ? 1024 : 0)); - for (i = 0; i < 8; i++) + for (i = 0; i < 6; i++) input_report_key(dev, spaceorb_buttons[i], (data[1] >> i) & 1); break; @@ -167,8 +170,8 @@ spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - for (i = 0; i < 7; i++) - set_bit(spaceorb_buttons[i], &spaceorb->dev.keybit); + for (i = 0; i < 6; i++) + set_bit(spaceorb_buttons[i], spaceorb->dev.keybit); for (i = 0; i < 6; i++) { t = spaceorb_axes[i]; @@ -180,7 +183,10 @@ spaceorb->serio = serio; spaceorb->dev.private = spaceorb; + sprintf(spaceorb->phys, "%s/input0", serio->phys); + spaceorb->dev.name = spaceorb_name; + spaceorb->dev.phys = spaceorb->phys; spaceorb->dev.idbus = BUS_RS232; spaceorb->dev.idvendor = SERIO_SPACEORB; spaceorb->dev.idproduct = 0x0001; @@ -223,5 +229,3 @@ module_init(spaceorb_init); module_exit(spaceorb_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/stinger.c linux-2.5/drivers/input/joystick/stinger.c --- linux-2.5.5/drivers/input/joystick/stinger.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/input/joystick/stinger.c Fri Mar 1 14:50:26 2002 @@ -1,10 +1,8 @@ /* - * $Id: stinger.c,v 1.4 2001/05/23 09:25:02 vojtech Exp $ + * $Id: stinger.c,v 1.10 2002/01/22 20:29:31 vojtech Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik * Copyright (c) 2000 Mark Fletcher - * - * Sponsored by SuSE */ /* @@ -28,7 +26,7 @@ * * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -38,6 +36,10 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Gravis Stinger gamepad driver"); +MODULE_LICENSE("GPL"); + /* * Constants. */ @@ -54,6 +56,7 @@ struct input_dev dev; int idx; unsigned char data[STINGER_MAX_LENGTH]; + char phys[32]; }; /* @@ -145,7 +148,10 @@ BIT(BTN_START) | BIT(BTN_SELECT); stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + sprintf(stinger->phys, "%s/serio0", serio->phys); + stinger->dev.name = stinger_name; + stinger->dev.phys = stinger->phys; stinger->dev.idbus = BUS_RS232; stinger->dev.idvendor = SERIO_STINGER; stinger->dev.idproduct = 0x0001; @@ -168,7 +174,7 @@ input_register_device(&stinger->dev); - printk(KERN_INFO "input%d: %s on serio%d\n", stinger->dev.number, stinger_name, serio->number); + printk(KERN_INFO "input: %s on %s\n", stinger_name, serio->phys); } /* @@ -198,5 +204,3 @@ module_init(stinger_init); module_exit(stinger_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/tmdc.c linux-2.5/drivers/input/joystick/tmdc.c --- linux-2.5.5/drivers/input/joystick/tmdc.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/input/joystick/tmdc.c Fri Mar 1 14:50:37 2002 @@ -1,13 +1,10 @@ /* - * $Id: tmdc.c,v 1.23 2000/11/29 19:52:24 vojtech Exp $ + * $Id: tmdc.c,v 1.31 2002/01/22 20:29:52 vojtech Exp $ * - * Copyright (c) 1998-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1998-2001 Vojtech Pavlik * * Based on the work of: * Trystan Larey-Williams - * */ /* @@ -30,8 +27,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -42,6 +39,10 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("ThrustMaster DirectConnect joystick driver"); +MODULE_LICENSE("GPL"); + #define TMDC_MAX_START 400 /* 400 us */ #define TMDC_MAX_STROBE 45 /* 45 us */ #define TMDC_MAX_LENGTH 13 @@ -94,6 +95,7 @@ struct timer_list timer; struct input_dev dev[2]; char name[2][64]; + char phys[2][32]; int mode[2]; signed char *abs[2]; short *btn[2]; @@ -172,6 +174,7 @@ if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists) bad = 1; + else for (j = 0; j < 2; j++) if (r & (1 << j) & tmdc->exists) { @@ -302,11 +305,14 @@ sprintf(tmdc->name[j], models[m].name, models[m].abs, (data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]); + sprintf(tmdc->phys[j], "%s/input%d", gameport->phys, j); + tmdc->dev[j].private = tmdc; tmdc->dev[j].open = tmdc_open; tmdc->dev[j].close = tmdc_close; tmdc->dev[j].name = tmdc->name[j]; + tmdc->dev[j].phys = tmdc->phys[j]; tmdc->dev[j].idbus = BUS_GAMEPORT; tmdc->dev[j].idvendor = GAMEPORT_ID_VENDOR_THRUSTMASTER; tmdc->dev[j].idproduct = models[m].id; @@ -336,8 +342,7 @@ } input_register_device(tmdc->dev + j); - printk(KERN_INFO "input%d: %s on gameport%d.%d\n", - tmdc->dev[j].number, tmdc->name[j], gameport->number, j); + printk(KERN_INFO "input: %s on %s\n", tmdc->name[j], gameport->phys); } return; @@ -374,5 +379,3 @@ module_init(tmdc_init); module_exit(tmdc_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/turbografx.c linux-2.5/drivers/input/joystick/turbografx.c --- linux-2.5.5/drivers/input/joystick/turbografx.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/input/joystick/turbografx.c Fri Mar 1 14:50:55 2002 @@ -1,12 +1,10 @@ /* - * $Id: turbografx.c,v 1.8 2000/05/29 20:39:38 vojtech Exp $ + * $Id: turbografx.c,v 1.14 2002/01/22 20:30:39 vojtech Exp $ * - * Copyright (c) 1998-2000 Vojtech Pavlik + * Copyright (c) 1998-2001 Vojtech Pavlik * * Based on the work of: * Steffen Schwenke - * - * Sponsored by SuSE */ /* @@ -29,8 +27,8 @@ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -39,8 +37,10 @@ #include #include -MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("TurboGraFX parallel port interface driver"); MODULE_LICENSE("GPL"); + MODULE_PARM(tgfx, "2-8i"); MODULE_PARM(tgfx_2, "2-8i"); MODULE_PARM(tgfx_3, "2-8i"); @@ -69,6 +69,7 @@ struct pardevice *pd; struct timer_list timer; struct input_dev dev[7]; + char phys[7][32]; int sticks; int used; } *tgfx_base[3]; @@ -174,7 +175,10 @@ tgfx->dev[i].open = tgfx_open; tgfx->dev[i].close = tgfx_close; + sprintf(tgfx->phys[i], "%s/input0", tgfx->pd->port->name); + tgfx->dev[i].name = tgfx_name; + tgfx->dev[i].phys = tgfx->phys[i]; tgfx->dev[i].idbus = BUS_PARPORT; tgfx->dev[i].idvendor = 0x0003; tgfx->dev[i].idproduct = config[i+1]; @@ -190,8 +194,8 @@ tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1; input_register_device(tgfx->dev + i); - printk(KERN_INFO "input%d: %d-button Multisystem joystick on %s\n", - tgfx->dev[i].number, config[i+1], tgfx->pd->port->name); + printk(KERN_INFO "input: %d-button Multisystem joystick on %s\n", + config[i+1], tgfx->pd->port->name); } if (!tgfx->sticks) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/twidjoy.c linux-2.5/drivers/input/joystick/twidjoy.c --- linux-2.5.5/drivers/input/joystick/twidjoy.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/joystick/twidjoy.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,264 @@ +/* + * $Id: twidjoy.c,v 1.4 2001/09/25 09:17:15 vojtech Exp $ + * + * derived from CVS-ID "stinger.c,v 1.5 2001/05/29 12:57:18 vojtech Exp" + * + * Copyright (c) 2001 Arndt Schoenewald + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2000 Mark Fletcher + * + * Sponsored by Quelltext AG (http://www.quelltext-ag.de), Dortmund, Germany + */ + +/* + * Driver to use Handykey's Twiddler (the first edition, i.e. the one with + * the RS232 interface) as a joystick under Linux + * + * The Twiddler is a one-handed chording keyboard featuring twelve buttons on + * the front, six buttons on the top, and a built-in tilt sensor. The buttons + * on the front, which are grouped as four rows of three buttons, are pressed + * by the four fingers (this implies only one button per row can be held down + * at the same time) and the buttons on the top are for the thumb. The tilt + * sensor delivers X and Y axis data depending on how the Twiddler is held. + * Additional information can be found at http://www.handykey.com. + * + * This driver does not use the Twiddler for its intended purpose, i.e. as + * a chording keyboard, but as a joystick: pressing and releasing a button + * immediately sends a corresponding button event, and tilting it generates + * corresponding ABS_X and ABS_Y events. This turns the Twiddler into a game + * controller with amazing 18 buttons :-) + * + * Note: The Twiddler2 (the successor of the Twiddler that connects directly + * to the PS/2 keyboard and mouse ports) is NOT supported by this driver! + * + * For questions or feedback regarding this driver module please contact: + * Arndt Schoenewald + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +/* + * Constants. + */ + +#define TWIDJOY_MAX_LENGTH 5 + +static char *twidjoy_name = "Handykey Twiddler"; + +static struct twidjoy_button_spec { + int bitshift; + int bitmask; + int buttons[3]; +} +twidjoy_buttons[] = { + { 0, 3, { BTN_A, BTN_B, BTN_C } }, + { 2, 3, { BTN_X, BTN_Y, BTN_Z } }, + { 4, 3, { BTN_TL, BTN_TR, BTN_TR2 } }, + { 6, 3, { BTN_SELECT, BTN_START, BTN_MODE } }, + { 8, 1, { BTN_BASE5 } }, + { 9, 1, { BTN_BASE } }, + { 10, 1, { BTN_BASE3 } }, + { 11, 1, { BTN_BASE4 } }, + { 12, 1, { BTN_BASE2 } }, + { 13, 1, { BTN_BASE6 } }, + { 0, 0, { 0 } } +}; + +/* + * Per-Twiddler data. + */ + +struct twidjoy { + struct input_dev dev; + int idx; + unsigned char data[TWIDJOY_MAX_LENGTH]; + char phys[32]; +}; + +/* + * twidjoy_process_packet() decodes packets the driver receives from the + * Twiddler. It updates the data accordingly. + */ + +static void twidjoy_process_packet(struct twidjoy *twidjoy) +{ + if (twidjoy->idx == TWIDJOY_MAX_LENGTH) { + struct input_dev *dev = &twidjoy->dev; + unsigned char *data = twidjoy->data; + struct twidjoy_button_spec *bp; + int button_bits, abs_x, abs_y; + + button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f); + + for (bp = twidjoy_buttons; bp->bitmask; bp++) { + int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift; + int i; + + for (i = 0; i < bp->bitmask; i++) + input_report_key(dev, bp->buttons[i], i+1 == value); + } + + abs_x = ((data[4] & 0x07) << 5) | ((data[3] & 0x7C) >> 2); + if (data[4] & 0x08) abs_x -= 256; + + abs_y = ((data[3] & 0x01) << 7) | ((data[2] & 0x7F) >> 0); + if (data[3] & 0x02) abs_y -= 256; + + input_report_abs(dev, ABS_X, -abs_x); + input_report_abs(dev, ABS_Y, +abs_y); + } + + return; +} + +/* + * twidjoy_interrupt() is called by the low level driver when characters + * are ready for us. We then buffer them for further processing, or call the + * packet processing routine. + */ + +static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct twidjoy *twidjoy = serio->private; + + /* All Twiddler packets are 5 bytes. The fact that the first byte + * has a MSB of 0 and all other bytes have a MSB of 1 can be used + * to check and regain sync. */ + + if ((data & 0x80) == 0) + twidjoy->idx = 0; /* this byte starts a new packet */ + else if (twidjoy->idx == 0) + return; /* wrong MSB -- ignore this byte */ + + if (twidjoy->idx < TWIDJOY_MAX_LENGTH) + twidjoy->data[twidjoy->idx++] = data; + + if (twidjoy->idx == TWIDJOY_MAX_LENGTH) { + twidjoy_process_packet(twidjoy); + twidjoy->idx = 0; + } + + return; +} + +/* + * twidjoy_disconnect() is the opposite of twidjoy_connect() + */ + +static void twidjoy_disconnect(struct serio *serio) +{ + struct twidjoy *twidjoy = serio->private; + input_unregister_device(&twidjoy->dev); + serio_close(serio); + kfree(twidjoy); +} + +/* + * twidjoy_connect() is the routine that is called when someone adds a + * new serio device. It looks for the Twiddler, and if found, registers + * it as an input device. + */ + +static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) +{ + struct twidjoy_button_spec *bp; + struct twidjoy *twidjoy; + int i; + + if (serio->type != (SERIO_RS232 | SERIO_TWIDJOY)) + return; + + if (!(twidjoy = kmalloc(sizeof(struct twidjoy), GFP_KERNEL))) + return; + + memset(twidjoy, 0, sizeof(struct twidjoy)); + + sprintf(twidjoy->phys, "%s/input0", serio->phys); + + twidjoy->dev.name = twidjoy_name; + twidjoy->dev.phys = twidjoy->phys; + twidjoy->dev.idbus = BUS_RS232; + twidjoy->dev.idvendor = SERIO_TWIDJOY; + twidjoy->dev.idproduct = 0x0001; + twidjoy->dev.idversion = 0x0100; + + twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + + for (bp = twidjoy_buttons; bp->bitmask; bp++) { + for (i = 0; i < bp->bitmask; i++) + set_bit(bp->buttons[i], twidjoy->dev.keybit); + } + + twidjoy->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + + for (i = 0; i < 2; i++) { + twidjoy->dev.absmax[ABS_X+i] = 50; + twidjoy->dev.absmin[ABS_X+i] = -50; + + /* TODO: arndt 20010708: Are these values appropriate? */ + twidjoy->dev.absfuzz[ABS_X+i] = 4; + twidjoy->dev.absflat[ABS_X+i] = 4; + } + + twidjoy->dev.private = twidjoy; + + serio->private = twidjoy; + + if (serio_open(serio, dev)) { + kfree(twidjoy); + return; + } + + input_register_device(&twidjoy->dev); + + printk(KERN_INFO "input: %s on %s\n", twidjoy_name, serio->phys); +} + +/* + * The serio device structure. + */ + +static struct serio_dev twidjoy_dev = { + interrupt: twidjoy_interrupt, + connect: twidjoy_connect, + disconnect: twidjoy_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +int __init twidjoy_init(void) +{ + serio_register_device(&twidjoy_dev); + return 0; +} + +void __exit twidjoy_exit(void) +{ + serio_unregister_device(&twidjoy_dev); +} + +module_init(twidjoy_init); +module_exit(twidjoy_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/joystick/warrior.c linux-2.5/drivers/input/joystick/warrior.c --- linux-2.5.5/drivers/input/joystick/warrior.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/input/joystick/warrior.c Fri Mar 1 14:51:09 2002 @@ -1,9 +1,7 @@ /* - * $Id: warrior.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $ + * $Id: warrior.c,v 1.14 2002/01/22 20:32:10 vojtech Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1999-2001 Vojtech Pavlik */ /* @@ -27,7 +25,7 @@ * * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -37,6 +35,10 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Logitech WingMan Warrior joystick driver"); +MODULE_LICENSE("GPL"); + /* * Constants. */ @@ -53,6 +55,7 @@ struct input_dev dev; int idx, len; unsigned char data[WARRIOR_MAX_LENGTH]; + char phys[32]; }; /* @@ -149,7 +152,10 @@ warrior->dev.relbit[0] = BIT(REL_DIAL); warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y); + sprintf(warrior->phys, "%s/input0", serio->phys); + warrior->dev.name = warrior_name; + warrior->dev.phys = warrior->phys; warrior->dev.idbus = BUS_RS232; warrior->dev.idvendor = SERIO_WARRIOR; warrior->dev.idproduct = 0x0001; @@ -180,7 +186,7 @@ input_register_device(&warrior->dev); - printk(KERN_INFO "input%d: Logitech WingMan Warrior on serio%d\n", warrior->dev.number, serio->number); + printk(KERN_INFO "input: Logitech WingMan Warrior on %s\n", serio->phys); } /* @@ -210,5 +216,3 @@ module_init(warrior_init); module_exit(warrior_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/keybdev.c linux-2.5/drivers/input/keybdev.c --- linux-2.5.5/drivers/input/keybdev.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/input/keybdev.c Sun Jan 20 17:11:46 2002 @@ -154,6 +154,7 @@ #endif /* CONFIG_X86 || CONFIG_IA64 || __alpha__ || __mips__ || CONFIG_PPC */ + static struct input_handler keybdev_handler; void keybdev_ledfunc(unsigned int led) @@ -189,7 +190,10 @@ void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down) { if (type != EV_KEY) return; - emulate_raw(code, down); + + if (emulate_raw(code, down)) + printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", code); + tasklet_schedule(&keyboard_tasklet); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/keyboard/Config.help linux-2.5/drivers/input/keyboard/Config.help --- linux-2.5.5/drivers/input/keyboard/Config.help Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/keyboard/Config.help Thu Feb 14 00:58:44 2002 @@ -0,0 +1,66 @@ +CONFIG_INPUT_KEYBOARD + Say Y here, and a list of supported keyboards will be displayed. + This option doesn't affect the kernel. + + If unsure, say Y. + +CONFIG_KEYBOARD_ATKBD + Say Y here if you want to use the standard AT keyboard. Usually + you'll need this, unless you have a different type keyboard (USB, + ADB or other). + + If unsure, say Y. + + This driver 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 atkbd.o. If you want to compile it as a + module, say M here and read . + +CONFIG_KEYBOARD_SUNKBD + Say Y here if you want to use a Sun Type 4 or Type 5 keyboard, + connected either to the Sun keyboard connector or to an serial + (RS-232) port via a simple adapter. + + This driver 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 sunkbd.o. If you want to compile it as a + module, say M here and read . + +CONFIG_KEYBOARD_PS2SERKBD + Say Y here if you want to use a PS/2 to Serial converter with a + keyboard attached to it. + + This driver 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 ps2serkbd.o. If you want to compile it as a + module, say M here and read . + +CONFIG_KEYBOARD_XTKBD + Say Y here if you want to use the old IBM PC/XT keyboard (or + compatible) on your system. This is only possible with a + parallel port keyboard adapter, you cannot connect it to the + keyboard port on a PC that runs Linux. + + This driver 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 xtkbd.o. If you want to compile it as a + module, say M here and read . + +CONFIG_KEYBOARD_MAPLE + Say Y here if you have a DreamCast console running Linux and have + a keyboard attached to its Maple bus. + + This driver 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 maple_keyb.o. If you want to compile it as a + module, say M here and read . + +CONFIG_KEYBOARD_AMIGA + Say Y here if you are running Linux on any AMIGA and have a keyboard + attached. + + This driver 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 amikbd.o. If you want to compile it as a + module, say M here and read . + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/keyboard/Config.in linux-2.5/drivers/input/keyboard/Config.in --- linux-2.5.5/drivers/input/keyboard/Config.in Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/keyboard/Config.in Thu Feb 14 00:58:44 2002 @@ -0,0 +1,18 @@ +# +# Input core configuration +# + +bool 'Keyboards' CONFIG_INPUT_KEYBOARD + +dep_tristate ' AT keyboard support' CONFIG_KEYBOARD_ATKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO +dep_tristate ' Sun Type 4 and Type 5 keyboard support' CONFIG_KEYBOARD_SUNKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO +dep_tristate ' PS/2 to Serial converter support' CONFIG_KEYBOARD_PS2SERKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO +dep_tristate ' XT Keyboard support' CONFIG_KEYBOARD_XTKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO + +if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then + dep_tristate ' Maple bus keyboard support' CONFIG_KEYBOARD_MAPLE $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_MAPLE +fi + +if [ "$CONFIG_AMIGA" = "y" ]; then + dep_tristate ' Amiga keyboard' CONFIG_KEYBOARD_AMIGA $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD +fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/keyboard/Makefile linux-2.5/drivers/input/keyboard/Makefile --- linux-2.5.5/drivers/input/keyboard/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/keyboard/Makefile Thu Feb 14 00:58:44 2002 @@ -0,0 +1,20 @@ +# +# Makefile for the input core drivers. +# + +# The target object and module list name. + +O_TARGET := keybdrv.o + +# Each configuration option enables a list of files. + +obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o +obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o +obj-$(CONFIG_KEYBOARD_PS2SERKBD) += ps2serkbd.o +obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o +obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o +obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o + +# The global Rules.make. + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/keyboard/amikbd.c linux-2.5/drivers/input/keyboard/amikbd.c --- linux-2.5.5/drivers/input/keyboard/amikbd.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/keyboard/amikbd.c Fri Feb 15 19:04:42 2002 @@ -0,0 +1,144 @@ +/* + * $Id: amikbd.c,v 1.13 2002/02/01 16:02:24 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * + * Based on the work of: + * Hamish Macdonald + */ + +/* + * Amiga keyboard driver for Linux/m68k + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include + +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Amiga keyboard driver"); +MODULE_LICENSE("GPL"); + +static unsigned char amikbd_keycode[0x78] = { + 41, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 43, 0, 82, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 0, 79, 80, 81, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 0, 0, 75, 76, 77, + 0, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 0, 83, 71, 72, 73, + 57, 14, 15, 96, 28, 1,111, 0, 0, 0, 74, 0,103,108,106,105, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 98, 55, 78, 87, + 42, 54, 58, 29, 56,100 +} + +static char *amikbd_messages[] = { + KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n", + KERN_WARNING "amikbd: keyboard lost sync\n", + KERN_WARNING "amikbd: keyboard buffer overflow\n", + KERN_WARNING "amikbd: keyboard controller failure\n", + KERN_ERR "amikbd: keyboard selftest failure\n", + KERN_INFO "amikbd: initiate power-up key stream\n", + KERN_INFO "amikbd: terminate power-up key stream\n", + KERN_WARNING "amikbd: keyboard interrupt\n" +}; + +static struct input_dev amikbd_dev; + +static char *amikbd_name = "Amiga keyboard"; +static char *amikbd_phys = "amikbd/input0"; + +static void amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp) +{ + unsigned char scancode, down; + + scancode = ~ciaa.sdr; /* get and invert scancode (keyboard is active low) */ + ciaa.cra |= 0x40; /* switch SP pin to output for handshake */ + udelay(85); /* wait until 85 us have expired */ + ciaa.cra &= ~0x40; /* switch CIA serial port to input mode */ + + down = scancode & 1; /* lowest bit is release bit */ + scancode = scancode >> 1; + + if (scancode < 0x78) { /* scancodes < 0x78 are keys */ + + scancode = amikbd_keycode[scancode]; + + if (scancode == KEY_CAPS) { /* CapsLock is a toggle switch key on Amiga */ + input_report_key(&amikbd_dev, scancode, 1); + input_report_key(&amikbd_dev, scancode, 0); + return; + } + + input_report_key(&amikbd_dev, scancode, down); + + return; + } + + printk(amikbd_messages[scancode - 0x78]); /* scancodes >= 0x78 are error codes */ +} + +static int __init amikbd_init(void) +{ + int i; + + if (!AMIGAHW_PRESENT(AMI_KEYBOARD)) + return -EIO; + + if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb")) + return -EBUSY; + + amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + amikbd_dev.keycode = amikbd_keycode; + + for (i = 0; i < 0x78; i++) + if (amikbd_keycode[i]) + set_bit(amikbd_keycode[i], amikbd_dev.keybit); + + ciaa.cra &= ~0x41; /* serial data in, turn off TA */ + request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", NULL); + + amikbd_dev.name = amikbd_name; + amikbd_dev.phys = amikbd_phys; + amikbd_dev.idbus = BUS_AMIGA; + amikbd_dev.idvendor = 0x0001; + amikbd_dev.idproduct = 0x0001; + amikbd_dev.idversion = 0x0100; + + input_register_device(&amikbd_dev); + + printk(KERN_INFO "input: %s\n", amikbd_name); + + return 0; +} + +static void __exit amikbd_exit(void) +{ + input_unregister_device(&amikbd_dev); + free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt); + release_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100); +} + +module_init(amikbd_init); +module_exit(amikbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/keyboard/atkbd.c linux-2.5/drivers/input/keyboard/atkbd.c --- linux-2.5.5/drivers/input/keyboard/atkbd.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/keyboard/atkbd.c Mon Jan 28 12:38:10 2002 @@ -0,0 +1,551 @@ +/* + * $Id: atkbd.c,v 1.31 2002/01/27 01:48:54 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); +MODULE_PARM(atkbd_set, "1i"); +MODULE_LICENSE("GPL"); + +static int atkbd_set = 2; + +/* + * Scancode to keycode tables. These are just the default setting, and + * are loadable via an userland utility. + */ + +static unsigned char atkbd_set2_keycode[512] = { + 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85, + 0, 56, 42, 0, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90, + 0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0, + 0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0, + 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, + 122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0, + 85, 86, 90, 91, 92, 93, 14, 94, 95, 79, 0, 75, 71,121, 0,123, + 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, + 252, 0, 0, 65, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,251, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, + 0, 0, 92, 90, 85, 0,137, 0, 0, 0, 0, 91, 89,144,115, 0, + 136,100,255, 0, 97,149,164, 0,156, 0, 0,140,115, 0, 0,125, + 0,150, 0,154,152,163,151,126,112,166, 0,140, 0,147, 0,127, + 159,167,139,160,163, 0, 0,116,158, 0,150,165, 0, 0, 0,142, + 157, 0,114,166,168, 0, 0, 0,155, 0, 98,113, 0,148, 0,138, + 0, 0, 0, 0, 0, 0,153,140, 0,255, 96, 0, 0, 0,143, 0, + 133, 0,116, 0,143, 0,174,133, 0,107, 0,105,102, 0, 0,112, + 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119 +}; + +static unsigned char atkbd_set3_keycode[512] = { + 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60, + 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62, + 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64, + 136, 49, 48, 35, 34, 21, 7, 65,137,100, 50, 36, 22, 8, 9, 66, + 125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68, + 113,114, 40, 84, 26, 13, 87, 99,100, 54, 28, 27, 43, 84, 88, 70, + 108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104, + 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55, 85, + 89, 90, 91, 92, 74, 0, 0, 0, 0, 0, 0,125,126,127,112, 0, + 0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168, + 148,149,147,140, 0, 0, 0, 0, 0, 0,251, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255 +}; + +#define ATKBD_CMD_SETLEDS 0x10ed +#define ATKBD_CMD_GSCANSET 0x11f0 +#define ATKBD_CMD_SSCANSET 0x10f0 +#define ATKBD_CMD_GETID 0x02f2 +#define ATKBD_CMD_ENABLE 0x00f4 +#define ATKBD_CMD_RESET_DIS 0x00f5 +#define ATKBD_CMD_SETALL_MB 0x00f8 +#define ATKBD_CMD_EX_ENABLE 0x10ea +#define ATKBD_CMD_EX_SETLEDS 0x20eb + +#define ATKBD_RET_ACK 0xfa +#define ATKBD_RET_NAK 0xfe + +#define ATKBD_KEY_UNKNOWN 0 +#define ATKBD_KEY_BAT 251 +#define ATKBD_KEY_EMUL0 252 +#define ATKBD_KEY_EMUL1 253 +#define ATKBD_KEY_RELEASE 254 +#define ATKBD_KEY_NULL 255 + +/* + * The atkbd control structure + */ + +struct atkbd { + unsigned char keycode[512]; + struct input_dev dev; + struct serio *serio; + char name[64]; + char phys[32]; + struct tq_struct tq; + unsigned char cmdbuf[4]; + unsigned char cmdcnt; + unsigned char set; + char release; + char ack; + char emul; + char error; + unsigned short id; +}; + +/* + * atkbd_interrupt(). Here takes place processing of data received from + * the keyboard into events. + */ + +static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct atkbd *atkbd = serio->private; + int code = data; + +#ifdef ATKBD_DEBUG + printk(KERN_DEBUG "atkbd.c: Received %02x\n", data); +#endif + + switch (code) { + case ATKBD_RET_ACK: + atkbd->ack = 1; + return; + case ATKBD_RET_NAK: + atkbd->ack = -1; + return; + } + + if (atkbd->cmdcnt) { + atkbd->cmdbuf[--atkbd->cmdcnt] = code; + return; + } + + switch (atkbd->keycode[code]) { + case ATKBD_KEY_BAT: + queue_task(&atkbd->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return; + case ATKBD_KEY_EMUL0: + atkbd->emul = 1; + return; + case ATKBD_KEY_EMUL1: + atkbd->emul = 2; + return; + case ATKBD_KEY_RELEASE: + atkbd->release = 1; + return; + } + + if (atkbd->emul) { + if (--atkbd->emul) return; + code |= 0x100; + } + + switch (atkbd->keycode[code]) { + case ATKBD_KEY_NULL: + break; + case ATKBD_KEY_UNKNOWN: + printk(KERN_WARNING "atkbd.c: Unknown key (set %d, scancode %#x, on %s) %s.\n", + atkbd->set, code, serio->phys, atkbd->release ? "released" : "pressed"); + break; + default: + input_report_key(&atkbd->dev, atkbd->keycode[code], !atkbd->release); + } + + atkbd->release = 0; +} + +/* + * atkbd_sendbyte() sends a byte to the keyboard, and waits for + * acknowledge. It doesn't handle resends according to the keyboard + * protocol specs, because if these are needed, the keyboard needs + * replacement anyway, and they only make a mess in the protocol. + */ + +static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) +{ + int timeout = 1000; /* 10 msec */ + atkbd->ack = 0; + +#ifdef ATKBD_DEBUG + printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte); +#endif + serio_write(atkbd->serio, byte); + while (!atkbd->ack && timeout--) udelay(10); + + return -(atkbd->ack <= 0); +} + +/* + * atkbd_command() sends a command, and its parameters to the keyboard, + * then waits for the response and puts it in the param array. + */ + +static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) +{ + int timeout = 10000; /* 100 msec */ + int send = (command >> 12) & 0xf; + int receive = (command >> 8) & 0xf; + int i; + + atkbd->cmdcnt = receive; + + if (command & 0xff) + if (atkbd_sendbyte(atkbd, command & 0xff)) + return (atkbd->cmdcnt = 0) - 1; + + for (i = 0; i < send; i++) + if (atkbd_sendbyte(atkbd, param[i])) + return (atkbd->cmdcnt = 0) - 1; + + while (atkbd->cmdcnt && timeout--) udelay(10); + + for (i = 0; i < receive; i++) + param[i] = atkbd->cmdbuf[(receive - 1) - i]; + + if (atkbd->cmdcnt) + return (atkbd->cmdcnt = 0) - 1; + + return 0; +} + +/* + * Event callback from the input module. Events that change the state of + * the hardware are processed here. + */ + +static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct atkbd *atkbd = dev->private; + char param[2]; + + switch (type) { + + case EV_LED: + + *param = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) + | (test_bit(LED_NUML, dev->led) ? 2 : 0) + | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); + atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS); + + if (atkbd->set == 4) { + param[0] = 0; + param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) + | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) + | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) + | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); + atkbd_command(atkbd, param, ATKBD_CMD_EX_SETLEDS); + } + + return 0; + } + + return -1; +} + +/* + * atkbd_set_3 checks if a keyboard has a working Set 3 support, and + * sets it into that. Unfortunately there are keyboards that can be switched + * to Set 3, but don't work well in that (BTC Multimedia ...) + */ + +static int atkbd_set_3(struct atkbd *atkbd) +{ + unsigned char param; + +/* + * For known special keyboards we can go ahead and set the correct set. + */ + + if (atkbd->id == 0xaca1) { + param = 3; + atkbd_command(atkbd, ¶m, ATKBD_CMD_SSCANSET); + return 3; + } + +/* + * We check for the extra keys on an some keyboards that need extra + * command to get enabled. This shouldn't harm any keyboards not + * knowing the command. + */ + + param = 0x71; + if (!atkbd_command(atkbd, ¶m, ATKBD_CMD_EX_ENABLE)) + return 4; + +/* + * Try to set the set we want. + */ + + param = atkbd_set; + if (atkbd_command(atkbd, ¶m, ATKBD_CMD_SSCANSET)) + return 2; + +/* + * Read set number. Beware here. Some keyboards always send '2' + * or some other number regardless into what mode they have been + * attempted to be set. Other keyboards treat the '0' command as + * 'set to set 0', and not 'report current set' as they should. + * In that case we time out, and return 2. + */ + + param = 0; + if (atkbd_command(atkbd, ¶m, ATKBD_CMD_GSCANSET)) + return 2; + +/* + * Here we return the set number the keyboard reports about + * itself. + */ + + return (param == 3) ? 3 : 2; +} + +/* + * atkbd_probe() probes for an AT keyboard on a serio port. + */ + +static int atkbd_probe(struct atkbd *atkbd) +{ + unsigned char param[2]; + +/* + * Full reset with selftest can on some keyboards be annoyingly slow, + * so we just do a reset-and-disable on the keyboard, which + * is considerably faster, but doesn't have to reset everything. + */ + + if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_DIS)) + return -1; + +/* + * Next, we check if it's a keyboard. It should send 0xab83 + * (0xab84 on IBM ThinkPad, and 0xaca1 on a NCD Sun layout keyboard, + * 0xab02 on unxlated i8042 and 0xab03 on unxlated ThinkPad, 0xab7f + * on Fujitsu Lifebook). + * If it's a mouse, it'll only send 0x00 (0x03 if it's MS mouse), + * and we'll time out here, and report an error. + */ + + param[0] = param[1] = 0; + + if (atkbd_command(atkbd, param, ATKBD_CMD_GETID)) + return -1; + + atkbd->id = (param[0] << 8) | param[1]; + + if (atkbd->id != 0xab83 && atkbd->id != 0xab84 && atkbd->id != 0xaca1 && + atkbd->id != 0xab7f && atkbd->id != 0xab02 && atkbd->id != 0xab03) + printk(KERN_WARNING "atkbd.c: Unusual keyboard ID: %#x on %s\n", + atkbd->id, atkbd->serio->phys); + + return 0; +} + +/* + * atkbd_initialize() sets the keyboard into a sane state. + */ + +static void atkbd_initialize(struct atkbd *atkbd) +{ + unsigned char param; + +/* + * Disable autorepeat. We don't need it, as we do it in software anyway, + * because that way can get faster repeat, and have less system load + * (less accesses to the slow ISA hardware). If this fails, we don't care, + * and will just ignore the repeated keys. + */ + + atkbd_command(atkbd, NULL, ATKBD_CMD_SETALL_MB); + +/* + * We also shut off all the leds. The console code will turn them back on, + * if needed. + */ + + param = 0; + atkbd_command(atkbd, ¶m, ATKBD_CMD_SETLEDS); + +/* + * Last, we enable the keyboard so that we get keypresses from it. + */ + + if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE)) + printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n", + atkbd->serio->phys); +} + +/* + * atkbd_disconnect() cleans up behind us ... + */ + +static void atkbd_disconnect(struct serio *serio) +{ + struct atkbd *atkbd = serio->private; + input_unregister_device(&atkbd->dev); + serio_close(serio); + kfree(atkbd); +} + +/* + * atkbd_powerup() is called when the keyboard sends the 0xaa character, + * meaning that it was disconnected and reconnected. We close the port + * in that case and let the upper layer find an appropriate driver for + * the device that was connected. It may be a mouse, or a keyboard, we + * don't know yet. + */ + +static void atkbd_powerup(void *data) +{ + struct atkbd *atkbd = data; + mdelay(40); /* FIXME!!! Wait some nicer way */ + serio_rescan(atkbd->serio); +} + +/* + * atkbd_connect() is called when the serio module finds and interface + * that isn't handled yet by an appropriate device driver. We check if + * there is an AT keyboard out there and if yes, we register ourselves + * to the input module. + */ + +static void atkbd_connect(struct serio *serio, struct serio_dev *dev) +{ + struct atkbd *atkbd; + int i; + + if ((serio->type & SERIO_TYPE) != SERIO_8042) + return; + + if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL))) + return; + + memset(atkbd, 0, sizeof(struct atkbd)); + + atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); + + atkbd->serio = serio; + + atkbd->dev.keycode = atkbd->keycode; + atkbd->dev.event = atkbd_event; + atkbd->dev.private = atkbd; + + atkbd->tq.routine = atkbd_powerup; + atkbd->tq.data = atkbd; + + serio->private = atkbd; + + if (serio_open(serio, dev)) { + kfree(atkbd); + return; + } + + if (atkbd_probe(atkbd)) { + serio_close(serio); + kfree(atkbd); + return; + } + + atkbd->set = atkbd_set_3(atkbd); + + if (atkbd->set == 4) { + atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE); + sprintf(atkbd->name, "AT Set 2 Extended keyboard\n"); + } else + sprintf(atkbd->name, "AT Set %d keyboard", atkbd->set); + + sprintf(atkbd->phys, "%s/input0", serio->phys); + + if (atkbd->set == 3) + memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); + else + memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); + + atkbd->dev.name = atkbd->name; + atkbd->dev.phys = atkbd->phys; + atkbd->dev.idbus = BUS_I8042; + atkbd->dev.idvendor = 0x0001; + atkbd->dev.idproduct = atkbd->set; + atkbd->dev.idversion = atkbd->id; + + for (i = 0; i < 512; i++) + if (atkbd->keycode[i] && atkbd->keycode[i] <= 250) + set_bit(atkbd->keycode[i], atkbd->dev.keybit); + + input_register_device(&atkbd->dev); + + printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); + + atkbd_initialize(atkbd); +} + + +static struct serio_dev atkbd_dev = { + interrupt: atkbd_interrupt, + connect: atkbd_connect, + disconnect: atkbd_disconnect +}; + +/* + * Module init and exit. + */ + +void __init atkbd_setup(char *str, int *ints) +{ + if (!ints[0]) atkbd_set = ints[1]; +} + +int __init atkbd_init(void) +{ + serio_register_device(&atkbd_dev); + return 0; +} + +void __exit atkbd_exit(void) +{ + serio_unregister_device(&atkbd_dev); +} + +module_init(atkbd_init); +module_exit(atkbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/keyboard/maple_keyb.c linux-2.5/drivers/input/keyboard/maple_keyb.c --- linux-2.5.5/drivers/input/keyboard/maple_keyb.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/keyboard/maple_keyb.c Fri Feb 15 18:03:02 2002 @@ -0,0 +1,190 @@ +/* + * $Id: maple_keyb.c,v 1.1 2001/11/02 17:27:32 jsimmons Exp $ + * SEGA Dreamcast keyboard driver + * Based on drivers/usb/usbkbd.c + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("YAEGASHI Takeshi "); +MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver"); + +static unsigned char dc_kbd_keycode[256] = { + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, + 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, + 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, + 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, + 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, + 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113, + 115,114, 0, 0, 0,124, 0,181,182,183,184,185,186,187,188,189, + 190,191,192,193,194,195,196,197,198, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, + 150,158,159,128,136,177,178,176,142,152,173,140 +}; + + +struct dc_kbd { + struct input_dev dev; + unsigned char new[8]; + unsigned char old[8]; + int open; +}; + + +static void dc_scan_kbd(struct dc_kbd *kbd) +{ + int i; + struct input_dev *dev = &kbd->dev; + + for(i=0; i<8; i++) + input_report_key(dev, + dc_kbd_keycode[i+224], + (kbd->new[0]>>i)&1); + + for(i=2; i<8; i++) { + + if(kbd->old[i]>3&&memscan(kbd->new+2, kbd->old[i], 6)==NULL) { + if(dc_kbd_keycode[kbd->old[i]]) + input_report_key(dev, + dc_kbd_keycode[kbd->old[i]], + 0); + else + printk("Unknown key (scancode %#x) released.", + kbd->old[i]); + } + + if(kbd->new[i]>3&&memscan(kbd->old+2, kbd->new[i], 6)!=NULL) { + if(dc_kbd_keycode[kbd->new[i]]) + input_report_key(dev, + dc_kbd_keycode[kbd->new[i]], + 1); + else + printk("Unknown key (scancode %#x) pressed.", + kbd->new[i]); + } + } + + memcpy(kbd->old, kbd->new, 8); +} + + +static void dc_kbd_callback(struct mapleq *mq) +{ + struct maple_device *mapledev = mq->dev; + struct dc_kbd *kbd = mapledev->private_data; + unsigned long *buf = mq->recvbuf; + + if (buf[1] == mapledev->function) { + memcpy(kbd->new, buf+2, 8); + dc_scan_kbd(kbd); + } +} + + +static int dc_kbd_open(struct input_dev *dev) +{ + struct dc_kbd *kbd = dev->private; + kbd->open++; + return 0; +} + + +static void dc_kbd_close(struct input_dev *dev) +{ + struct dc_kbd *kbd = dev->private; + kbd->open--; +} + + +static int dc_kbd_connect(struct maple_device *dev) +{ + int i; + unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); + struct dc_kbd *kbd; + + if (!(kbd = kmalloc(sizeof(struct dc_kbd), GFP_KERNEL))) + return -1; + memset(kbd, 0, sizeof(struct dc_kbd)); + + dev->private_data = kbd; + + kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + + for (i=0; i<255; i++) + set_bit(dc_kbd_keycode[i], kbd->dev.keybit); + clear_bit(0, kbd->dev.keybit); + + kbd->dev.private = kbd; + kbd->dev.open = dc_kbd_open; + kbd->dev.close = dc_kbd_close; + kbd->dev.event = NULL; + + kbd->dev.name = dev->product_name; + kbd->dev.idbus = BUS_MAPLE; + + input_register_device(&kbd->dev); + + maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD); + + printk(KERN_INFO "input%d: keyboard(0x%lx): %s\n", + kbd->dev.number, data, kbd->dev.name); + + MOD_INC_USE_COUNT; + + return 0; +} + + +static void dc_kbd_disconnect(struct maple_device *dev) +{ + struct dc_kbd *kbd = dev->private_data; + + input_unregister_device(&kbd->dev); + + kfree(kbd); + + MOD_DEC_USE_COUNT; +} + + +static struct maple_driver dc_kbd_driver = { + function: MAPLE_FUNC_KEYBOARD, + name: "Dreamcast keyboard", + connect: dc_kbd_connect, + disconnect: dc_kbd_disconnect, +}; + + +static int __init dc_kbd_init(void) +{ + maple_register_driver(&dc_kbd_driver); + return 0; +} + + +static void __exit dc_kbd_exit(void) +{ + maple_unregister_driver(&dc_kbd_driver); +} + + +module_init(dc_kbd_init); +module_exit(dc_kbd_exit); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/keyboard/ps2serkbd.c linux-2.5/drivers/input/keyboard/ps2serkbd.c --- linux-2.5.5/drivers/input/keyboard/ps2serkbd.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/keyboard/ps2serkbd.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,297 @@ +/* + * based on: sunkbd.c and ps2serkbd.c + * + * $Id: ps2serkbd.c,v 1.5 2001/09/25 10:12:07 vojtech Exp $ + */ + +/* + * PS/2 keyboard via adapter at serial port driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ATKBD_CMD_SETLEDS 0x10ed +#define ATKBD_CMD_GSCANSET 0x11f0 +#define ATKBD_CMD_SSCANSET 0x10f0 +#define ATKBD_CMD_GETID 0x02f2 +#define ATKBD_CMD_ENABLE 0x00f4 +#define ATKBD_CMD_RESET_DIS 0x00f5 +#define ATKBD_CMD_SETALL_MB 0x00f8 +#define ATKBD_CMD_EX_ENABLE 0x10ea +#define ATKBD_CMD_EX_SETLEDS 0x20eb + +#define ATKBD_RET_ACK 0xfa +#define ATKBD_RET_NAK 0xfe + +#define ATKBD_KEY_UNKNOWN 0 +#define ATKBD_KEY_BAT 251 +#define ATKBD_KEY_EMUL0 252 +#define ATKBD_KEY_EMUL1 253 +#define ATKBD_KEY_RELEASE 254 +#define ATKBD_KEY_NULL 255 + +static unsigned char ps2serkbd_set2_keycode[512] = { + 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85, + 0, 56, 42, 0, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90, + 0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0, + 0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0, + 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, + 122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0, + 85, 86, 90, 91, 92, 93, 14, 94, 95, 79, 0, 75, 71,121, 0,123, + 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, + 252, 0, 0, 65, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,251, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, + 0, 0, 92, 90, 85, 0,137, 0, 0, 0, 0, 91, 89,144,115, 0, + 136,100,255, 0, 97,149,164, 0,156, 0, 0,140,115, 0, 0,125, + 0,150, 0,154,152,163,151,126,112,166, 0,140, 0,147, 0,127, + 159,167,139,160,163, 0, 0,116,158, 0,150,165, 0, 0, 0,142, + 157, 0,114,166,168, 0, 0, 0,155, 0, 98,113, 0,148, 0,138, + 0, 0, 0, 0, 0, 0,153,140, 0, 0, 96, 0, 0, 0,143, 0, + 133, 0,116, 0,143, 0,174,133, 0,107, 0,105,102, 0, 0,112, + 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119 +}; + +/* + * Per-keyboard data. + */ + +struct ps2serkbd { + unsigned char keycode[512]; + struct input_dev dev; + struct serio *serio; + char name[64]; + char phys[32]; + struct tq_struct tq; + unsigned char cmdbuf[4]; + unsigned char cmdcnt; + unsigned char set; + char release; + char ack; + char emul; + char error; + unsigned short id; +}; + +/* + * ps2serkbd_interrupt() is called by the low level driver when a character + * is received. + */ + +static void ps2serkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + static int event_count=0; + struct ps2serkbd* ps2serkbd = serio->private; + int code=data; + +#if 0 + printk(KERN_WARNING "ps2serkbd.c(%8d): (scancode %#x)\n", event_count, data); +#endif + event_count++; + + switch (code) { + case ATKBD_RET_ACK: + ps2serkbd->ack = 1; + return; + case ATKBD_RET_NAK: + ps2serkbd->ack = -1; + return; + } + + if (ps2serkbd->cmdcnt) { + ps2serkbd->cmdbuf[--ps2serkbd->cmdcnt] = code; + return; + } + + switch (ps2serkbd->keycode[code]) { + case ATKBD_KEY_BAT: + queue_task(&ps2serkbd->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return; + case ATKBD_KEY_EMUL0: + ps2serkbd->emul = 1; + return; + case ATKBD_KEY_EMUL1: + ps2serkbd->emul = 2; + return; + case ATKBD_KEY_RELEASE: + ps2serkbd->release = 1; + return; + } + + if (ps2serkbd->emul) { + if (--ps2serkbd->emul) return; + code |= 0x100; + } + + switch (ps2serkbd->keycode[code]) { + case ATKBD_KEY_NULL: + break; + case ATKBD_KEY_UNKNOWN: + printk(KERN_WARNING "ps2serkbd.c: Unknown key (set %d, scancode %#x) %s.\n", + ps2serkbd->set, code, ps2serkbd->release ? "released" : "pressed"); + break; + default: + input_report_key(&ps2serkbd->dev, ps2serkbd->keycode[code], !ps2serkbd->release); + } + + ps2serkbd->release = 0; +} + +/* + * ps2serkbd_event() handles events from the input module. + */ + +static int ps2serkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + switch (type) { + + case EV_LED: + + return 0; + } + + return -1; +} + +static int ps2serkbd_initialize(struct ps2serkbd *ps2serkbd) +{ + return 0; +} + +static void ps2serkbd_reinit(void *data) +{ +} + + +static void ps2serkbd_connect(struct serio *serio, struct serio_dev *dev) +{ + struct ps2serkbd *ps2serkbd; + int i; + + if ((serio->type & SERIO_TYPE) != SERIO_RS232) + return; + + if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_PS2SER) + return; + + + if (!(ps2serkbd = kmalloc(sizeof(struct ps2serkbd), GFP_KERNEL))) + return; + + memset(ps2serkbd, 0, sizeof(struct ps2serkbd)); + + ps2serkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + ps2serkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); + + ps2serkbd->serio = serio; + + ps2serkbd->dev.keycode = ps2serkbd->keycode; + ps2serkbd->dev.event = ps2serkbd_event; + ps2serkbd->dev.private = ps2serkbd; + + ps2serkbd->tq.routine = ps2serkbd_reinit; + ps2serkbd->tq.data = ps2serkbd; + + serio->private = ps2serkbd; + + if (serio_open(serio, dev)) { + kfree(ps2serkbd); + return; + } + + if (ps2serkbd_initialize(ps2serkbd) < 0) { + serio_close(serio); + kfree(ps2serkbd); + return; + } + + ps2serkbd->set = 4; + + if (ps2serkbd->set == 4) { + ps2serkbd->dev.ledbit[0] |= 0; + sprintf(ps2serkbd->name, "AT Set 2 Extended keyboard\n"); + } + memcpy(ps2serkbd->keycode, ps2serkbd_set2_keycode, sizeof(ps2serkbd->keycode)); + + sprintf(ps2serkbd->phys, "%s/input0", serio->phys); + + ps2serkbd->dev.name = ps2serkbd->name; + ps2serkbd->dev.phys = ps2serkbd->phys; + ps2serkbd->dev.idbus = BUS_RS232; + ps2serkbd->dev.idvendor = SERIO_PS2SER; + ps2serkbd->dev.idproduct = ps2serkbd->set; + ps2serkbd->dev.idversion = ps2serkbd->id; + + for (i = 0; i < 512; i++) + if (ps2serkbd->keycode[i] && ps2serkbd->keycode[i] <= 250) + set_bit(ps2serkbd->keycode[i], ps2serkbd->dev.keybit); + + input_register_device(&ps2serkbd->dev); +} + +/* + * ps2serkbd_disconnect() unregisters and closes behind us. + */ + +static void ps2serkbd_disconnect(struct serio *serio) +{ + struct ps2serkbd *ps2serkbd = serio->private; + input_unregister_device(&ps2serkbd->dev); + serio_close(serio); + kfree(ps2serkbd); +} + +static struct serio_dev ps2serkbd_dev = { +interrupt: + ps2serkbd_interrupt, +connect: + ps2serkbd_connect, +disconnect: + ps2serkbd_disconnect +}; + +/* + * The functions for insering/removing us as a module. + */ + +int __init ps2serkbd_init(void) +{ + serio_register_device(&ps2serkbd_dev); + return 0; +} + +void __exit ps2serkbd_exit(void) +{ + serio_unregister_device(&ps2serkbd_dev); +} + +module_init(ps2serkbd_init); +module_exit(ps2serkbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/keyboard/sunkbd.c linux-2.5/drivers/input/keyboard/sunkbd.c --- linux-2.5.5/drivers/input/keyboard/sunkbd.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/keyboard/sunkbd.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,317 @@ +/* + * $Id: sunkbd.c,v 1.14 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * Sun keyboard driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Sun keyboard driver"); +MODULE_LICENSE("GPL"); + +static unsigned char sunkbd_keycode[128] = { + 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64, 0, + 65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, 14,110,113, 98, 55, + 116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27,111,127, 71, 72, 73, 74,134,135,107, 0, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 43, 28, 96, 75, 76, 77, 82,136, + 104,137, 69, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,101, + 79, 80, 81, 0, 0, 0,138, 58,125, 57,126,109, 86, 78 +}; + +#define SUNKBD_CMD_RESET 0x1 +#define SUNKBD_CMD_BELLON 0x2 +#define SUNKBD_CMD_BELLOFF 0x3 +#define SUNKBD_CMD_CLICK 0xa +#define SUNKBD_CMD_NOCLICK 0xb +#define SUNKBD_CMD_SETLED 0xe +#define SUNKBD_CMD_LAYOUT 0xf + +#define SUNKBD_RET_RESET 0xff +#define SUNKBD_RET_ALLUP 0x7f +#define SUNKBD_RET_LAYOUT 0xfe + +#define SUNKBD_LAYOUT_5_MASK 0x20 +#define SUNKBD_RELEASE 0x80 +#define SUNKBD_KEY 0x7f + +/* + * Per-keyboard data. + */ + +struct sunkbd { + unsigned char keycode[128]; + struct input_dev dev; + struct serio *serio; + struct tq_struct tq; + char name[64]; + char phys[32]; + char type; + char reset; + char layout; +}; + +/* + * sunkbd_interrupt() is called by the low level driver when a character + * is received. + */ + +static void sunkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct sunkbd* sunkbd = serio->private; + + if (sunkbd->reset <= -1) { /* If cp[i] is 0xff, sunkbd->reset will stay -1. */ + sunkbd->reset = data; /* The keyboard sends 0xff 0xff 0xID on powerup */ + return; + } + + if (sunkbd->layout == -1) { + sunkbd->layout = data; + return; + } + + switch (data) { + + case SUNKBD_RET_RESET: + queue_task(&sunkbd->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + sunkbd->reset = -1; + return; + + case SUNKBD_RET_LAYOUT: + sunkbd->layout = -1; + return; + + case SUNKBD_RET_ALLUP: /* All keys released */ + return; + + default: + if (sunkbd->keycode[data & SUNKBD_KEY]) { + input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE)); + } else { + printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n", + data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed"); + } + } +} + +/* + * sunkbd_event() handles events from the input module. + */ + +static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct sunkbd *sunkbd = dev->private; + + switch (type) { + + case EV_LED: + + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); + sunkbd->serio->write(sunkbd->serio, + (!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) | + (!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led)); + return 0; + + case EV_SND: + + switch (code) { + + case SND_CLICK: + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); + return 0; + + case SND_BELL: + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); + return 0; + } + + break; + } + + return -1; +} + +/* + * sunkbd_initialize() checks for a Sun keyboard attached, and determines + * its type. + */ + +static int sunkbd_initialize(struct sunkbd *sunkbd) +{ + int t; + + t = 1000; + sunkbd->reset = -2; + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET); + while (sunkbd->reset < 0 && --t) mdelay(1); + if (!t) return -1; + + sunkbd->type = sunkbd->reset; + + if (sunkbd->type == 4) { /* Type 4 keyboard */ + t = 250; + sunkbd->layout = -2; + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT); + while (sunkbd->layout < 0 && --t) mdelay(1); + if (!t) return -1; + if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5; + } + + return 0; +} + +/* + * sunkbd_reinit() sets leds and beeps to a state the computer remembers they + * were in. + */ + +static void sunkbd_reinit(void *data) +{ + struct sunkbd *sunkbd = data; + int t = 1000; + + while (sunkbd->reset < 0 && --t) mdelay(1); + + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); + sunkbd->serio->write(sunkbd->serio, + (!!test_bit(LED_CAPSL, sunkbd->dev.led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev.led) << 2) | + (!!test_bit(LED_COMPOSE, sunkbd->dev.led) << 1) | !!test_bit(LED_NUML, sunkbd->dev.led)); + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev.snd)); + sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev.snd)); +} + +/* + * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures. + */ + +static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) +{ + struct sunkbd *sunkbd; + int i; + + if ((serio->type & SERIO_TYPE) != SERIO_RS232) + return; + + if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_SUNKBD) + return; + + if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL))) + return; + + memset(sunkbd, 0, sizeof(struct sunkbd)); + + sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP); + sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML); + sunkbd->dev.sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL); + + sunkbd->serio = serio; + + sunkbd->tq.routine = sunkbd_reinit; + sunkbd->tq.data = sunkbd; + + sunkbd->dev.keycode = sunkbd->keycode; + sunkbd->dev.event = sunkbd_event; + sunkbd->dev.private = sunkbd; + + serio->private = sunkbd; + + if (serio_open(serio, dev)) { + kfree(sunkbd); + return; + } + + if (sunkbd_initialize(sunkbd) < 0) { + serio_close(serio); + kfree(sunkbd); + return; + } + + sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type); + + memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode)); + for (i = 0; i < 255; i++) + set_bit(sunkbd->keycode[i], sunkbd->dev.keybit); + clear_bit(0, sunkbd->dev.keybit); + + sprintf(sunkbd->name, "%s/input", serio->phys); + + sunkbd->dev.name = sunkbd->name; + sunkbd->dev.phys = sunkbd->phys; + sunkbd->dev.idbus = BUS_RS232; + sunkbd->dev.idvendor = SERIO_SUNKBD; + sunkbd->dev.idproduct = sunkbd->type; + sunkbd->dev.idversion = 0x0100; + + input_register_device(&sunkbd->dev); + + printk(KERN_INFO "input: %s on %s\n", sunkbd->name, serio->phys); +} + +/* + * sunkbd_disconnect() unregisters and closes behind us. + */ + +static void sunkbd_disconnect(struct serio *serio) +{ + struct sunkbd *sunkbd = serio->private; + input_unregister_device(&sunkbd->dev); + serio_close(serio); + kfree(sunkbd); +} + +static struct serio_dev sunkbd_dev = { + interrupt: sunkbd_interrupt, + connect: sunkbd_connect, + disconnect: sunkbd_disconnect +}; + +/* + * The functions for insering/removing us as a module. + */ + +int __init sunkbd_init(void) +{ + serio_register_device(&sunkbd_dev); + return 0; +} + +void __exit sunkbd_exit(void) +{ + serio_unregister_device(&sunkbd_dev); +} + +module_init(sunkbd_init); +module_exit(sunkbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/keyboard/xtkbd.c linux-2.5/drivers/input/keyboard/xtkbd.c --- linux-2.5.5/drivers/input/keyboard/xtkbd.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/keyboard/xtkbd.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,157 @@ +/* + * $Id: xtkbd.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * XT keyboard driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("XT keyboard driver"); +MODULE_LICENSE("GPL"); + +#define XTKBD_EMUL0 0xe0 +#define XTKBD_EMUL1 0xe1 +#define XTKBD_KEY 0x7f +#define XTKBD_RELEASE 0x80 + +static unsigned char xtkbd_keycode[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 0, 0, 0, 87, 88, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 87, 88, 0, 0, 0, 0,110,111,103,108,105, + 106 +}; + +static char *xtkbd_name = "XT Keyboard"; + +struct xtkbd { + unsigned char keycode[256]; + struct input_dev dev; + struct serio *serio; + char phys[32]; +}; + +void xtkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct xtkbd *xtkbd = serio->private; + + switch (data) { + case XTKBD_EMUL0: + case XTKBD_EMUL1: + return; + default: + + if (xtkbd->keycode[data & XTKBD_KEY]) { + input_report_key(&xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE)); + } else { + printk(KERN_WARNING "xtkbd.c: Unknown key (scancode %#x) %s.\n", + data & XTKBD_KEY, data & XTKBD_RELEASE ? "released" : "pressed"); + } + } +} + +void xtkbd_connect(struct serio *serio, struct serio_dev *dev) +{ + struct xtkbd *xtkbd; + int i; + + if ((serio->type & SERIO_TYPE) != SERIO_XT) + return; + + if (!(xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL))) + return; + + memset(xtkbd, 0, sizeof(struct xtkbd)); + + xtkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + + xtkbd->serio = serio; + + xtkbd->dev.keycode = xtkbd->keycode; + xtkbd->dev.private = xtkbd; + + serio->private = xtkbd; + + if (serio_open(serio, dev)) { + kfree(xtkbd); + return; + } + + memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode)); + for (i = 0; i < 255; i++) + set_bit(xtkbd->keycode[i], xtkbd->dev.keybit); + clear_bit(0, xtkbd->dev.keybit); + + sprintf(xtkbd->phys, "%s/input0", serio->phys); + + xtkbd->dev.name = xtkbd_name; + xtkbd->dev.phys = xtkbd->phys; + xtkbd->dev.idbus = BUS_XTKBD; + xtkbd->dev.idvendor = 0x0001; + xtkbd->dev.idproduct = 0x0001; + xtkbd->dev.idversion = 0x0100; + + input_register_device(&xtkbd->dev); + + printk(KERN_INFO "input: %s on %s\n", xtkbd_name, serio->phys); +} + +void xtkbd_disconnect(struct serio *serio) +{ + struct xtkbd *xtkbd = serio->private; + input_unregister_device(&xtkbd->dev); + serio_close(serio); + kfree(xtkbd); +} + +struct serio_dev xtkbd_dev = { + interrupt: xtkbd_interrupt, + connect: xtkbd_connect, + disconnect: xtkbd_disconnect +}; + +int __init xtkbd_init(void) +{ + serio_register_device(&xtkbd_dev); + return 0; +} + +void __exit xtkbd_exit(void) +{ + serio_unregister_device(&xtkbd_dev); +} + +module_init(xtkbd_init); +module_exit(xtkbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/mouse/Config.help linux-2.5/drivers/input/mouse/Config.help --- linux-2.5.5/drivers/input/mouse/Config.help Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/mouse/Config.help Sun Jan 27 00:32:29 2002 @@ -0,0 +1,98 @@ +CONFIG_INPUT_MOUSE + Say Y here, and a list of supported mice will be displayed. + This option doesn't affect the kernel. + + If unsure, say Y. + +CONFIG_MOUSE_PS2 + Say Y here if you have a PS/2 mouse connected to your system. This + includes the standard 2 or 3-button PS/2 mouse, as well as PS/2 + mice with wheels and extra buttons, Microsoft, Logitech or Genius + compatible. + + If unsure, say Y. + + This driver 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 psmouse.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_SERIAL + Say Y here if you have a serial (RS-232, COM port) mouse connected + to your system. This includes Sun, MouseSystems, Microsoft, + Logitech and all other compatible serial mice. + + If unsure, say N. + + This driver 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 sermouse.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_GUNZE + Say Y here if you have the Gunze AHL-51 touchscreen connected to + your system. + + If unsure, say N. + + This driver 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 gunze.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_INPORT + Say Y here if you have an InPort, Microsoft or ATI XL busmouse. + They are rather rare these days. + + This driver 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 inport.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_ATIXL + Say Y here if your mouse is of the ATI XL variety. + +CONFIG_MOUSE_LOGIBM + Say Y here if you have a Logitech busmouse. + They are rather rare these days. + + This driver 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 logibm.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_PC110PAD + Say Y if you have the IBM PC-110 micro-notebook and want its + touchscreen supported. + + This driver 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 pc110pad.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_MAPLE + Say Y if you have a DreamCast console and a mouse attached to + its Maple bus. + + This driver 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 maplemouse.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_AMIGA + Say Y here if you have an Amiga and want its native mouse + supported by the kernel. + + This driver 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 amimouse.o. If you want to compile it as a + module, say M here and read . + +CONFIG_MOUSE_ACORN + Say Y here if you have the Acorn RiscPC computer and want its + native mouse supported. + + This driver 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 rpcmouse.o. If you want to compile it as a + module, say M here and read . diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/mouse/Config.in linux-2.5/drivers/input/mouse/Config.in --- linux-2.5.5/drivers/input/mouse/Config.in Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/mouse/Config.in Sun Jan 20 17:11:46 2002 @@ -0,0 +1,25 @@ +# +# Mouse driver configuration +# + +bool 'Mice' CONFIG_INPUT_MOUSE + +dep_tristate ' PS/2 mouse' CONFIG_MOUSE_PS2 $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_SERIO +dep_tristate ' Serial mouse' CONFIG_MOUSE_SERIAL $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_SERIO +dep_tristate ' Gunze AHL-51S touchscreen' CONFIG_MOUSE_GUNZE $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_SERIO + +dep_tristate ' InPort/MS/ATIXL busmouse' CONFIG_MOUSE_INPORT $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA +if [ "$CONFIG_MOUSE_INPORT" != "n" ]; then + bool ' ATI XL variant' CONFIG_MOUSE_ATIXL +fi +dep_tristate ' Logitech busmouse' CONFIG_MOUSE_LOGIBM $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA +dep_tristate ' IBM PC110 touchpad' CONFIG_MOUSE_PC110PAD $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA +if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then + dep_tristate ' Maple bus mouse' CONFIG_MOUSE_MAPLE $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_MAPLE +fi +if [ "$CONFIG_AMIGA" = "y" ]; then + dep_tristate ' Amiga mouse' CONFIG_MOUSE_AMIGA $CONFIG_INPUT $CONFIG_INPUT_MOUSE +fi +if [ "$CONFIG_ARCH_ACORN" = "y" ]; then + dep_tristate ' Acorn RiscPC mouse' CONFIG_MOUSE_ACORN $CONFIG_INPUT $CONFIG_INPUT_MOUSE +fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/mouse/Makefile linux-2.5/drivers/input/mouse/Makefile --- linux-2.5.5/drivers/input/mouse/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/mouse/Makefile Sun Jan 20 17:11:46 2002 @@ -0,0 +1,23 @@ +# +# Makefile for the mouse drivers. +# + +# The target object and module list name. + +O_TARGET := mousedrv.o + +# Each configuration option enables a list of files. + +obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o +obj-$(CONFIG_MOUSE_ACORN) += rpcmouse.o +obj-$(CONFIG_MOUSE_GUNZE) += gunze.o +obj-$(CONFIG_MOUSE_INPORT) += inport.o +obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o +obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o +obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o +obj-$(CONFIG_MOUSE_PS2) += psmouse.o +obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o + +# The global Rules.make. + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/mouse/amimouse.c linux-2.5/drivers/input/mouse/amimouse.c --- linux-2.5.5/drivers/input/mouse/amimouse.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/mouse/amimouse.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,147 @@ +/* + * $Id: amimouse.c,v 1.9 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * + * Based on the work of: + * Michael Rausch James Banks + * Matther Dillon David Giller + * Nathan Laredo Linus Torvalds + * Johan Myreen Jes Sorensen + * Russel King + */ + +/* + * Amiga mouse driver for Linux/m68k + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Amiga mouse driver"); +MODULE_LICENSE("GPL"); + +static int amimouse_used = 0; +static int amimouse_lastx, amimouse_lasty; +static struct input_dev amimouse_dev; + +static char *amimouse_name = "Amiga mouse"; +static char *amimouse_phys = "amimouse/input0"; + +static void amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp) +{ + unsigned short joy0dat, potgor; + int nx, ny, dx, dy; + + joy0dat = custom.joy0dat; + + nx = joy0dat & 0xff; + ny = joy0dat >> 8; + + dx = nx - amimouse_lastx; + dy = ny - amimouse_lasty; + + if (dx < -127) dx = (256 + nx) - lastx; + if (dx > 127) dx = (nx - 256) - lastx; + if (dy < -127) dy = (256 + ny) - lasty; + if (dy > 127) dy = (ny - 256) - lasty; + + amimouse_lastx = nx; + amimouse_lasty = ny; + + potgor = custom.potgor; + + input_report_rel(&amimouse_dev, REL_X, dx); + input_report_rel(&amimouse_dev, REL_Y, dy); + + input_report_key(&amimouse_dev, BTN_LEFT, ciaa.pra & 0x40); + input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100); + input_report_key(&amimouse_dev, BTN_RIGHT, potgor & 0x0400); +} + +static int amimouse_open(struct input_dev *dev) +{ + unsigned short joy0dat; + + if (amimouse_used++) + return 0; + + joy0dat = custom.joy0dat; + + amimouse_lastx = joy0dat & 0xff; + amimouse_lasty = joy0dat >> 8; + + if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", NULL)) { + amimouse_used--; + printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", amimouse_irq); + return -EBUSY; + } + + return 0; +} + +static void amimouse_close(struct input_dev *dev) +{ + if (!--amimouse_used) + free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt); +} + +static int __init amimouse_init(void) +{ + if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE)) + return -ENODEV; + + amimouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + amimouse_dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); + amimouse_dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + amimouse_dev.open = amimouse_open; + amimouse_dev.close = amimouse_close; + + amimouse_dev.name = amimouse_name; + amimouse_dev.phys = amimouse_phys; + amimouse_dev.idbus = BUS_AMIGA; + amimouse_dev.idvendor = 0x0001; + amimouse_dev.idproduct = 0x0002; + amimouse_dev.idversion = 0x0100; + + input_register_device(&amimouse_dev); + + printk(KERN_INFO "input: %s at joy0dat\n", amimouse_name); +} + +static void __exit amimouse_exit(void) +{ + input_unregister_device(&amimouse_dev); +} + +module_init(amimouse_init); +module_exit(amimouse_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/mouse/gunze.c linux-2.5/drivers/input/mouse/gunze.c --- linux-2.5.5/drivers/input/mouse/gunze.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/mouse/gunze.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,178 @@ +/* + * $Id: gunze.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + */ + +/* + * Gunze AHL-51S touchscreen driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Gunze AHL-51S touchscreen driver"); +MODULE_LICENSE("GPL"); + +/* + * Definitions & global arrays. + */ + +#define GUNZE_MAX_LENGTH 10 + +static char *gunze_name = "Gunze AHL-51S TouchScreen"; + +/* + * Per-touchscreen data. + */ + +struct gunze { + struct input_dev dev; + struct serio *serio; + int idx; + unsigned char data[GUNZE_MAX_LENGTH]; + char phys[32]; +}; + +static void gunze_process_packet(struct gunze* gunze) +{ + struct input_dev *dev = &gunze->dev; + + if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' || + (gunze->data[0] != 'T' && gunze->data[0] != 'R')) { + gunze->data[10] = 0; + printk(KERN_WARNING "gunze.c: bad packet: >%s<\n", gunze->data); + return; + } + + input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10) * 4); + input_report_abs(dev, ABS_Y, 3072 - simple_strtoul(gunze->data + 6, NULL, 10) * 3); + input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T'); +} + +static void gunze_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct gunze* gunze = serio->private; + + if (data == '\r') { + gunze_process_packet(gunze); + gunze->idx = 0; + } else { + if (gunze->idx < GUNZE_MAX_LENGTH) + gunze->data[gunze->idx++] = data; + } +} + +/* + * gunze_disconnect() is the opposite of gunze_connect() + */ + +static void gunze_disconnect(struct serio *serio) +{ + struct gunze* gunze = serio->private; + input_unregister_device(&gunze->dev); + serio_close(serio); + kfree(gunze); +} + +/* + * gunze_connect() is the routine that is called when someone adds a + * new serio device. It looks whether it was registered as a Gunze touchscreen + * and if yes, registers it as an input device. + */ + +static void gunze_connect(struct serio *serio, struct serio_dev *dev) +{ + struct gunze *gunze; + + if (serio->type != (SERIO_RS232 | SERIO_GUNZE)) + return; + + if (!(gunze = kmalloc(sizeof(struct gunze), GFP_KERNEL))) + return; + + memset(gunze, 0, sizeof(struct gunze)); + + gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + gunze->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + + gunze->dev.absmin[ABS_X] = 96; gunze->dev.absmin[ABS_Y] = 72; + gunze->dev.absmax[ABS_X] = 4000; gunze->dev.absmax[ABS_Y] = 3000; + + gunze->serio = serio; + serio->private = gunze; + + sprintf(gunze->phys, "%s/input0", serio->phys); + + gunze->dev.private = gunze; + gunze->dev.name = gunze_name; + gunze->dev.phys = gunze->phys; + gunze->dev.idbus = BUS_RS232; + gunze->dev.idvendor = SERIO_GUNZE; + gunze->dev.idproduct = 0x0051; + gunze->dev.idversion = 0x0100; + + if (serio_open(serio, dev)) { + kfree(gunze); + return; + } + + input_register_device(&gunze->dev); + + printk(KERN_INFO "input: %s on %s\n", gunze_name, serio->phys); +} + +/* + * The serio device structure. + */ + +static struct serio_dev gunze_dev = { + interrupt: gunze_interrupt, + connect: gunze_connect, + disconnect: gunze_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +int __init gunze_init(void) +{ + serio_register_device(&gunze_dev); + return 0; +} + +void __exit gunze_exit(void) +{ + serio_unregister_device(&gunze_dev); +} + +module_init(gunze_init); +module_exit(gunze_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/mouse/inport.c linux-2.5/drivers/input/mouse/inport.c --- linux-2.5.5/drivers/input/mouse/inport.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/mouse/inport.c Tue Jan 22 17:43:43 2002 @@ -0,0 +1,193 @@ +/* + * $Id: inport.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + * + * Based on the work of: + * Teemu Rantanen Derrick Cole + * Peter Cervasio Christoph Niemann + * Philip Blundell Russell King + * Bob Harris + */ + +/* + * Inport (ATI XL and Microsoft) busmouse driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Inport (ATI XL and Microsoft) busmouse driver"); +MODULE_LICENSE("GPL"); + +#define INPORT_BASE 0x23c +#define INPORT_EXTENT 4 + +#define INPORT_CONTROL_PORT INPORT_BASE + 0 +#define INPORT_DATA_PORT INPORT_BASE + 1 +#define INPORT_SIGNATURE_PORT INPORT_BASE + 2 + +#define INPORT_REG_BTNS 0x00 +#define INPORT_REG_X 0x01 +#define INPORT_REG_Y 0x02 +#define INPORT_REG_MODE 0x07 +#define INPORT_RESET 0x80 + +#ifdef CONFIG_INPUT_ATIXL +#define INPORT_NAME "ATI XL Mouse" +#define INPORT_VENDOR 0x0002 +#define INPORT_SPEED_30HZ 0x01 +#define INPORT_SPEED_50HZ 0x02 +#define INPORT_SPEED_100HZ 0x03 +#define INPORT_SPEED_200HZ 0x04 +#define INPORT_MODE_BASE INPORT_SPEED_100HZ +#define INPORT_MODE_IRQ 0x08 +#else +#define INPORT_NAME "Microsoft InPort Mouse" +#define INPORT_VENDOR 0x0001 +#define INPORT_MODE_BASE 0x10 +#define INPORT_MODE_IRQ 0x01 +#endif +#define INPORT_MODE_HOLD 0x20 + +#define INPORT_IRQ 5 + +MODULE_PARM(inport_irq, "i"); + +static int inport_irq = INPORT_IRQ; +static int inport_used = 0; + +static void inport_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +static int inport_open(struct input_dev *dev) +{ + if (!inport_used++) { + if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL)) + return -EBUSY; + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); + } + + return 0; +} + +static void inport_close(struct input_dev *dev) +{ + if (!--inport_used) { + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_BASE, INPORT_DATA_PORT); + free_irq(inport_irq, NULL); + } +} + +static struct input_dev inport_dev = { + evbit: { BIT(EV_KEY) | BIT(EV_REL) }, + keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, + relbit: { BIT(REL_X) | BIT(REL_Y) }, + open: inport_open, + close: inport_close, + name: INPORT_NAME, + phys: "isa023c/input0", + idbus: BUS_ISA, + idvendor: INPORT_VENDOR, + idproduct: 0x0001, + idversion: 0x0100, +}; + +static void inport_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned char buttons; + + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); + + outb(INPORT_REG_X, INPORT_CONTROL_PORT); + input_report_rel(&inport_dev, REL_X, inb(INPORT_DATA_PORT)); + + outb(INPORT_REG_Y, INPORT_CONTROL_PORT); + input_report_rel(&inport_dev, REL_Y, inb(INPORT_DATA_PORT)); + + outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT); + buttons = inb(INPORT_DATA_PORT); + + input_report_key(&inport_dev, BTN_MIDDLE, buttons & 1); + input_report_key(&inport_dev, BTN_LEFT, buttons & 2); + input_report_key(&inport_dev, BTN_RIGHT, buttons & 4); + + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); +} + +#ifndef MODULE +static int __init inport_setup(char *str) +{ + int ints[4]; + str = get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] > 0) inport_irq = ints[1]; + return 1; +} +__setup("inport_irq=", inport_setup); +#endif + +static int __init inport_init(void) +{ + unsigned char a,b,c; + + if (check_region(INPORT_BASE, INPORT_EXTENT)) + return -EBUSY; + + a = inb(INPORT_SIGNATURE_PORT); + b = inb(INPORT_SIGNATURE_PORT); + c = inb(INPORT_SIGNATURE_PORT); + if (( a == b ) || ( a != c )) + return -ENODEV; + + outb(INPORT_RESET, INPORT_CONTROL_PORT); + outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); + outb(INPORT_MODE_BASE, INPORT_DATA_PORT); + + request_region(INPORT_BASE, INPORT_EXTENT, "inport"); + + input_register_device(&inport_dev); + + printk(KERN_INFO "input: " INPORT_NAME " at %#x irq %d\n", + INPORT_BASE, inport_irq); + + return 0; +} + +static void __exit inport_exit(void) +{ + input_unregister_device(&inport_dev); + release_region(INPORT_BASE, INPORT_EXTENT); +} + +module_init(inport_init); +module_exit(inport_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/mouse/logibm.c linux-2.5/drivers/input/mouse/logibm.c --- linux-2.5.5/drivers/input/mouse/logibm.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/mouse/logibm.c Tue Jan 22 17:43:47 2002 @@ -0,0 +1,182 @@ +/* + * $Id: logibm.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + * + * Based on the work of: + * James Banks Matthew Dillon + * David Giller Nathan Laredo + * Linus Torvalds Johan Myreen + * Cliff Matthews Philip Blundell + * Russell King + */ + +/* + * Logitech Bus Mouse Driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Logitech busmouse driver"); +MODULE_LICENSE("GPL"); + +#define LOGIBM_BASE 0x23c +#define LOGIBM_EXTENT 4 + +#define LOGIBM_DATA_PORT LOGIBM_BASE + 0 +#define LOGIBM_SIGNATURE_PORT LOGIBM_BASE + 1 +#define LOGIBM_CONTROL_PORT LOGIBM_BASE + 2 +#define LOGIBM_CONFIG_PORT LOGIBM_BASE + 3 + +#define LOGIBM_ENABLE_IRQ 0x00 +#define LOGIBM_DISABLE_IRQ 0x10 +#define LOGIBM_READ_X_LOW 0x80 +#define LOGIBM_READ_X_HIGH 0xa0 +#define LOGIBM_READ_Y_LOW 0xc0 +#define LOGIBM_READ_Y_HIGH 0xe0 + +#define LOGIBM_DEFAULT_MODE 0x90 +#define LOGIBM_CONFIG_BYTE 0x91 +#define LOGIBM_SIGNATURE_BYTE 0xa5 + +#define LOGIBM_IRQ 5 + +MODULE_PARM(logibm_irq, "i"); + +static int logibm_irq = LOGIBM_IRQ; +static int logibm_used = 0; + +static void logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +static int logibm_open(struct input_dev *dev) +{ + if (logibm_used++) + return 0; + if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) { + logibm_used--; + printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq); + return -EBUSY; + } + outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT); + return 0; +} + +static void logibm_close(struct input_dev *dev) +{ + if (--logibm_used) + return; + outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); + free_irq(logibm_irq, NULL); +} + +static struct input_dev logibm_dev = { + evbit: { BIT(EV_KEY) | BIT(EV_REL) }, + keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, + relbit: { BIT(REL_X) | BIT(REL_Y) }, + open: logibm_open, + close: logibm_close, + name: "Logitech bus mouse", + phys: "isa023c/input0", + idbus: BUS_ISA, + idvendor: 0x0003, + idproduct: 0x0001, + idversion: 0x0100, +}; + +static void logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + char dx, dy; + unsigned char buttons; + + outb(LOGIBM_READ_X_LOW, LOGIBM_CONTROL_PORT); + dx = (inb(LOGIBM_DATA_PORT) & 0xf); + outb(LOGIBM_READ_X_HIGH, LOGIBM_CONTROL_PORT); + dx |= (inb(LOGIBM_DATA_PORT) & 0xf) << 4; + outb(LOGIBM_READ_Y_LOW, LOGIBM_CONTROL_PORT); + dy = (inb(LOGIBM_DATA_PORT) & 0xf); + outb(LOGIBM_READ_Y_HIGH, LOGIBM_CONTROL_PORT); + buttons = inb(LOGIBM_DATA_PORT); + dy |= (buttons & 0xf) << 4; + buttons = ~buttons; + + input_report_rel(&logibm_dev, REL_X, dx); + input_report_rel(&logibm_dev, REL_Y, 255 - dy); + input_report_key(&logibm_dev, BTN_MIDDLE, buttons & 1); + input_report_key(&logibm_dev, BTN_LEFT, buttons & 2); + input_report_key(&logibm_dev, BTN_RIGHT, buttons & 4); +} + +#ifndef MODULE +static int __init logibm_setup(char *str) +{ + int ints[4]; + str = get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] > 0) logibm_irq = ints[1]; + return 1; +} +__setup("logibm_irq=", logibm_setup); +#endif + +static int __init logibm_init(void) +{ + if (request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) { + printk(KERN_ERR "logibm.c: Can't allocate ports at %#x\n", LOGIBM_BASE); + return -EBUSY; + } + + outb(LOGIBM_CONFIG_BYTE, LOGIBM_CONFIG_PORT); + outb(LOGIBM_SIGNATURE_BYTE, LOGIBM_SIGNATURE_PORT); + udelay(100); + + if (inb(LOGIBM_SIGNATURE_PORT) != LOGIBM_SIGNATURE_BYTE) { + release_region(LOGIBM_BASE, LOGIBM_EXTENT); + printk(KERN_ERR "logibm.c: Didn't find Logitech busmouse at %#x\n", LOGIBM_BASE); + return -ENODEV; + } + + outb(LOGIBM_DEFAULT_MODE, LOGIBM_CONFIG_PORT); + outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); + + input_register_device(&logibm_dev); + + printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq); + + return 0; +} + +static void __exit logibm_exit(void) +{ + input_unregister_device(&logibm_dev); + release_region(LOGIBM_BASE, LOGIBM_EXTENT); +} + +module_init(logibm_init); +module_exit(logibm_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/mouse/maplemouse.c linux-2.5/drivers/input/mouse/maplemouse.c --- linux-2.5.5/drivers/input/mouse/maplemouse.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/mouse/maplemouse.c Fri Feb 15 18:03:10 2002 @@ -0,0 +1,137 @@ +/* + * $Id: maplemouse.c,v 1.1 2001/11/02 17:27:32 jsimmons Exp $ + * SEGA Dreamcast mouse driver + * Based on drivers/usb/usbmouse.c + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("YAEGASHI Takeshi "); +MODULE_DESCRIPTION("SEGA Dreamcast mouse driver"); + +struct dc_mouse { + struct input_dev dev; + int open; +}; + + +static void dc_mouse_callback(struct mapleq *mq) +{ + int buttons, relx, rely, relz; + struct maple_device *mapledev = mq->dev; + struct dc_mouse *mouse = mapledev->private_data; + struct input_dev *dev = &mouse->dev; + unsigned char *res = mq->recvbuf; + + buttons = ~res[8]; + relx=*(unsigned short *)(res+12)-512; + rely=*(unsigned short *)(res+14)-512; + relz=*(unsigned short *)(res+16)-512; + + input_report_key(dev, BTN_LEFT, buttons&4); + input_report_key(dev, BTN_MIDDLE, buttons&9); + input_report_key(dev, BTN_RIGHT, buttons&2); + input_report_rel(dev, REL_X, relx); + input_report_rel(dev, REL_Y, rely); + input_report_rel(dev, REL_WHEEL, relz); +} + + +static int dc_mouse_open(struct input_dev *dev) +{ + struct dc_mouse *mouse = dev->private; + mouse->open++; + return 0; +} + + +static void dc_mouse_close(struct input_dev *dev) +{ + struct dc_mouse *mouse = dev->private; + mouse->open--; +} + + +static int dc_mouse_connect(struct maple_device *dev) +{ + unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]); + struct dc_mouse *mouse; + + if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL))) + return -1; + memset(mouse, 0, sizeof(struct dc_mouse)); + + dev->private_data = mouse; + + mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL); + + mouse->dev.private = mouse; + mouse->dev.open = dc_mouse_open; + mouse->dev.close = dc_mouse_close; + mouse->dev.event = NULL; + + mouse->dev.name = dev->product_name; + mouse->dev.idbus = BUS_MAPLE; + + input_register_device(&mouse->dev); + + maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE); + + printk(KERN_INFO "input%d: mouse(0x%lx): %s\n", + mouse->dev.number, data, mouse->dev.name); + + MOD_INC_USE_COUNT; + + return 0; +} + + +static void dc_mouse_disconnect(struct maple_device *dev) +{ + struct dc_mouse *mouse = dev->private_data; + + input_unregister_device(&mouse->dev); + + kfree(mouse); + + MOD_DEC_USE_COUNT; +} + + +static struct maple_driver dc_mouse_driver = { + function: MAPLE_FUNC_MOUSE, + name: "Dreamcast mouse", + connect: dc_mouse_connect, + disconnect: dc_mouse_disconnect, +}; + + +static int __init dc_mouse_init(void) +{ + maple_register_driver(&dc_mouse_driver); + return 0; +} + + +static void __exit dc_mouse_exit(void) +{ + maple_unregister_driver(&dc_mouse_driver); +} + + +module_init(dc_mouse_init); +module_exit(dc_mouse_exit); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/mouse/pc110pad.c linux-2.5/drivers/input/mouse/pc110pad.c --- linux-2.5.5/drivers/input/mouse/pc110pad.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/mouse/pc110pad.c Tue Jan 22 17:43:47 2002 @@ -0,0 +1,163 @@ +/* + * $Id: pc110pad.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * + * Based on the work of: + * Alan Cox Robin O'Leary + */ + +/* + * IBM PC110 touchpad driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("IBM PC110 touchpad driver"); +MODULE_LICENSE("GPL"); + +#define PC110PAD_OFF 0x30 +#define PC110PAD_ON 0x38 + +static int pc110pad_irq = 10; +static int pc110pad_io = 0x15e0; + +static struct input_dev pc110pad_dev; +static int pc110pad_data[3]; +static int pc110pad_count; +static int pc110pad_used; + +static char *pc110pad_name = "IBM PC110 TouchPad"; +static char *pc110pad_phys = "isa15e0/input0"; + +static void pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + int value = inb_p(pc110pad_io); + int handshake = inb_p(pc110pad_io + 2); + + outb_p(handshake | 1, pc110pad_io + 2); + outb_p(handshake & ~1, pc110pad_io + 2); + inb_p(0x64); + + pc110pad_data[pc110pad_count++] = value; + + if (pc110pad_count < 3) return; + + input_report_key(&pc110pad_dev, BTN_TOUCH, + pc110pad_data[0] & 0x01); + input_report_abs(&pc110pad_dev, ABS_X, + pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100)); + input_report_abs(&pc110pad_dev, ABS_Y, + pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80)); + + pc110pad_count = 0; +} + +static void pc110pad_close(struct input_dev *dev) +{ + if (!--pc110pad_used) + outb(PC110PAD_OFF, pc110pad_io + 2); +} + +static int pc110pad_open(struct input_dev *dev) +{ + unsigned long flags; + + if (pc110pad_used++) + return 0; + + save_flags(flags); + cli(); + pc110pad_interrupt(0,0,0); + pc110pad_interrupt(0,0,0); + pc110pad_interrupt(0,0,0); + outb(PC110PAD_ON, pc110pad_io + 2); + pc110pad_count = 0; + restore_flags(flags); + + return 0; +} + +static int __init pc110pad_init(void) +{ + if (request_region(pc110pad_io, 4, "pc110pad")) + { + printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n", pc110pad_io, pc110pad_io + 4); + return -EBUSY; + } + + outb(PC110PAD_OFF, pc110pad_io + 2); + + if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", 0)) + { + release_region(pc110pad_io, 4); + printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq); + return -EBUSY; + } + + pc110pad_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + pc110pad_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); + pc110pad_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + + pc110pad_dev.absmax[ABS_X] = 0x1ff; + pc110pad_dev.absmax[ABS_Y] = 0x0ff; + + pc110pad_dev.open = pc110pad_open; + pc110pad_dev.close = pc110pad_close; + + pc110pad_dev.name = pc110pad_name; + pc110pad_dev.phys = pc110pad_phys; + pc110pad_dev.idbus = BUS_ISA; + pc110pad_dev.idvendor = 0x0003; + pc110pad_dev.idproduct = 0x0001; + pc110pad_dev.idversion = 0x0100; + + input_register_device(&pc110pad_dev); + + printk(KERN_INFO "input: %s at %#x irq %d\n", + pc110pad_name, pc110pad_io, pc110pad_irq); + + return 0; +} + +static void __exit pc110pad_exit(void) +{ + input_unregister_device(&pc110pad_dev); + + outb(PC110PAD_OFF, pc110pad_io + 2); + + free_irq(pc110pad_irq, 0); + release_region(pc110pad_io, 4); +} + +module_init(pc110pad_init); +module_exit(pc110pad_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/mouse/psmouse.c linux-2.5/drivers/input/mouse/psmouse.c --- linux-2.5.5/drivers/input/mouse/psmouse.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/mouse/psmouse.c Tue Jan 29 18:23:52 2002 @@ -0,0 +1,651 @@ +/* + * $Id: psmouse.c,v 1.16 2002/01/26 19:20:36 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("PS/2 mouse driver"); +MODULE_LICENSE("GPL"); + +#define PSMOUSE_CMD_SETSCALE11 0x00e6 +#define PSMOUSE_CMD_SETRES 0x10e8 +#define PSMOUSE_CMD_GETINFO 0x03e9 +#define PSMOUSE_CMD_SETSTREAM 0x00ea +#define PSMOUSE_CMD_POLL 0x03eb +#define PSMOUSE_CMD_GETID 0x01f2 +#define PSMOUSE_CMD_SETRATE 0x10f3 +#define PSMOUSE_CMD_ENABLE 0x00f4 +#define PSMOUSE_CMD_RESET_DIS 0x00f6 + +#define PSMOUSE_RET_BAT 0xaa +#define PSMOUSE_RET_ACK 0xfa +#define PSMOUSE_RET_NAK 0xfe + +struct psmouse { + struct input_dev dev; + struct serio *serio; + char *vendor; + char *name; + struct tq_struct tq; + unsigned char cmdbuf[8]; + unsigned char packet[8]; + unsigned char cmdcnt; + unsigned char pktcnt; + unsigned char type; + unsigned long last; + char acking; + char ack; + char error; + char devname[64]; + char phys[32]; +}; + +#define PSMOUSE_PS2 1 +#define PSMOUSE_PS2PP 2 +#define PSMOUSE_PS2TPP 3 +#define PSMOUSE_GENPS 4 +#define PSMOUSE_IMPS 5 +#define PSMOUSE_IMEX 6 + +static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2" }; + +/* + * psmouse_process_packet() anlyzes the PS/2 mouse packet contents and + * reports relevant events to the input module. + */ + +static void psmouse_process_packet(struct psmouse *psmouse) +{ + struct input_dev *dev = &psmouse->dev; + unsigned char *packet = psmouse->packet; + +/* + * The PS2++ protocol is a little bit complex + */ + + if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP) { + + if ((packet[0] & 0x40) == 0x40 && (int) packet[1] - (int) ((packet[0] & 0x10) << 4) > 191 ) { + + switch (((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0xc0)) { + + case 1: /* Mouse extra info */ + + input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, + (int) (packet[2] & 7) - (int) (packet[2] & 8)); + input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); + input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); + + break; + + case 3: /* TouchPad extra info */ + + input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, + (int) ((packet[2] >> 4) & 7) - (int) ((packet[2] >> 4) & 8)); + packet[0] = packet[2] | 0x08; + + break; + + default: + + printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", + ((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0xc0)); + + } + + packet[0] &= 0x0f; + packet[1] = 0; + packet[2] = 0; + + } + } + +/* + * Scroll wheel on IntelliMice, scroll buttons on NetMice + */ + + if (psmouse->type == PSMOUSE_IMPS || psmouse->type == PSMOUSE_GENPS) + input_report_rel(dev, REL_WHEEL, (signed char) packet[3]); + +/* + * Scroll wheel and buttons on IntelliMouse Explorer + */ + + if (psmouse->type == PSMOUSE_IMEX) { + input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 7) - (int) (packet[2] & 8)); + input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1); + input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); + } + +/* + * Extra buttons on Genius NewNet 3D + */ + + if (psmouse->type == PSMOUSE_GENPS) { + input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1); + input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1); + } + +/* + * Generic PS/2 Mouse + */ + + input_report_key(dev, BTN_LEFT, packet[0] & 1); + input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); + input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); + + input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0); + input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0); + +} + +/* + * psmouse_interrupt() handles incoming characters, either gathering them into + * packets or passing them to the command routine as command output. + */ + +static void psmouse_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct psmouse *psmouse = serio->private; + + if (psmouse->acking) { + switch (data) { + case PSMOUSE_RET_ACK: + psmouse->ack = 1; + break; + case PSMOUSE_RET_NAK: + psmouse->ack = -1; + break; + default: + psmouse->ack = 1; /* Workaround for mice which don't ACK the Get ID command */ + if (psmouse->cmdcnt) + psmouse->cmdbuf[--psmouse->cmdcnt] = data; + break; + } + psmouse->acking = 0; + return; + } + + if (psmouse->cmdcnt) { + psmouse->cmdbuf[--psmouse->cmdcnt] = data; + return; + } + + if (psmouse->pktcnt && jiffies - psmouse->last > 2) { + printk(KERN_WARNING "psmouse.c: Lost synchronization, throwing %d bytes away.\n", psmouse->pktcnt); + psmouse->pktcnt = 0; + } + + psmouse->last = jiffies; + psmouse->packet[psmouse->pktcnt++] = data; + + if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) { + if ((psmouse->packet[0] & 0x08) == 0x08) psmouse_process_packet(psmouse); + psmouse->pktcnt = 0; + return; + } + + if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) { + queue_task(&psmouse->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return; + } +} + +/* + * psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge. + * It doesn't handle retransmission, though it could - because when there would + * be need for retransmissions, the mouse has to be replaced anyway. + */ + +static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte) +{ + int timeout = 1000; /* 10 msec */ + psmouse->ack = 0; + psmouse->acking = 1; + + serio_write(psmouse->serio, byte); + while (!psmouse->ack && timeout--) udelay(10); + + return -(psmouse->ack <= 0); +} + +/* + * psmouse_command() sends a command and its parameters to the mouse, + * then waits for the response and puts it in the param array. + */ + +static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) +{ + int timeout = 100000; /* 100 msec */ + int send = (command >> 12) & 0xf; + int receive = (command >> 8) & 0xf; + int i; + + psmouse->cmdcnt = receive; + + if (command & 0xff) + if (psmouse_sendbyte(psmouse, command & 0xff)) + return (psmouse->cmdcnt = 0) - 1; + + for (i = 0; i < send; i++) + if (psmouse_sendbyte(psmouse, param[i])) + return (psmouse->cmdcnt = 0) - 1; + + while (psmouse->cmdcnt && timeout--) udelay(1); + + for (i = 0; i < receive; i++) + param[i] = psmouse->cmdbuf[(receive - 1) - i]; + + if (psmouse->cmdcnt) + return (psmouse->cmdcnt = 0) - 1; + + return 0; +} + +/* + * psmouse_ps2pp_cmd() sends a PS2++ command, sliced into two bit + * pieces through the SETRES command. This is needed to send extended + * commands to mice on notebooks that try to understand the PS/2 protocol + * Ugly. + */ + +static int psmouse_ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command) +{ + unsigned char d; + int i; + + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) + return -1; + + for (i = 6; i >= 0; i -= 2) { + d = (command >> i) & 3; + if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES)) + return -1; + } + + if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL)) + return -1; + + return 0; +} + +/* + * psmouse_extensions() probes for any extensions to the basic PS/2 protocol + * the mouse may have. + */ + +static int psmouse_extensions(struct psmouse *psmouse) +{ + unsigned char param[4]; + + param[0] = 0; + psmouse->vendor = "Generic"; + psmouse->name = "Mouse"; + +/* + * Try Genius NetMouse magic init. + */ + + param[0] = 3; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + + if (param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55) { + psmouse->vendor = "Genius"; + psmouse->name = "Mouse"; + + set_bit(BTN_EXTRA, psmouse->dev.keybit); + set_bit(BTN_SIDE, psmouse->dev.keybit); + set_bit(REL_WHEEL, psmouse->dev.relbit); + + return PSMOUSE_GENPS; + } + +/* + * Try Logitech magic ID. + */ + + param[0] = 0; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + + if (param[1]) { + + int i; + static int logitech_4btn[] = { 12, 40, 41, 42, 43, 73, 80, -1 }; + static int logitech_wheel[] = { 75, 76, 80, 81, 83, 88, -1 }; + static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75, + 76, 80, 81, 83, 88, 96, 97, -1 }; + + int devicetype = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); + + psmouse->vendor = "Logitech"; + psmouse->name = "Mouse"; + + if (param[1] < 3) + clear_bit(BTN_MIDDLE, psmouse->dev.keybit); + if (param[1] < 2) + clear_bit(BTN_RIGHT, psmouse->dev.keybit); + + psmouse->type = PSMOUSE_PS2; + + for (i = 0; logitech_ps2pp[i] != -1; i++) + if (logitech_ps2pp[i] == devicetype) psmouse->type = PSMOUSE_PS2PP; + + if (psmouse->type != PSMOUSE_PS2PP) return PSMOUSE_PS2; + + for (i = 0; logitech_4btn[i] != -1; i++) + if (logitech_4btn[i] == devicetype) set_bit(BTN_SIDE, psmouse->dev.keybit); + + for (i = 0; logitech_wheel[i] != -1; i++) + if (logitech_wheel[i] == devicetype) set_bit(REL_WHEEL, psmouse->dev.relbit); + +/* + * Do Logitech PS2++ / PS2T++ magic init. + */ + + if (devicetype == 97) { /* TouchPad 3 */ + + set_bit(REL_WHEEL, psmouse->dev.relbit); + set_bit(REL_HWHEEL, psmouse->dev.relbit); + + param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */ + psmouse_command(psmouse, param, 0x30d1); + param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */ + psmouse_command(psmouse, param, 0x30d1); + param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */ + psmouse_command(psmouse, param, 0x30d1); + + param[0] = 0; + if (!psmouse_command(psmouse, param, 0x13d1) && + param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) + return PSMOUSE_PS2TPP; + + } else { + psmouse_ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ + psmouse_ps2pp_cmd(psmouse, param, 0xDB); + + if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && + (param[2] & 3) == ((param[1] >> 2) & 3)) + return PSMOUSE_PS2PP; + } + + } + +/* + * Try IntelliMouse magic init. + */ + + param[0] = 200; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + param[0] = 100; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + param[0] = 80; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETID); + + if (param[0] == 3) { + + set_bit(REL_WHEEL, psmouse->dev.relbit); + +/* + * Try IntelliMouse Explorer magic init. + */ + + param[0] = 200; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + param[0] = 200; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + param[0] = 80; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETID); + + if (param[0] == 4) { + + psmouse->vendor = "Microsoft"; + psmouse->name = "IntelliMouse Explorer"; + + set_bit(BTN_SIDE, psmouse->dev.keybit); + set_bit(BTN_EXTRA, psmouse->dev.keybit); + + return PSMOUSE_IMEX; + } + + psmouse->vendor = "Microsoft"; + psmouse->name = "IntelliMouse"; + + return PSMOUSE_IMPS; + } + +/* + * Okay, all failed, we have a standard mouse here. The number of the buttons is + * still a question, though. + */ + + psmouse->vendor = "Generic"; + psmouse->name = "Mouse"; + + return PSMOUSE_PS2; +} + +/* + * psmouse_probe() probes for a PS/2 mouse. + */ + +static int psmouse_probe(struct psmouse *psmouse) +{ + unsigned char param[2]; + +/* + * First we reset and disable the mouse. + */ + + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS)) + return -1; + +/* + * Next, we check if it's a mouse. It should send 0x00 or 0x03 + * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer. + */ + + param[0] = param[1] = 0xa5; + + if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID)) + return -1; + + if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04) + return -1; + +/* + * And here we try to determine if it has any extensions over the + * basic PS/2 3-button mouse. + */ + + return psmouse->type = psmouse_extensions(psmouse); +} + +/* + * psmouse_initialize() initializes the mouse to a sane state. + */ + +static void psmouse_initialize(struct psmouse *psmouse) +{ + unsigned char param[2]; + +/* + * We set the mouse report rate to a highest possible value. + * We try 100 first in case mouse fails to set 200. + */ + + param[0] = 100; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + + param[0] = 200; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + +/* + * We also set the resolution and scaling. + */ + + param[0] = 3; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + +/* + * We set the mouse into streaming mode. + */ + + psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM); + +/* + * Last, we enable the mouse so that we get reports from it. + */ + + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) { + printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys); + } + +} + +/* + * psmouse_disconnect() cleans up after we don't want talk + * to the mouse anymore. + */ + +static void psmouse_disconnect(struct serio *serio) +{ + struct psmouse *psmouse = serio->private; + input_unregister_device(&psmouse->dev); + serio_close(serio); + kfree(psmouse); +} + +/* + * psmouse_powerup() is called when we get the powerup + * sequence - 0xaa [0x00], so that the mouse/kbd is re-probed. + */ + +static void psmouse_powerup(void *data) +{ + struct psmouse *psmouse = data; + + if (psmouse->packet[0] == PSMOUSE_RET_BAT && (psmouse->pktcnt == 1 || + (psmouse->pktcnt == 2 && psmouse->packet[1] == 0x00))) { + mdelay(40); /* FIXME!!! Wait some nicer way */ + serio_rescan(psmouse->serio); + } +} + +/* + * psmouse_connect() is a callback form the serio module when + * an unhandled serio port is found. + */ + +static void psmouse_connect(struct serio *serio, struct serio_dev *dev) +{ + struct psmouse *psmouse; + + if ((serio->type & SERIO_TYPE) != SERIO_8042) + return; + + if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) + return; + + memset(psmouse, 0, sizeof(struct psmouse)); + + psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); + + psmouse->serio = serio; + psmouse->dev.private = psmouse; + psmouse->tq.routine = psmouse_powerup; + psmouse->tq.data = psmouse; + + serio->private = psmouse; + + if (serio_open(serio, dev)) { + kfree(psmouse); + return; + } + + if (psmouse_probe(psmouse) <= 0) { + serio_close(serio); + kfree(psmouse); + return; + } + + sprintf(psmouse->devname, "%s %s %s", + psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name); + sprintf(psmouse->phys, "%s/input0", + serio->phys); + + psmouse->dev.name = psmouse->devname; + psmouse->dev.phys = psmouse->phys; + psmouse->dev.idbus = BUS_I8042; + psmouse->dev.idvendor = psmouse->type; + psmouse->dev.idproduct = 0x0002; + psmouse->dev.idversion = 0x0100; + + input_register_device(&psmouse->dev); + + printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); + + psmouse_initialize(psmouse); +} + +static struct serio_dev psmouse_dev = { + interrupt: psmouse_interrupt, + connect: psmouse_connect, + disconnect: psmouse_disconnect +}; + +int __init psmouse_init(void) +{ + serio_register_device(&psmouse_dev); + return 0; +} + +void __exit psmouse_exit(void) +{ + serio_unregister_device(&psmouse_dev); +} + +module_init(psmouse_init); +module_exit(psmouse_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/mouse/rpcmouse.c linux-2.5/drivers/input/mouse/rpcmouse.c --- linux-2.5.5/drivers/input/mouse/rpcmouse.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/mouse/rpcmouse.c Tue Jan 22 17:43:47 2002 @@ -0,0 +1,111 @@ +/* + * $Id: rpcmouse.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * + * Based on the work of: + * Russel King + */ + +/* + * Acorn RiscPC mouse driver for Linux/ARM + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Acorn RiscPC mouse driver"); +MODULE_LICENSE("GPL"); + +#define IOMD_MOUSEBTN 0x800C4000 + +static short rpcmouse_lastx, rpcmouse_lasty; + +static struct input_dev rpcmouse_dev = { + evbit: { BIT(EV_KEY) | BIT(EV_REL) }, + keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, + relbit: { BIT(REL_X) | BIT(REL_Y) }, + name: "Acorn RiscPC Mouse", + phys: "rpcmouse/input0", + idbus: BUS_ISA, + idvendor: 0x0005, + idproduct: 0x0001, + idversion: 0x0100, +}; + +static void rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + short x, y, dx, dy, b; + + x = (short) inl(IOMD_MOUSEX); + y = (short) inl(IOMD_MOUSEY); + b = (short) inl(IOMD_MOUSEBTN); + + dx = x - rpcmouse_lastx; + dy = y - rpcmouse_lasty; + + rpcmouse_lastx = x; + rpcmouse_lasty = y; + + input_report_rel(&rpcmouse_dev, REL_X, dx); + input_report_rel(&rpcmouse_dev, REL_Y, dy); + + input_report_key(&amimouse_dev, BTN_LEFT, buttons & 0x10); + input_report_key(&amimouse_dev, BTN_MIDDLE, buttons & 0x20); + input_report_key(&amimouse_dev, BTN_RIGHT, buttons & 0x40); +} + +static int __init rpcmouse_init(void) +{ + rpcmouse_lastx = (short) inl(IOMD_MOUSEX); + rpcmouse_lasty = (short) inl(IOMD_MOUSEY); + + if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", NULL)) { + printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n"); + return -1; + } + + input_register_device(&rpcmouse_dev); + printk(KERN_INFO "input%d: Acorn RiscPC mouse irq %d", IRQ_VSYNCPULSE); + + return 0; +} + +static void __exit rpcmouse_exit(void) +{ + input_unregister_device(&rpcmouse_dev); + free_irq(IRQ_VSYNCPULSE, NULL); +} + +module_init(rpcmouse_init); +module_exit(rpcmouse_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/mouse/sermouse.c linux-2.5/drivers/input/mouse/sermouse.c --- linux-2.5.5/drivers/input/mouse/sermouse.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/mouse/sermouse.c Tue Jan 22 17:43:47 2002 @@ -0,0 +1,299 @@ +/* + * $Id: sermouse.c,v 1.15 2001/10/09 22:34:17 jsimmons Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * Serial mouse driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Serial mouse driver"); +MODULE_LICENSE("GPL"); + +static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", + "Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse", + "Logitech MZ++ Mouse"}; + +struct sermouse { + struct input_dev dev; + signed char buf[8]; + unsigned char count; + unsigned char type; + unsigned long last; + char phys[32]; +}; + +/* + * sermouse_process_msc() analyzes the incoming MSC/Sun bytestream and + * applies some prediction to the data, resulting in 96 updates per + * second, which is as good as a PS/2 or USB mouse. + */ + +static void sermouse_process_msc(struct sermouse *sermouse, signed char data) +{ + struct input_dev *dev = &sermouse->dev; + signed char *buf = sermouse->buf; + + switch (sermouse->count) { + + case 0: + if ((data & 0xf8) != 0x80) return; + input_report_key(dev, BTN_LEFT, !(data & 4)); + input_report_key(dev, BTN_RIGHT, !(data & 1)); + input_report_key(dev, BTN_MIDDLE, !(data & 2)); + break; + + case 1: + case 3: + input_report_rel(dev, REL_X, data / 2); + input_report_rel(dev, REL_Y, -buf[1]); + buf[0] = data - data / 2; + break; + + case 2: + case 4: + input_report_rel(dev, REL_X, buf[0]); + input_report_rel(dev, REL_Y, buf[1] - data); + buf[1] = data / 2; + break; + } + + if (++sermouse->count == (5 - ((sermouse->type == SERIO_SUN) << 1))) + sermouse->count = 0; +} + +/* + * sermouse_process_ms() anlyzes the incoming MS(Z/+/++) bytestream and + * generates events. With prediction it gets 80 updates/sec, assuming + * standard 3-byte packets and 1200 bps. + */ + +static void sermouse_process_ms(struct sermouse *sermouse, signed char data) +{ + struct input_dev *dev = &sermouse->dev; + signed char *buf = sermouse->buf; + + if (data & 0x40) sermouse->count = 0; + + switch (sermouse->count) { + + case 0: + buf[1] = data; + input_report_key(dev, BTN_LEFT, (data >> 5) & 1); + input_report_key(dev, BTN_RIGHT, (data >> 4) & 1); + break; + + case 1: + buf[2] = data; + data = (signed char) (((buf[1] << 6) & 0xc0) | (data & 0x3f)); + input_report_rel(dev, REL_X, data / 2); + input_report_rel(dev, REL_Y, buf[4]); + buf[3] = data - data / 2; + break; + + case 2: + /* Guessing the state of the middle button on 3-button MS-protocol mice - ugly. */ + if ((sermouse->type == SERIO_MS) && !data && !buf[2] && !((buf[0] & 0xf0) ^ buf[1])) + input_report_key(dev, BTN_MIDDLE, !test_bit(BTN_MIDDLE, dev->key)); + buf[0] = buf[1]; + + data = (signed char) (((buf[1] << 4) & 0xc0) | (data & 0x3f)); + input_report_rel(dev, REL_X, buf[3]); + input_report_rel(dev, REL_Y, data - buf[4]); + buf[4] = data / 2; + break; + + case 3: + + switch (sermouse->type) { + + case SERIO_MS: + sermouse->type = SERIO_MP; + + case SERIO_MP: + if ((data >> 2) & 3) break; /* M++ Wireless Extension packet. */ + input_report_key(dev, BTN_MIDDLE, (data >> 5) & 1); + input_report_key(dev, BTN_SIDE, (data >> 4) & 1); + break; + + case SERIO_MZP: + case SERIO_MZPP: + input_report_key(dev, BTN_SIDE, (data >> 5) & 1); + + case SERIO_MZ: + input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1); + input_report_rel(dev, REL_WHEEL, (data & 7) - (data & 8)); + break; + } + + break; + + case 4: + case 6: /* MZ++ packet type. We can get these bytes for M++ too but we ignore them later. */ + buf[1] = (data >> 2) & 0x0f; + break; + + case 5: + case 7: /* Ignore anything besides MZ++ */ + if (sermouse->type != SERIO_MZPP) break; + + switch (buf[1]) { + + case 1: /* Extra mouse info */ + + input_report_key(dev, BTN_SIDE, (data >> 4) & 1); + input_report_key(dev, BTN_EXTRA, (data >> 5) & 1); + input_report_rel(dev, data & 0x80 ? REL_HWHEEL : REL_WHEEL, (data & 7) - (data & 8)); + + break; + + default: /* We don't decode anything else yet. */ + + printk(KERN_WARNING + "sermouse.c: Received MZ++ packet %x, don't know how to handle.\n", buf[1]); + break; + } + + break; + } + + sermouse->count++; +} + +/* + * sermouse_interrupt() handles incoming characters, either gathering them into + * packets or passing them to the command routine as command output. + */ + +static void sermouse_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct sermouse *sermouse = serio->private; + + if (jiffies - sermouse->last > 2) sermouse->count = 0; + sermouse->last = jiffies; + + if (sermouse->type > SERIO_SUN) + sermouse_process_ms(sermouse, data); + else + sermouse_process_msc(sermouse, data); +} + +/* + * sermouse_disconnect() cleans up after we don't want talk + * to the mouse anymore. + */ + +static void sermouse_disconnect(struct serio *serio) +{ + struct sermouse *sermouse = serio->private; + input_unregister_device(&sermouse->dev); + serio_close(serio); + kfree(sermouse); +} + +/* + * sermouse_connect() is a callback form the serio module when + * an unhandled serio port is found. + */ + +static void sermouse_connect(struct serio *serio, struct serio_dev *dev) +{ + struct sermouse *sermouse; + unsigned char c; + + if ((serio->type & SERIO_TYPE) != SERIO_RS232) + return; + + if (!(serio->type & SERIO_PROTO) || ((serio->type & SERIO_PROTO) > SERIO_MZPP)) + return; + + if (!(sermouse = kmalloc(sizeof(struct sermouse), GFP_KERNEL))) + return; + + memset(sermouse, 0, sizeof(struct sermouse)); + + sermouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + sermouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); + sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); + sermouse->dev.private = sermouse; + + serio->private = sermouse; + + sermouse->type = serio->type & SERIO_PROTO; + c = (serio->type & SERIO_EXTRA) >> 16; + + if (c & 0x01) set_bit(BTN_MIDDLE, &sermouse->dev.keybit); + if (c & 0x02) set_bit(BTN_SIDE, &sermouse->dev.keybit); + if (c & 0x04) set_bit(BTN_EXTRA, &sermouse->dev.keybit); + if (c & 0x10) set_bit(REL_WHEEL, &sermouse->dev.relbit); + if (c & 0x20) set_bit(REL_HWHEEL, &sermouse->dev.relbit); + + sprintf(sermouse->phys, "%s/input0", serio->phys); + + sermouse->dev.name = sermouse_protocols[sermouse->type]; + sermouse->dev.phys = sermouse->phys; + sermouse->dev.idbus = BUS_RS232; + sermouse->dev.idvendor = sermouse->type; + sermouse->dev.idproduct = c; + sermouse->dev.idversion = 0x0100; + + if (serio_open(serio, dev)) { + kfree(sermouse); + return; + } + + input_register_device(&sermouse->dev); + + printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys); +} + +static struct serio_dev sermouse_dev = { + interrupt: sermouse_interrupt, + connect: sermouse_connect, + disconnect: sermouse_disconnect +}; + +int __init sermouse_init(void) +{ + serio_register_device(&sermouse_dev); + return 0; +} + +void __exit sermouse_exit(void) +{ + serio_unregister_device(&sermouse_dev); +} + +module_init(sermouse_init); +module_exit(sermouse_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/power.c linux-2.5/drivers/input/power.c --- linux-2.5.5/drivers/input/power.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/power.c Tue Jan 22 17:43:42 2002 @@ -0,0 +1,180 @@ +/* + * $Id: power.c,v 1.10 2001/09/25 09:17:15 vojtech Exp $ + * + * Copyright (c) 2001 "Crazy" James Simmons + * + * Input driver Power Management. + * + * Sponsored by Transvirtual Technology. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct input_handler power_handler; + +/* + * Power management can't be done in a interrupt context. So we have to + * use keventd. + */ +static int suspend_button_pushed = 0; +static void suspend_button_task_handler(void *data) +{ + //extern void pm_do_suspend(void); + udelay(200); /* debounce */ + //pm_do_suspend(); + suspend_button_pushed = 0; +} + +static struct tq_struct suspend_button_task = { + routine: suspend_button_task_handler +}; + +static void power_event(struct input_handle *handle, unsigned int type, + unsigned int code, int down) +{ + struct input_dev *dev = handle->dev; + + printk("Entering power_event\n"); + + if (type != EV_KEY || type != EV_PWR) return; + + if (type == EV_PWR) { + switch (code) { + case KEY_SUSPEND: + printk("Powering down entire device\n"); + + //pm_send_all(PM_SUSPEND, dev); + + if (!suspend_button_pushed) { + suspend_button_pushed = 1; + schedule_task(&suspend_button_task); + } + break; + case KEY_POWER: + /* Hum power down the machine. */ + break; + default: + return; + } + } else { + switch (code) { + case KEY_SUSPEND: + printk("Powering down input device\n"); + /* This is risky. See pm.h for details. */ + if (dev->state != PM_RESUME) + dev->state = PM_RESUME; + else + dev->state = PM_SUSPEND; + pm_send(dev->pm_dev, dev->state, dev); + break; + case KEY_POWER: + /* Turn the input device off completely ? */ + break; + default: + return; + } + } + return; +} + +static struct input_handle *power_connect(struct input_handler *handler, + struct input_dev *dev, + struct input_device_id *id) +{ + struct input_handle *handle; + + if (!test_bit(EV_KEY, dev->evbit) || !test_bit(EV_PWR, dev->evbit)) + return NULL; + + if (!test_bit(KEY_SUSPEND, dev->keybit) || (!test_bit(KEY_POWER, dev->keybit))) + return NULL; + + if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + return NULL; + memset(handle, 0, sizeof(struct input_handle)); + + handle->dev = dev; + handle->handler = handler; + + input_open_device(handle); + + printk(KERN_INFO "power.c: Adding power management to input layer\n"); + return handle; +} + +static void power_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + kfree(handle); +} + +static struct input_device_id power_ids[] = { + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + evbit: { BIT(EV_KEY) }, + keybit: { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) } + }, + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + evbit: { BIT(EV_KEY) }, + keybit: { [LONG(KEY_POWER)] = BIT(KEY_POWER) } + }, + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT, + evbit: { BIT(EV_PWR) }, + }, + { }, /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(input, power_ids); + +static struct input_handler power_handler = { + event: power_event, + connect: power_connect, + disconnect: power_disconnect, + name: "power", + id_table: power_ids, +}; + +static int __init power_init(void) +{ + input_register_handler(&power_handler); + return 0; +} + +static void __exit power_exit(void) +{ + input_unregister_handler(&power_handler); +} + +module_init(power_init); +module_exit(power_exit); + +MODULE_AUTHOR("James Simmons "); +MODULE_DESCRIPTION("Input Power Management driver"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/serio/Config.help linux-2.5/drivers/input/serio/Config.help --- linux-2.5.5/drivers/input/serio/Config.help Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/input/serio/Config.help Sun Jan 27 00:32:29 2002 @@ -12,6 +12,18 @@ The module will be called serio.o. If you want to compile it as a module, say M here and read . +CONFIG_SERIO_I8042 + i8042 is the chip over which the standard AT keyboard and PS/2 + mouse are connected to the computer. If you use these devices, + you'll need to say Y here. + + If unsure, say Y. + + This driver 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 i8042.o. If you want to compile it + as a module, say M here and read . + CONFIG_SERIO_SERPORT Say Y here if you plan to use an input device (mouse, joystick, tablet, 6dof) that communicates over the RS232 serial (COM) port. @@ -24,3 +36,38 @@ inserted in and removed from the running kernel whenever you want). The module will be called serport.o. If you want to compile it as a module, say M here and read . + +CONFIG_SERIO_CT82C710 + Say Y here if you have a Texas Instruments TravelMate notebook + equipped with the ct82c710 chip and want to use a mouse connected + to the "QuickPort". + + If unsure, say N. + + This driver 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 ct82c710.o. If you want to compile it as a + module, say M here and read . + +CONFIG_SERIO_PARKBD + Say Y here if you built a simple parallel port adapter to attach + an additional AT keyboard, XT keyboard or PS/2 mouse. + + More information is available: + + If unsure, say N. + + This driver 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 parkbd.o. If you want to compile it as a + module, say M here and read . + +CONFIG_SERIO_ACORN + Say Y here if you have the Acorn RiscPC and want to use an AT + keyboard connected to its keyboard controller. + + This driver 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 rpckbd.o. If you want to compile it as a + module, say M here and read . + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/serio/Config.in linux-2.5/drivers/input/serio/Config.in --- linux-2.5.5/drivers/input/serio/Config.in Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/input/serio/Config.in Sun Feb 3 18:03:58 2002 @@ -4,4 +4,16 @@ tristate 'Serial i/o support' CONFIG_SERIO +dep_tristate ' i8042 PC Keyboard controller' CONFIG_SERIO_I8042 $CONFIG_SERIO $CONFIG_ISA +if [ "$CONFIG_INPUT_I8042" != "n" ]; then + hex ' Register Base Address' CONFIG_I8042_REG_BASE 60 + int ' PS/2 Keyboard IRQ' CONFIG_I8042_KBD_IRQ 1 + int ' PS/2 AUX IRQ' CONFIG_I8042_AUX_IRQ 12 +fi dep_tristate ' Serial port line discipline' CONFIG_SERIO_SERPORT $CONFIG_SERIO +dep_tristate ' ct82c710 Aux port controller' CONFIG_SERIO_CT82C710 $CONFIG_SERIO $CONFIG_ISA +dep_tristate ' Parallel port keyboard adapter' CONFIG_SERIO_PARKBD $CONFIG_SERIO $CONFIG_PARPORT + +if [ "$CONFIG_ARCH_ACORN" = "y" ]; then + dep_tristate ' Acorn RiscPC keyboard controller' CONFIG_SERIO_ACORN $CONFIG_SERIO +fi diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/serio/Makefile linux-2.5/drivers/input/serio/Makefile --- linux-2.5.5/drivers/input/serio/Makefile Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/input/serio/Makefile Mon Jan 21 23:54:13 2002 @@ -13,7 +13,11 @@ # Each configuration option enables a list of files. obj-$(CONFIG_SERIO) += serio.o +obj-$(CONFIG_SERIO_I8042) += i8042.o +obj-$(CONFIG_SERIO_PARKBD) += parkbd.o obj-$(CONFIG_SERIO_SERPORT) += serport.o +obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o +obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o # The global Rules.make. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/serio/ct82c710.c linux-2.5/drivers/input/serio/ct82c710.c --- linux-2.5.5/drivers/input/serio/ct82c710.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/serio/ct82c710.c Tue Jan 22 17:43:47 2002 @@ -0,0 +1,210 @@ +/* + * $Id: ct82c710.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * 82C710 C&T mouse port chip driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("82C710 C&T mouse port chip driver"); +MODULE_LICENSE("GPL"); + +static char ct82c710_name[] = "C&T 82c710 mouse port"; +static char ct82c710_phys[16]; + +/* + * ct82c710 interface + */ + +#define CT82C710_DEV_IDLE 0x01 /* Device Idle */ +#define CT82C710_RX_FULL 0x02 /* Device Char received */ +#define CT82C710_TX_IDLE 0x04 /* Device XMIT Idle */ +#define CT82C710_RESET 0x08 /* Device Reset */ +#define CT82C710_INTS_ON 0x10 /* Device Interrupt On */ +#define CT82C710_ERROR_FLAG 0x20 /* Device Error */ +#define CT82C710_CLEAR 0x40 /* Device Clear */ +#define CT82C710_ENABLE 0x80 /* Device Enable */ + +#define CT82C710_IRQ 12 + +static int ct82c710_data = 0; +static int ct82c710_status = 0; + +static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs); + +/* + * Wait for device to send output char and flush any input char. + */ + +static int ct82c170_wait(void) +{ + int timeout = 60000; + + while ((inb(ct82c710_status) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE)) + != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) { + + if (inb_p(ct82c710_status) & CT82C710_RX_FULL) inb_p(ct82c710_data); + + udelay(1); + timeout--; + } + + return !timeout; +} + +static void ct82c710_close(struct serio *serio) +{ + if (ct82c170_wait()) + printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); + + outb_p(inb_p(ct82c710_status) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), ct82c710_status); + + if (ct82c170_wait()) + printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); + + free_irq(CT82C710_IRQ, NULL); +} + +static int ct82c710_open(struct serio *serio) +{ + unsigned char status; + + if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL)) + return -1; + + status = inb_p(ct82c710_status); + + status |= (CT82C710_ENABLE | CT82C710_RESET); + outb_p(status, ct82c710_status); + + status &= ~(CT82C710_RESET); + outb_p(status, ct82c710_status); + + status |= CT82C710_INTS_ON; + outb_p(status, ct82c710_status); /* Enable interrupts */ + + while (ct82c170_wait()) { + printk(KERN_ERR "ct82c710: Device busy in open()\n"); + status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON); + outb_p(status, ct82c710_status); + free_irq(CT82C710_IRQ, NULL); + return -1; + } + + return 0; +} + +/* + * Write to the 82C710 mouse device. + */ + +static int ct82c710_write(struct serio *port, unsigned char c) +{ + if (ct82c170_wait()) return -1; + outb_p(c, ct82c710_data); + return 0; +} + +static struct serio ct82c710_port = +{ + type: SERIO_8042, + name: ct82c710_name, + phys: ct82c710_phys, + write: ct82c710_write, + open: ct82c710_open, + close: ct82c710_close, +}; + +/* + * Interrupt handler for the 82C710 mouse port. A character + * is waiting in the 82C710. + */ + +static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs) +{ + if (ct82c710_port.dev) + ct82c710_port.dev->interrupt(&ct82c710_port, inb(ct82c710_data), 0); +} + +/* + * See if we can find a 82C710 device. Read mouse address. + */ + +static int __init ct82c710_probe(void) +{ + outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */ + outb_p(0xaa, 0x3fa); /* Inverse of 55 */ + outb_p(0x36, 0x3fa); /* Address the chip */ + outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */ + outb_p(0x1b, 0x2fa); /* Inverse of e4 */ + outb_p(0x0f, 0x390); /* Write index */ + if (inb_p(0x391) != 0xe4) /* Config address found? */ + return -1; /* No: no 82C710 here */ + + outb_p(0x0d, 0x390); /* Write index */ + ct82c710_data = inb_p(0x391) << 2; /* Get mouse I/O address */ + ct82c710_status = ct82c710_data + 1; + outb_p(0x0f, 0x390); + outb_p(0x0f, 0x391); /* Close config mode */ + + return 0; +} + +int __init ct82c710_init(void) +{ + if (ct82c710_probe()) + return -ENODEV; + + if (request_region(ct82c710_data, 2, "ct82c710")) + return -EBUSY; + + sprintf(ct82c710_phys, "isa%04x/serio0", ct82c710_data); + + serio_register_port(&ct82c710_port); + + printk(KERN_INFO "serio: C&T 82c710 mouse port at %#x irq %d\n", + ct82c710_data, CT82C710_IRQ); + + return 0; +} + +void __exit ct82c710_exit(void) +{ + serio_unregister_port(&ct82c710_port); + release_region(ct82c710_data, 2); +} + +module_init(ct82c710_init); +module_exit(ct82c710_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/serio/i8042.c linux-2.5/drivers/input/serio/i8042.c --- linux-2.5.5/drivers/input/serio/i8042.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/serio/i8042.c Tue Jan 29 18:23:52 2002 @@ -0,0 +1,707 @@ +/* + * $Id: i8042.c,v 1.15 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * i8042 keyboard and mouse controller driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "i8042.h" + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(i8042_noaux, "1i"); +MODULE_PARM(i8042_unlock, "1i"); +MODULE_PARM(i8042_reset, "1i"); +MODULE_PARM(i8042_direct, "1i"); + +static int i8042_noaux; +static int i8042_unlock; +static int i8042_reset; +static int i8042_direct; + +spinlock_t i8042_lock = SPIN_LOCK_UNLOCKED; + +struct i8042_values { + int irq; + unsigned char disable; + unsigned char irqen; + unsigned char exists; + unsigned char *name; + unsigned char *phys; +}; + +static struct serio i8042_kbd_port; +static struct serio i8042_aux_port; +static unsigned char i8042_initial_ctr; +static unsigned char i8042_ctr; + +#ifdef I8042_DEBUG_IO +static unsigned long i8042_start; +#endif + +static unsigned long i8042_unxlate_seen[128 / BITS_PER_LONG]; +static unsigned char i8042_unxlate_table[128] = { + 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, + 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, + 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, + 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, + 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, + 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, + 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, + 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 +}; + +static void i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +/* + * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to + * be ready for reading values from it / writing values to it. + */ + +static int i8042_wait_read(void) +{ + int i = 0; + while ((~inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { + udelay(50); + i++; + } + return -(i == I8042_CTL_TIMEOUT); +} + +static int i8042_wait_write(void) +{ + int i = 0; + while ((inb(I8042_STATUS_REG) & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { + udelay(50); + i++; + } + return -(i == I8042_CTL_TIMEOUT); +} + +/* + * i8042_flush() flushes all data that may be in the keyboard and mouse buffers + * of the i8042 down the toilet. + */ + +static int i8042_flush(void) +{ + unsigned long flags; + int i = 0; + + spin_lock_irqsave(&i8042_lock, flags); + + while ((inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE)) +#ifdef I8042_DEBUG_IO + printk(KERN_DEBUG "i8042.c: %02x <- i8042 (flush) [%d]\n", + inb(I8042_DATA_REG), (int) (jiffies - i8042_start)); +#else + inb(I8042_DATA_REG); +#endif + + spin_unlock_irqrestore(&i8042_lock, flags); + + return i; +} + +/* + * i8042_command() executes a command on the i8042. It also sends the input parameter(s) + * of the commands to it, and receives the output value(s). The parameters are to be + * stored in the param array, and the output is placed into the same array. The number + * of the parameters and output values is encoded in bits 8-11 of the command + * number. + */ + +static int i8042_command(unsigned char *param, int command) +{ + unsigned long flags; + int retval = 0, i = 0; + + spin_lock_irqsave(&i8042_lock, flags); + + retval = i8042_wait_write(); + if (!retval) { +#ifdef I8042_DEBUG_IO + printk(KERN_DEBUG "i8042.c: %02x -> i8042 (command) [%d]\n", + command & 0xff, (int) (jiffies - i8042_start)); +#endif + outb(command & 0xff, I8042_COMMAND_REG); + } + + if (!retval) + for (i = 0; i < ((command >> 12) & 0xf); i++) { + if ((retval = i8042_wait_write())) break; +#ifdef I8042_DEBUG_IO + printk(KERN_DEBUG "i8042.c: %02x -> i8042 (parameter) [%d]\n", + param[i], (int) (jiffies - i8042_start)); +#endif + outb(param[i], I8042_DATA_REG); + } + + if (!retval) + for (i = 0; i < ((command >> 8) & 0xf); i++) { + if ((retval = i8042_wait_read())) break; + if (inb(I8042_STATUS_REG) & I8042_STR_AUXDATA) + param[i] = ~inb(I8042_DATA_REG); + else + param[i] = inb(I8042_DATA_REG); +#ifdef I8042_DEBUG_IO + printk(KERN_DEBUG "i8042.c: %02x <- i8042 (return) [%d]\n", + param[i], (int) (jiffies - i8042_start)); +#endif + } + + spin_unlock_irqrestore(&i8042_lock, flags); + +#ifdef I8042_DEBUG_IO + if (retval) + printk(KERN_DEBUG "i8042.c: -- i8042 (timeout) [%d]\n", + (int) (jiffies - i8042_start)); +#endif + + return retval; +} + +/* + * i8042_kbd_write() sends a byte out through the keyboard interface. + * It also automatically refreshes the CTR value, since some i8042's + * trash their CTR after attempting to send data to an nonexistent + * device. + */ + +static int i8042_kbd_write(struct serio *port, unsigned char c) +{ + unsigned long flags; + int retval = 0; + + spin_lock_irqsave(&i8042_lock, flags); + + if(!(retval = i8042_wait_write())) { +#ifdef I8042_DEBUG_IO + printk(KERN_DEBUG "i8042.c: %02x -> i8042 (kbd-data) [%d]\n", + c, (int) (jiffies - i8042_start)); +#endif + outb(c, I8042_DATA_REG); + } + + spin_unlock_irqrestore(&i8042_lock, flags); + + return retval; +} + +/* + * i8042_aux_write() sends a byte out through the aux interface. + */ + +static int i8042_aux_write(struct serio *port, unsigned char c) +{ + int retval; + +/* + * Send the byte out. + */ + + retval = i8042_command(&c, I8042_CMD_AUX_SEND); + +/* + * Here we restore the CTR value. I don't know why, but i8042's in half-AT + * mode tend to trash their CTR when doing the AUX_SEND command. + */ + + retval += i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR); + +/* + * Make sure the interrupt happens and the character is received even + * in the case the IRQ isn't wired, so that we can receive further + * characters later. + */ + + i8042_interrupt(0, port, NULL); + return retval; +} + +/* + * i8042_open() is called when a port is open by the higher layer. + * It allocates an interrupt and enables the port. + */ + +static int i8042_open(struct serio *port) +{ + struct i8042_values *values = port->driver; + +/* + * Allocate the interrupt + */ + + if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL)) { + printk(KERN_ERR "i8042.c: Can't get irq %d for %s\n", values->irq, values->name); + return -1; + } + +/* + * Enable the device and its interrupt. + */ + + i8042_ctr |= values->irqen; + i8042_ctr &= ~values->disable; + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { + printk(KERN_ERR "i8042.c: Can't write CTR while opening %s.\n", values->name); + return -1; + } + +/* + * Flush buffers + */ + + i8042_flush(); + + return 0; +} + +/* + * i8042_close() frees the interrupt, and disables the interface when the + * upper layer doesn't need it anymore. + */ + +static void i8042_close(struct serio *port) +{ + struct i8042_values *values = port->driver; + +/* + * Disable the device and its interrupt. + */ + + i8042_ctr &= ~values->irqen; + i8042_ctr |= values->disable; + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { + printk(KERN_ERR "i8042.c: Can't write CTR while closing %s.\n", values->name); + return; + } + +/* + * Free the interrupt + */ + + free_irq(values->irq, NULL); +} + +/* + * Structures for registering the devices in the serio.c module. + */ + +static struct i8042_values i8042_kbd_values = { + irq: I8042_KBD_IRQ, + irqen: I8042_CTR_KBDINT, + disable: I8042_CTR_KBDDIS, + name: "KBD", + exists: 0, +}; + +static struct serio i8042_kbd_port = +{ + type: SERIO_8042, + write: i8042_kbd_write, + open: i8042_open, + close: i8042_close, + driver: &i8042_kbd_values, + name: "i8042 Kbd Port", + phys: "isa0060/serio0", +}; + +static struct i8042_values i8042_aux_values = { + irq: I8042_AUX_IRQ, + irqen: I8042_CTR_AUXINT, + disable: I8042_CTR_AUXDIS, + name: "AUX", + exists: 0, +}; + +static struct serio i8042_aux_port = +{ + type: SERIO_8042, + write: i8042_aux_write, + open: i8042_open, + close: i8042_close, + driver: &i8042_aux_values, + name: "i8042 Aux Port", + phys: "isa0060/serio1", +}; + +/* + * i8042_interrupt() is the most important function in this driver - + * it handles the interrupts from the i8042, and sends incoming bytes + * to the upper layers. + */ + +static void i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + unsigned char str, data; + + spin_lock_irqsave(&i8042_lock, flags); + + while ((str = inb(I8042_STATUS_REG)) & I8042_STR_OBF) { + + data = inb(I8042_DATA_REG); + +#ifdef I8042_DEBUG_IO + printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt-%s) [%d]\n", + data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", (int) (jiffies - i8042_start)); +#endif + + if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) { + if (i8042_aux_port.dev) + i8042_aux_port.dev->interrupt(&i8042_aux_port, data, 0); + } else { + if (i8042_kbd_values.exists && i8042_kbd_port.dev) { + if (!i8042_direct) { + if (data > 0x7f) { + if (test_and_clear_bit(data & 0x7f, i8042_unxlate_seen)) { + i8042_kbd_port.dev->interrupt(&i8042_kbd_port, 0xf0, 0); + data = i8042_unxlate_table[data & 0x7f]; + } + } else { + set_bit(data, i8042_unxlate_seen); + data = i8042_unxlate_table[data]; + } + } + i8042_kbd_port.dev->interrupt(&i8042_kbd_port, data, 0); + } + } + } + + spin_unlock_irqrestore(&i8042_lock, flags); +} + +/* + * i8042_controller init initializes the i8042 controller, and, + * most importantly, sets it into non-xlated mode. + */ + +static int __init i8042_controller_init(void) +{ + +/* + * Check the i/o region before we touch it. + */ +#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) + if (check_region(I8042_DATA_REG, 16)) { + printk(KERN_ERR "i8042.c: %#x port already in use!\n", I8042_DATA_REG); + return -1; + } +#endif + +/* + * Test the i8042. We need to know if it thinks it's working correctly + * before doing anything else. + */ + + i8042_flush(); + + if (i8042_reset) { + + unsigned char param; + + if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { + printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); + return -1; + } + + if (param != I8042_RET_CTL_TEST) { + printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", + param, I8042_RET_CTL_TEST); + return -1; + } + } + +/* + * Read the CTR. + */ + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { + printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); + return -1; + } + +/* + * Save the CTR for restoral on unload / reboot. + */ + + i8042_initial_ctr = i8042_ctr; + +/* + * Disable both interfaces and their interrupts. + */ + + i8042_ctr |= I8042_CTR_KBDDIS; + i8042_ctr &= ~I8042_CTR_KBDINT; + +/* + * Handle keylock. + */ + + if (~inb(I8042_STATUS_REG) & I8042_STR_KEYLOCK) { + + if (i8042_unlock) { + i8042_ctr |= I8042_CTR_IGNKEYLOCK; + } else { + printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); + } + } + +/* + * Set nontranslated mode for the kbd interface. This is vital for a working + * scancode set 2/3 support. After this the kbd interface becomes a simple serial + * in/out, like the aux interface is. If the user doesn't wish this, the driver + * tries to untranslate the values after the i8042 translates them. + */ + + if (i8042_direct) + i8042_ctr &= ~I8042_CTR_XLATE; + +/* + * Write CTR back. + */ + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { + printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); + return -1; + } + + return 0; +} + +/* + * Here we try to reset everything back to a state in which the BIOS will be + * able to talk to the hardware when rebooting. + */ + +void i8042_controller_cleanup(void) +{ + +/* + * Reset the controller. + */ + + if (i8042_reset) { + unsigned char param; + + if (i8042_command(¶m, I8042_CMD_CTL_TEST)) + printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n"); + } + +/* + * Restore the original control register setting. + */ + + i8042_ctr = i8042_initial_ctr; + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) + printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); + +/* + * Reset anything that is connected to the ports if the ports + * are enabled in the original config. + */ + + if (i8042_kbd_values.exists) + i8042_kbd_write(&i8042_kbd_port, 0xff); + + if (i8042_aux_values.exists) + i8042_aux_write(&i8042_aux_port, 0xff); +} + +/* + * i8042_check_aux() applies as much paranoia as it can at detecting + * the presence of an AUX interface. + */ + +static int __init i8042_check_aux(struct i8042_values *values, struct serio *port) +{ + unsigned char param; + + i8042_flush(); + +/* + * Internal loopback test - filters out AT-type i8042's + */ + + param = 0x5a; + + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xa5) + return -1; + +/* + * External connection test - filters out AT-soldered PS/2 i8042's + */ + + if (i8042_command(¶m, I8042_CMD_AUX_TEST) || param) + return -1; + +/* + * Bit assignment test - filters out PS/2 i8042's in AT mode + */ + + if (i8042_command(¶m, I8042_CMD_AUX_DISABLE)) + return -1; + + if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS)) + return -1; + + if (i8042_command(¶m, I8042_CMD_AUX_TEST) || param) { + +/* + * We've got an old AMI i8042 with 'Bad Cache' commands. + */ + + i8042_command(¶m, I8042_CMD_AUX_ENABLE); + return -1; + } + + if (i8042_command(¶m, I8042_CMD_AUX_ENABLE)) + return -1; + + if (i8042_command(¶m, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS)) + return -1; + +/* + * Disable the interface. + */ + + i8042_ctr |= I8042_CTR_AUXDIS; + i8042_ctr &= ~I8042_CTR_AUXINT; + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) + return -1; + + return 0; +} + +/* + * i8042_port_register() marks the device as existing, + * registers it, and reports to the user. + */ + +static int __init i8042_port_register(struct i8042_values *values, struct serio *port) +{ + values->exists = 1; + serio_register_port(port); + printk(KERN_INFO "serio: i8042 %s port at %#x,%#x irq %d\n", + values->name, I8042_DATA_REG, I8042_COMMAND_REG, values->irq); + + return 0; +} + +/* + * Module init and cleanup functions. + */ + +void __init i8042_setup(char *str, int *ints) +{ + if (!strcmp(str, "i8042_reset=1")) + i8042_reset = 1; + if (!strcmp(str, "i8042_noaux=1")) + i8042_noaux = 1; + if (!strcmp(str, "i8042_unlock=1")) + i8042_unlock = 1; + if (!strcmp(str, "i8042_direct=1")) + i8042_direct = 1; +} + +/* + * Reset the 8042 back to original mode. + */ +static int i8042_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code==SYS_DOWN || code==SYS_HALT) + i8042_controller_cleanup(); + return NOTIFY_DONE; +} + +static struct notifier_block i8042_notifier= +{ + i8042_notify_sys, + NULL, + 0 +}; + +int __init i8042_init(void) +{ +#ifdef I8042_DEBUG_IO + i8042_start = jiffies; +#endif + + if (i8042_controller_init()) + return -ENODEV; + + i8042_port_register(&i8042_kbd_values, &i8042_kbd_port); + + if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values, &i8042_aux_port)) + i8042_port_register(&i8042_aux_values, &i8042_aux_port); + +/* + * On ix86 platforms touching the i8042 data register region can do really + * bad things. Because of this the region is always reserved on ix86 boxes. + */ +#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) + request_region(I8042_DATA_REG, 16, "i8042"); +#endif + register_reboot_notifier(&i8042_notifier); + return 0; +} + +void __exit i8042_exit(void) +{ + unregister_reboot_notifier(&i8042_notifier); + + if (i8042_kbd_values.exists) + serio_unregister_port(&i8042_kbd_port); + + if (i8042_aux_values.exists) + serio_unregister_port(&i8042_aux_port); + + i8042_controller_cleanup(); +#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) + release_region(I8042_DATA_REG, 16); +#endif +} + +module_init(i8042_init); +module_exit(i8042_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/serio/i8042.h linux-2.5/drivers/input/serio/i8042.h --- linux-2.5.5/drivers/input/serio/i8042.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/serio/i8042.h Tue Feb 26 16:31:15 2002 @@ -0,0 +1,128 @@ +#ifndef _I8042_H +#define _I8042_H + +/* + * $Id: i8042.h,v 1.6 2001/10/05 22:48:09 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +/* + * If you want to reset your i8042 upon boot, define this. + */ + +#undef I8042_RESET + +/* + * If you want to trace all the i/o the i8042 module does for + * debugging purposes, define this. + */ + +#undef I8042_DEBUG_IO + +/* + * On most PC based systems the keyboard IRQ is 1. + */ + +#define I8042_KBD_IRQ CONFIG_I8042_KBD_IRQ + +/* + * On most PC based systems the aux port IRQ is 12. There are exceptions, + * though. Unfortunately IRQ probing is not possible without touching + * the device attached to the port. + */ + +#define I8042_AUX_IRQ CONFIG_I8042_AUX_IRQ + +/* + * This is in 50us units, the time we wait for the i8042 to react. This + * has to be long enough for the i8042 itself to timeout on sending a byte + * to a non-existent mouse. + */ + +#define I8042_CTL_TIMEOUT 10000 + +/* + * Register numbers. + */ + +#define I8042_COMMAND_REG CONFIG_I8042_REG_BASE + 4 +#define I8042_STATUS_REG CONFIG_I8042_REG_BASE + 4 +#define I8042_DATA_REG CONFIG_I8042_REG_BASE + +/* + * Status register bits. + */ + +#define I8042_STR_PARITY 0x80 +#define I8042_STR_TIMEOUT 0x40 +#define I8042_STR_AUXDATA 0x20 +#define I8042_STR_KEYLOCK 0x10 +#define I8042_STR_CMDDAT 0x08 +#define I8042_STR_IBF 0x02 +#define I8042_STR_OBF 0x01 + +/* + * Control register bits. + */ + +#define I8042_CTR_KBDINT 0x01 +#define I8042_CTR_AUXINT 0x02 +#define I8042_CTR_IGNKEYLOCK 0x08 +#define I8042_CTR_KBDDIS 0x10 +#define I8042_CTR_AUXDIS 0x20 +#define I8042_CTR_XLATE 0x40 + +/* + * Commands. + */ + +#define I8042_CMD_CTL_RCTR 0x0120 +#define I8042_CMD_CTL_WCTR 0x1060 +#define I8042_CMD_CTL_TEST 0x01aa + +#define I8042_CMD_KBD_DISABLE 0x00ad +#define I8042_CMD_KBD_ENABLE 0x00ae +#define I8042_CMD_KBD_TEST 0x01ab +#define I8042_CMD_KBD_LOOP 0x11d2 + +#define I8042_CMD_AUX_DISABLE 0x00a7 +#define I8042_CMD_AUX_ENABLE 0x00a8 +#define I8042_CMD_AUX_TEST 0x01a9 +#define I8042_CMD_AUX_SEND 0x10d4 +#define I8042_CMD_AUX_LOOP 0x11d3 + +/* + * Return codes. + */ + +#define I8042_RET_CTL_TEST 0x55 + +/* + * Expected maximum internal i8042 buffer size. This is used for flushing + * the i8042 buffers. 32 should be more than enough. + */ + +#define I8042_BUFFER_SIZE 32 + +#endif _I8042_H diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/serio/parkbd.c linux-2.5/drivers/input/serio/parkbd.c --- linux-2.5.5/drivers/input/serio/parkbd.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/serio/parkbd.c Tue Jan 22 17:43:47 2002 @@ -0,0 +1,203 @@ +/* + * $Id: parkbd.c,v 1.8 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * Parallel port to Keyboard port adapter driver for Linux + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Parallel port to Keyboard port adapter driver"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(parkbd, "1i"); +MODULE_PARM(parkbd_mode, "1i"); + +#define PARKBD_CLOCK 0x01 /* Strobe & Ack */ +#define PARKBD_DATA 0x02 /* AutoFd & Busy */ + +static int parkbd = 0; +static int parkbd_mode = SERIO_8042; + +static int parkbd_buffer = 0; +static int parkbd_counter = 0; +static int parkbd_last = 0; +static int parkbd_writing = 0; +static unsigned long parkbd_start = 0; + +static struct pardevice *parkbd_dev; + +static char parkbd_name[] = "PARKBD AT/XT keyboard adapter"; +static char parkbd_phys[32]; + +static int parkbd_readlines(void) +{ + return (parport_read_status(parkbd_dev->port) >> 6) ^ 2; +} + +static void parkbd_writelines(int data) +{ + parport_write_control(parkbd_dev->port, (~data & 3) | 0x10); +} + +static int parkbd_write(struct serio *port, unsigned char c) +{ + unsigned char p; + + if (!parkbd_mode) return -1; + + p = c ^ (c >> 4); + p = p ^ (p >> 2); + p = p ^ (p >> 1); + + parkbd_counter = 0; + parkbd_writing = 1; + parkbd_buffer = c | (((int) (~p & 1)) << 8) | 0x600; + + parkbd_writelines(2); + + return 0; +} + +static int parkbd_open(struct serio *port) +{ + return 0; +} + +static void parkbd_close(struct serio *port) +{ +} + +static struct serio parkbd_port = +{ + write: parkbd_write, + open: parkbd_open, + close: parkbd_close, + name: parkbd_name, + phys: parkbd_phys, +}; + +static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + + if (parkbd_writing) { + + if (parkbd_counter && ((parkbd_counter == 11) || (jiffies - parkbd_last > 1))) { + parkbd_counter = 0; + parkbd_buffer = 0; + parkbd_writing = 0; + parkbd_writelines(3); + return; + } + + parkbd_writelines(((parkbd_buffer >> parkbd_counter++) & 1) | 2); + + if (parkbd_counter == 11) { + parkbd_counter = 0; + parkbd_buffer = 0; + parkbd_writing = 0; + parkbd_writelines(3); + } + + } else { + + if ((parkbd_counter == parkbd_mode + 10) || (jiffies - parkbd_last > 1)) { + parkbd_counter = 0; + parkbd_buffer = 0; + } + + parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++; + + if (parkbd_counter == parkbd_mode + 10) { + if (parkbd_port.dev) + parkbd_port.dev->interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0); + } + } + + parkbd_last = jiffies; +} + +static int parkbd_getport(void) +{ + struct parport *pp; + + if (parkbd < 0) { + printk(KERN_ERR "parkbd: no port specified\n"); + return -ENODEV; + } + + for (pp = parport_enumerate(); pp != NULL && (parkbd > 0); pp = pp->next) parkbd--; + + if (pp == NULL) { + printk(KERN_ERR "parkbd: no such parport\n"); + return -ENODEV; + } + + parkbd_dev = parport_register_device(pp, "parkbd", NULL, NULL, parkbd_interrupt, PARPORT_DEV_EXCL, NULL); + + if (!parkbd_dev) + return -ENODEV; + + if (parport_claim(parkbd_dev)) { + parport_unregister_device(parkbd_dev); + return -EBUSY; + } + + parkbd_start = jiffies; + + return 0; +} + + +int __init parkbd_init(void) +{ + if (parkbd_getport()) return -1; + parkbd_writelines(3); + parkbd_port.type = parkbd_mode; + + sprintf(parkbd_phys, "%s/serio0", parkbd_dev->port->name); + + serio_register_port(&parkbd_port); + + printk(KERN_INFO "serio: PARKBD %s adapter on %s\n", + parkbd_mode ? "AT" : "XT", parkbd_dev->port->name); + + return 0; +} + +void __exit parkbd_exit(void) +{ + parport_release(parkbd_dev); + serio_unregister_port(&parkbd_port); + parport_unregister_device(parkbd_dev); +} + +module_init(parkbd_init); +module_exit(parkbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/serio/rpckbd.c linux-2.5/drivers/input/serio/rpckbd.c --- linux-2.5.5/drivers/input/serio/rpckbd.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/serio/rpckbd.c Tue Jan 22 17:48:01 2002 @@ -0,0 +1,117 @@ +/* + * $Id: rpckbd.c,v 1.7 2001/09/25 10:12:07 vojtech Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * + * Based on the work of: + * unknown author + */ + +/* + * Acorn RiscPC PS/2 keyboard controller driver for Linux/ARM + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver"); +MODULE_LICENSE("GPL"); + +static inline void rpckbd_write(unsigned char val) +{ + while(!(inb(IOMD_KCTRL) & (1 << 7))); + outb(val, IOMD_KARTTX); +} + +static struct serio rpckbd_port = +{ + type: SERIO_8042, + write: rpckbd_write, + name: "RiscPC PS/2 kbd port", + phys: "rpckbd/serio0", +}; + +static void rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs) +{ + kbd_pt_regs = regs; + + while (inb(IOMD_KCTRL) & (1 << 5)) + if (rpckbd_port.dev) + rpckbd_port.dev->interrupt(&rpckbd_port, inb(IOMD_KARTRX), 0); + +} + +static void rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs) +{ +} + +static int __init rpckbd_init(void) +{ + unsigned long flags; + + /* Reset the keyboard state machine. */ + outb(0, IOMD_KCTRL); + outb(8, IOMD_KCTRL); + + save_flags_cli(flags); + + if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", NULL) != 0) { + printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ!\n") + return -EBUSY; + } + + if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", NULL) != 0) { + printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ!\n") + free_irq(IRQ_KEYBOARDRX, NULL); + return -EBUSY; + } + + disable_irq(IRQ_KEYBOARDTX); + (void)IOMD_KARTRX; + + restore_flags(flags); + + register_serio_port(&rpckbd_port); + printk(KERN_INFO "serio: RiscPC PS/2 kbd port irq %d %d\n", IRQ_KEYBOARDRX, IRQ_KEYBOARDTX); + + return 0; +} + +static void __exit rpckbd_exit(void) +{ + free_irq(IRQ_KEYBOARDRX, NULL); + free_irq(IRQ_KEYBOARDTX, NULL); + + unregister_serio_port(&rpckbd_port); +} + +module_init(rpckbd_init); +module_exit(rpckbd_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/serio/serio.c linux-2.5/drivers/input/serio/serio.c --- linux-2.5.5/drivers/input/serio/serio.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/input/serio/serio.c Fri Mar 1 14:51:42 2002 @@ -1,9 +1,7 @@ /* - * $Id: serio.c,v 1.5 2000/06/04 17:44:59 vojtech Exp $ + * $Id: serio.c,v 1.15 2002/01/22 21:12:03 vojtech Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1999-2001 Vojtech Pavlik */ /* @@ -27,14 +25,16 @@ * * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Serio abstraction core"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(serio_register_port); @@ -47,7 +47,6 @@ static struct serio *serio_list; static struct serio_dev *serio_dev; -static int serio_number; static void serio_find_dev(struct serio *serio) { @@ -69,7 +68,6 @@ void serio_register_port(struct serio *serio) { - serio->number = serio_number++; serio->next = serio_list; serio_list = serio; serio_find_dev(serio); @@ -84,8 +82,6 @@ if (serio->dev && serio->dev->disconnect) serio->dev->disconnect(serio); - - serio_number--; } void serio_register_device(struct serio_dev *dev) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/serio/serport.c linux-2.5/drivers/input/serio/serport.c --- linux-2.5.5/drivers/input/serio/serport.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/input/serio/serport.c Fri Mar 1 14:51:54 2002 @@ -1,9 +1,7 @@ /* - * $Id: serport.c,v 1.7 2001/05/25 19:00:27 jdeneux Exp $ + * $Id: serport_old.c,v 1.10 2002/01/24 19:52:57 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik - * - * Sponsored by SuSE */ /* @@ -28,7 +26,7 @@ * * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -39,12 +37,19 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Input device TTY line discipline"); +MODULE_LICENSE("GPL"); + struct serport { struct tty_struct *tty; wait_queue_head_t wait; struct serio serio; + char phys[32]; }; +char serport_name[] = "Serial port"; + /* * Callback functions from the serio code. */ @@ -75,6 +80,8 @@ static int serport_ldisc_open(struct tty_struct *tty) { struct serport *serport; + char ttyname[64]; + int i; MOD_INC_USE_COUNT; @@ -85,9 +92,19 @@ memset(serport, 0, sizeof(struct serport)); + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); serport->tty = tty; tty->disc_data = serport; + strcpy(ttyname, tty->driver.name); + for (i = 0; ttyname[i] != 0 && ttyname[i] != '/'; i++); + ttyname[i] = 0; + + sprintf(serport->phys, "%s%d/serio0", ttyname, minor(tty->device) - tty->driver.minor_start); + + serport->serio.name = serport_name; + serport->serio.phys = serport->phys; + serport->serio.type = SERIO_RS232; serport->serio.write = serport_serio_write; serport->serio.open = serport_serio_open; @@ -156,14 +173,14 @@ serio_register_port(&serport->serio); - printk(KERN_INFO "serio%d: Serial port %s\n", serport->serio.number, name); + printk(KERN_INFO "serio: Serial port %s\n", name); add_wait_queue(&serport->wait, &wait); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); while(serport->serio.type && !signal_pending(current)) schedule(); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&serport->wait, &wait); serio_unregister_port(&serport->serio); @@ -187,6 +204,14 @@ return -EINVAL; } +static void serport_ldisc_write_wakeup(struct tty_struct * tty) +{ + struct serport *sp = (struct serport *) tty->disc_data; + + serio_dev_write_wakeup(&sp->serio); + +} + /* * The line discipline structure. */ @@ -199,6 +224,7 @@ ioctl: serport_ldisc_ioctl, receive_buf: serport_ldisc_receive, receive_room: serport_ldisc_room, + write_wakeup: serport_ldisc_write_wakeup }; /* @@ -222,5 +248,3 @@ module_init(serport_init); module_exit(serport_exit); - -MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/input/tsdev.c linux-2.5/drivers/input/tsdev.c --- linux-2.5.5/drivers/input/tsdev.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/input/tsdev.c Sat Jan 26 20:31:39 2002 @@ -0,0 +1,403 @@ +/* + * $Id: tsdev.c,v 1.10 2001/12/26 21:08:33 jsimmons Exp $ + * + * Copyright (c) 2001 "Crazy" james Simmons + * + * Input driver to Touchscreen device driver module. + * + * Sponsored by Transvirtual Technology + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along 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 . + */ + +#define TSDEV_MINOR_BASE 32 +#define TSDEV_MINORS 32 +#define TSDEV_BUFFER_SIZE 64 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CONFIG_INPUT_TSDEV_SCREEN_X +#define CONFIG_INPUT_TSDEV_SCREEN_X 1024 +#endif +#ifndef CONFIG_INPUT_TSDEV_SCREEN_Y +#define CONFIG_INPUT_TSDEV_SCREEN_Y 768 +#endif + +struct tsdev { + int exist; + int open; + int minor; + char name[16]; + wait_queue_head_t wait; + struct tsdev_list *list; + struct input_handle handle; + devfs_handle_t devfs; +}; + +/* From Compaq's Touch Screen Specification version 0.2 (draft) */ +typedef struct { + short pressure; + short x; + short y; + short millisecs; +} TS_EVENT; + +struct tsdev_list { + struct fasync_struct *fasync; + struct tsdev_list *next; + struct tsdev *tsdev; + int head, tail; + int oldx, oldy, pendown; + TS_EVENT event[TSDEV_BUFFER_SIZE]; +}; + +static struct input_handler tsdev_handler; + +static struct tsdev *tsdev_table[TSDEV_MINORS]; + +static int xres = CONFIG_INPUT_TSDEV_SCREEN_X; +static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y; + +static int tsdev_fasync(int fd, struct file *file, int on) +{ + struct tsdev_list *list = file->private_data; + int retval; + + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static int tsdev_open(struct inode * inode, struct file * file) +{ + int i = minor(inode->i_rdev) - TSDEV_MINOR_BASE; + struct tsdev_list *list; + + if (i >= TSDEV_MINORS || !tsdev_table[i]) + return -ENODEV; + + if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL))) + return -ENOMEM; + memset(list, 0, sizeof(struct tsdev_list)); + + list->tsdev = tsdev_table[i]; + list->next = tsdev_table[i]->list; + tsdev_table[i]->list = list; + file->private_data = list; + + if (!list->tsdev->open++) + if (list->tsdev->exist) + input_open_device(&list->tsdev->handle); + return 0; +} + +static int tsdev_release(struct inode * inode, struct file * file) +{ + struct tsdev_list *list = file->private_data; + struct tsdev_list **listptr; + + listptr = &list->tsdev->list; + tsdev_fasync(-1, file, 0); + + while (*listptr && (*listptr != list)) + listptr = &((*listptr)->next); + *listptr = (*listptr)->next; + + if (!--list->tsdev->open) { + if (list->tsdev->exist) { + input_close_device(&list->tsdev->handle); + } else { + input_unregister_minor(list->tsdev->devfs); + tsdev_table[list->tsdev->minor] = NULL; + kfree(list->tsdev); + } + } + kfree(list); + return 0; +} + +static ssize_t tsdev_read(struct file * file, char * buffer, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + struct tsdev_list *list = file->private_data; + int retval = 0; + + if (list->head == list->tail) { + add_wait_queue(&list->tsdev->wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (list->head == list->tail) { + if (!list->tsdev->exist) { + retval = -ENODEV; + break; + } + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&list->tsdev->wait, &wait); + } + + if (retval) + return retval; + + while (list->head != list->tail && retval+sizeof(TS_EVENT) <= count) { + if (copy_to_user(buffer + retval, list->event + list->tail, + sizeof(TS_EVENT))) return -EFAULT; + list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1); + retval += sizeof(TS_EVENT); + } + return retval; +} + +/* No kernel lock - fine */ +static unsigned int tsdev_poll(struct file *file, poll_table *wait) +{ + struct tsdev_list *list = file->private_data; + + poll_wait(file, &list->tsdev->wait, wait); + if (list->head != list->tail) + return POLLIN | POLLRDNORM; + return 0; +} + +static int tsdev_ioctl(struct inode *inode, struct file *file,unsigned int cmd, + unsigned long arg) +{ +/* + struct tsdev_list *list = file->private_data; + struct tsdev *evdev = list->tsdev; + struct input_dev *dev = tsdev->handle.dev; + int retval; + + switch (cmd) { + case HHEHE: + return 0; + case hjff: + return 0; + default: + return 0; + } +*/ + return -EINVAL; +} + +struct file_operations tsdev_fops = { + owner: THIS_MODULE, + open: tsdev_open, + release: tsdev_release, + read: tsdev_read, + poll: tsdev_poll, + fasync: tsdev_fasync, + ioctl: tsdev_ioctl, +}; + +static void tsdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + struct tsdev *tsdev = handle->private; + struct tsdev_list *list = tsdev->list; + struct timeval time; + int size; + + while (list) { + switch (type) { + case EV_ABS: + switch (code) { + case ABS_X: + size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; + if(size > 0) + list->oldx = ((value - handle->dev->absmin[ABS_X]) * xres / size); + else + list->oldx = ((value - handle->dev->absmin[ABS_X])); + break; + case ABS_Y: + size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; + if(size > 0) + list->oldy = ((value - handle->dev->absmin[ABS_Y]) * yres / size); + else + list->oldy = ((value - handle->dev->absmin[ABS_Y])); + break; + case ABS_PRESSURE: + list->pendown = ((value > handle->dev->absmin[ABS_PRESSURE])) ? + value - handle->dev->absmin[ABS_PRESSURE] : 0; + break; + } + break; + + case EV_REL: + switch (code) { + case REL_X: + list->oldx += value; + if(list->oldx < 0) + list->oldx = 0; + else if(list->oldx > xres) + list->oldx = xres; + break; + case REL_Y: + list->oldy += value; + if(list->oldy < 0) + list->oldy = 0; + else if(list->oldy > xres) + list->oldy = xres; + break; + } + break; + + case EV_KEY: + if (code == BTN_TOUCH || code == BTN_MOUSE) { + switch (value) { + case 0: + list->pendown = 0; + break; + case 1: + if(!list->pendown) list->pendown = 1; + break; + case 2: + return; + } + } else + return; + break; + } + do_gettimeofday(&time); + list->event[list->head].millisecs = time.tv_usec/100; + list->event[list->head].pressure = list->pendown; + list->event[list->head].x = list->oldx; + list->event[list->head].y = list->oldy; + list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1); + kill_fasync(&list->fasync, SIGIO, POLL_IN); + list = list->next; + } + wake_up_interruptible(&tsdev->wait); +} + +static struct input_handle *tsdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) +{ + struct tsdev *tsdev; + int minor; + + for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor]; minor++); + if (minor == TSDEV_MINORS) { + printk(KERN_ERR "tsdev: You have way too many touchscreens\n"); + return NULL; + } + + if (!(tsdev = kmalloc(sizeof(struct tsdev), GFP_KERNEL))) + return NULL; + memset(tsdev, 0, sizeof(struct tsdev)); + init_waitqueue_head(&tsdev->wait); + + tsdev->minor = minor; + tsdev_table[minor] = tsdev; + sprintf(tsdev->name, "ts%d", minor); + + tsdev->handle.dev = dev; + tsdev->handle.name = tsdev->name; + tsdev->handle.handler = handler; + tsdev->handle.private = tsdev; + + tsdev->devfs = input_register_minor("ts%d", minor, TSDEV_MINOR_BASE); + + tsdev->exist = 1; + + return &tsdev->handle; +} + +static void tsdev_disconnect(struct input_handle *handle) +{ + struct tsdev *tsdev = handle->private; + + tsdev->exist = 0; + + if (tsdev->open) { + input_close_device(handle); + wake_up_interruptible(&tsdev->wait); + } else { + input_unregister_minor(tsdev->devfs); + tsdev_table[tsdev->minor] = NULL; + kfree(tsdev); + } +} + +static struct input_device_id tsdev_ids[] = { + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, + evbit: { BIT(EV_KEY) | BIT(EV_REL) }, + keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, + relbit: { BIT(REL_X) | BIT(REL_Y) }, + }, /* A mouse like device, at least one button, two relative axes */ + + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, + keybit: { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, + absbit: { BIT(ABS_X) | BIT(ABS_Y) }, + }, /* A tablet like device, at least touch detection, two absolute axes */ + + { }, /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(input, tsdev_ids); + +static struct input_handler tsdev_handler = { + event: tsdev_event, + connect: tsdev_connect, + disconnect: tsdev_disconnect, + fops: &tsdev_fops, + minor: TSDEV_MINOR_BASE, + name: "tsdev", + id_table: tsdev_ids, +}; + +static int __init tsdev_init(void) +{ + input_register_handler(&tsdev_handler); + printk(KERN_INFO "ts: Compaq touchscreen protocol output\n"); + return 0; +} + +static void __exit tsdev_exit(void) +{ + input_unregister_handler(&tsdev_handler); +} + +module_init(tsdev_init); +module_exit(tsdev_exit); + +MODULE_AUTHOR("James Simmons "); +MODULE_DESCRIPTION("Input driver to touchscreen converter"); +MODULE_PARM(xres, "i"); +MODULE_PARM_DESC(xres, "Horizontal screen resolution"); +MODULE_PARM(yres, "i"); +MODULE_PARM_DESC(yres, "Vertical screen resolution"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/Config.help linux-2.5/drivers/isdn/Config.help --- linux-2.5.5/drivers/isdn/Config.help Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/isdn/Config.help Tue Feb 26 21:24:48 2002 @@ -161,6 +161,14 @@ Enable this if you like to use ISDN in US on a NI1 basic rate interface. +CONFIG_HISAX_MAX_CARDS + This is used to allocate a driver-internal structure array with one + entry for each HiSax card on your system. + +CONFIG_HISAX_MAX_CARDS + This option allows you to specify the maximum number of cards which + the HiSax driver will be able to handle. + CONFIG_HISAX_16_0 This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8 and many compatibles. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/Config.in linux-2.5/drivers/isdn/Config.in --- linux-2.5.5/drivers/isdn/Config.in Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/isdn/Config.in Tue Feb 26 21:24:48 2002 @@ -84,6 +84,7 @@ dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL dep_tristate 'AVM Fritz!Card classic support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_CLASSIC $CONFIG_HISAX $CONFIG_EXPERIMENTAL + dep_tristate 'HFC PCI support (EXPERIMENTAL)' CONFIG_HISAX_HFCPCI $CONFIG_HISAX $CONFIG_EXPERIMENTAL fi endmenu diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/avmb1/capi.c linux-2.5/drivers/isdn/avmb1/capi.c --- linux-2.5.5/drivers/isdn/avmb1/capi.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/isdn/avmb1/capi.c Sun Feb 17 23:08:54 2002 @@ -1535,7 +1535,7 @@ /* -------- init function and module interface ---------------------- */ -static void __exit alloc_exit(void) +static void alloc_exit(void) { if (capidev_cachep) { (void)kmem_cache_destroy(capidev_cachep); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/avmb1/capifs.c linux-2.5/drivers/isdn/avmb1/capifs.c --- linux-2.5.5/drivers/isdn/avmb1/capifs.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/isdn/avmb1/capifs.c Thu Feb 14 02:57:58 2002 @@ -235,10 +235,9 @@ unsigned int maxncci = 512; char *this_char, *value; - this_char = NULL; - if ( options ) - this_char = strtok(options,","); - for ( ; this_char; this_char = strtok(NULL,",")) { + while ((this_char = strsep(&options,",")) != NULL) { + if (!*this_char) + continue; if ((value = strchr(this_char,'=')) != NULL) *value++ = 0; if (!strcmp(this_char,"uid")) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/avmb1/kcapi.c linux-2.5/drivers/isdn/avmb1/kcapi.c --- linux-2.5.5/drivers/isdn/avmb1/kcapi.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/isdn/avmb1/kcapi.c Thu Feb 14 00:36:31 2002 @@ -102,8 +102,8 @@ #define APPL(a) (&applications[(a)-1]) #define VALID_APPLID(a) ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a) #define APPL_IS_FREE(a) (APPL(a)->applid == 0) -#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0); -#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0); +#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0) +#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0) #define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/hisax/Makefile linux-2.5/drivers/isdn/hisax/Makefile --- linux-2.5.5/drivers/isdn/hisax/Makefile Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/isdn/hisax/Makefile Tue Feb 26 21:24:48 2002 @@ -64,6 +64,7 @@ obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o obj-$(CONFIG_HISAX_FRITZ_CLASSIC) += hisax_isac.o hisax_hscx.o hisax_fcclassic.o +obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_hfcpci.o CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?) CFLAGS_cert.o := -DCERTIFICATION=$(CERT) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/hisax/hisax_fcpcipnp.c linux-2.5/drivers/isdn/hisax/hisax_fcpcipnp.c --- linux-2.5.5/drivers/isdn/hisax/hisax_fcpcipnp.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/isdn/hisax/hisax_fcpcipnp.c Tue Feb 26 21:24:48 2002 @@ -65,6 +65,7 @@ static int protocol = 2; /* EURO-ISDN Default */ MODULE_PARM(protocol, "i"); +MODULE_LICENSE("GPL"); // ---------------------------------------------------------------------- @@ -369,7 +370,7 @@ unsigned long flags; unsigned char *p; - DBG(0x40, ""); + DBG(0x40, "hdlc_fill_fifo"); if (skb->len == 0) BUG(); @@ -945,14 +946,14 @@ static struct pci_driver fcpci_driver = { name: "fcpci", probe: fcpci_probe, - remove: fcpci_remove, + remove: __devexit_p(fcpci_remove), id_table: fcpci_ids, }; static struct isapnp_driver fcpnp_driver = { name: "fcpnp", probe: fcpnp_probe, - remove: fcpnp_remove, + remove: __devexit_p(fcpnp_remove), id_table: fcpnp_ids, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/hisax/hisax_hfcpci.c linux-2.5/drivers/isdn/hisax/hisax_hfcpci.c --- linux-2.5.5/drivers/isdn/hisax/hisax_hfcpci.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/isdn/hisax/hisax_hfcpci.c Tue Feb 26 21:24:48 2002 @@ -0,0 +1,1646 @@ +/* + * Driver for HFC PCI based cards + * + * Author Kai Germaschewski + * Copyright 2002 by Kai Germaschewski + * 2000 by Karsten Keil + * 2000 by Werner Cornelius + * + * based upon Werner Cornelius's original hfc_pci.c driver + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +// XXX timer3 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hisax_hfcpci.h" + +// debugging cruft +#define __debug_variable debug +#include "hisax_debug.h" + +#ifdef CONFIG_HISAX_DEBUG +static int debug = 0; +MODULE_PARM(debug, "i"); +#endif + +MODULE_AUTHOR("Kai Germaschewski /Werner Cornelius "); +MODULE_DESCRIPTION("HFC PCI ISDN driver"); + +#define ID(ven, dev, name) \ + { vendor: PCI_VENDOR_ID_##ven, \ + device: PCI_DEVICE_ID_##dev, \ + subvendor: PCI_ANY_ID, \ + subdevice: PCI_ANY_ID, \ + class: 0, \ + class_mask: 0, \ + driver_data: (unsigned long) name } + +static struct pci_device_id hfcpci_ids[] __devinitdata = { + ID(CCD, CCD_2BD0, "CCD/Billion/Asuscom 2BD0"), + ID(CCD, CCD_B000, "Billion B000"), + ID(CCD, CCD_B006, "Billion B006"), + ID(CCD, CCD_B007, "Billion B007"), + ID(CCD, CCD_B008, "Billion B008"), + ID(CCD, CCD_B009, "Billion B009"), + ID(CCD, CCD_B00A, "Billion B00A"), + ID(CCD, CCD_B00B, "Billion B00B"), + ID(CCD, CCD_B00C, "Billion B00C"), + ID(CCD, CCD_B100, "Seyeon"), + ID(ABOCOM, ABOCOM_2BD1, "Abocom/Magitek"), + ID(ASUSTEK, ASUSTEK_0675, "Asuscom/Askey"), + ID(BERKOM, BERKOM_T_CONCEPT, "German Telekom T-Concept"), + ID(BERKOM, BERKOM_A1T, "German Telekom A1T"), + ID(ANIGMA, ANIGMA_MC145575, "Motorola MC145575"), + ID(ZOLTRIX, ZOLTRIX_2BD0, "Zoltrix 2BD0"), + ID(DIGI, DIGI_DF_M_IOM2_E, "Digi DataFire Micro V IOM2 (Europe)"), + ID(DIGI, DIGI_DF_M_E, "Digi DataFire Micro V (Europe)"), + ID(DIGI, DIGI_DF_M_IOM2_A, "Digi DataFire Micro V IOM2 (America)"), + ID(DIGI, DIGI_DF_M_A, "Digi DataFire Micro V (America)"), + { } +}; +MODULE_DEVICE_TABLE(pci, hfcpci_ids); + +#undef ID + +static int protocol = 2; /* EURO-ISDN Default */ +MODULE_PARM(protocol, "i"); + +// ---------------------------------------------------------------------- +// + +#define DBG_WARN 0x0001 +#define DBG_INFO 0x0002 +#define DBG_IRQ 0x0010 +#define DBG_L1M 0x0020 +#define DBG_PR 0x0040 +#define DBG_D_XMIT 0x0100 +#define DBG_D_RECV 0x0200 +#define DBG_B_XMIT 0x1000 +#define DBG_B_RECV 0x2000 + +/* memory window base address offset (in config space) */ + +#define HFCPCI_MWBA 0x80 + +/* GCI/IOM bus monitor registers */ + +#define HCFPCI_C_I 0x08 +#define HFCPCI_TRxR 0x0C +#define HFCPCI_MON1_D 0x28 +#define HFCPCI_MON2_D 0x2C + + +/* GCI/IOM bus timeslot registers */ + +#define HFCPCI_B1_SSL 0x80 +#define HFCPCI_B2_SSL 0x84 +#define HFCPCI_AUX1_SSL 0x88 +#define HFCPCI_AUX2_SSL 0x8C +#define HFCPCI_B1_RSL 0x90 +#define HFCPCI_B2_RSL 0x94 +#define HFCPCI_AUX1_RSL 0x98 +#define HFCPCI_AUX2_RSL 0x9C + +/* GCI/IOM bus data registers */ + +#define HFCPCI_B1_D 0xA0 +#define HFCPCI_B2_D 0xA4 +#define HFCPCI_AUX1_D 0xA8 +#define HFCPCI_AUX2_D 0xAC + +/* GCI/IOM bus configuration registers */ + +#define HFCPCI_MST_EMOD 0xB4 +#define HFCPCI_MST_MODE 0xB8 +#define HFCPCI_CONNECT 0xBC + + +/* Interrupt and status registers */ + +#define HFCPCI_FIFO_EN 0x44 +#define HFCPCI_TRM 0x48 +#define HFCPCI_B_MODE 0x4C +#define HFCPCI_CHIP_ID 0x58 +#define HFCPCI_CIRM 0x60 +#define HFCPCI_CTMT 0x64 +#define HFCPCI_INT_M1 0x68 +#define HFCPCI_INT_M2 0x6C +#define HFCPCI_INT_S1 0x78 +#define HFCPCI_INT_S2 0x7C +#define HFCPCI_STATUS 0x70 + +/* S/T section registers */ + +#define HFCPCI_STATES 0xC0 +#define HFCPCI_SCTRL 0xC4 +#define HFCPCI_SCTRL_E 0xC8 +#define HFCPCI_SCTRL_R 0xCC +#define HFCPCI_SQ 0xD0 +#define HFCPCI_CLKDEL 0xDC +#define HFCPCI_B1_REC 0xF0 +#define HFCPCI_B1_SEND 0xF0 +#define HFCPCI_B2_REC 0xF4 +#define HFCPCI_B2_SEND 0xF4 +#define HFCPCI_D_REC 0xF8 +#define HFCPCI_D_SEND 0xF8 +#define HFCPCI_E_REC 0xFC + + +/* bits in status register (READ) */ +#define HFCPCI_PCI_PROC 0x02 +#define HFCPCI_NBUSY 0x04 +#define HFCPCI_TIMER_ELAP 0x10 +#define HFCPCI_STATINT 0x20 +#define HFCPCI_FRAMEINT 0x40 +#define HFCPCI_ANYINT 0x80 + +/* bits in CTMT (Write) */ +#define HFCPCI_CLTIMER 0x80 +#define HFCPCI_TIM3_125 0x04 +#define HFCPCI_TIM25 0x10 +#define HFCPCI_TIM50 0x14 +#define HFCPCI_TIM400 0x18 +#define HFCPCI_TIM800 0x1C +#define HFCPCI_AUTO_TIMER 0x20 +#define HFCPCI_TRANSB2 0x02 +#define HFCPCI_TRANSB1 0x01 + +/* bits in CIRM (Write) */ +#define HFCPCI_AUX_MSK 0x07 +#define HFCPCI_RESET 0x08 +#define HFCPCI_B1_REV 0x40 +#define HFCPCI_B2_REV 0x80 + +/* bits in INT_M1 and INT_S1 */ +#define HFCPCI_INTS_B1TRANS 0x01 +#define HFCPCI_INTS_B2TRANS 0x02 +#define HFCPCI_INTS_DTRANS 0x04 +#define HFCPCI_INTS_B1REC 0x08 +#define HFCPCI_INTS_B2REC 0x10 +#define HFCPCI_INTS_DREC 0x20 +#define HFCPCI_INTS_L1STATE 0x40 +#define HFCPCI_INTS_TIMER 0x80 + +/* bits in INT_M2 */ +#define HFCPCI_PROC_TRANS 0x01 +#define HFCPCI_GCI_I_CHG 0x02 +#define HFCPCI_GCI_MON_REC 0x04 +#define HFCPCI_IRQ_ENABLE 0x08 +#define HFCPCI_PMESEL 0x80 + +/* bits in STATES */ +#define HFCPCI_STATE_MSK 0x0F +#define HFCPCI_LOAD_STATE 0x10 +#define HFCPCI_ACTIVATE 0x20 +#define HFCPCI_DO_ACTION 0x40 +#define HFCPCI_NT_G2_G3 0x80 + +/* bits in HFCD_MST_MODE */ +#define HFCPCI_MASTER 0x01 +#define HFCPCI_SLAVE 0x00 +/* remaining bits are for codecs control */ + +/* bits in HFCD_SCTRL */ +#define SCTRL_B1_ENA 0x01 +#define SCTRL_B2_ENA 0x02 +#define SCTRL_MODE_TE 0x00 +#define SCTRL_MODE_NT 0x04 +#define SCTRL_LOW_PRIO 0x08 +#define SCTRL_SQ_ENA 0x10 +#define SCTRL_TEST 0x20 +#define SCTRL_NONE_CAP 0x40 +#define SCTRL_PWR_DOWN 0x80 + +/* bits in SCTRL_E */ +#define HFCPCI_AUTO_AWAKE 0x01 +#define HFCPCI_DBIT_1 0x04 +#define HFCPCI_IGNORE_COL 0x08 +#define HFCPCI_CHG_B1_B2 0x80 + +/* bits in FIFO_EN register */ +#define HFCPCI_FIFOEN_B1 0x03 +#define HFCPCI_FIFOEN_B2 0x0C +#define HFCPCI_FIFOEN_DTX 0x10 +#define HFCPCI_FIFOEN_DRX 0x20 +#define HFCPCI_FIFOEN_B1TX 0x01 +#define HFCPCI_FIFOEN_B1RX 0x02 +#define HFCPCI_FIFOEN_B2TX 0x04 +#define HFCPCI_FIFOEN_B2RX 0x08 + +/* + * thresholds for transparent B-channel mode + * change mask and threshold simultaneously + */ +#define HFCPCI_BTRANS_THRESHOLD 128 +#define HFCPCI_BTRANS_THRESMASK 0x00 + +#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ +#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ + +#define MAX_D_FRAMES 0x10 +#define MAX_B_FRAMES 0x20 +#define B_FIFO_START 0x0200 +#define B_FIFO_END 0x2000 +#define B_FIFO_SIZE (B_FIFO_END - B_FIFO_START) +#define D_FIFO_START 0x0000 +#define D_FIFO_END 0x0200 +#define D_FIFO_SIZE (D_FIFO_END - D_FIFO_START) + +// ---------------------------------------------------------------------- +// push messages to the upper layers + +static inline void D_L1L2(struct hfcpci_adapter *adapter, int pr, void *arg) +{ + struct hisax_if *ifc = (struct hisax_if *) &adapter->d_if; + + DBG(DBG_PR, "pr %#x", pr); + ifc->l1l2(ifc, pr, arg); +} + +static inline void B_L1L2(struct hfcpci_bcs *bcs, int pr, void *arg) +{ + struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if; + + DBG(DBG_PR, "pr %#x", pr); + ifc->l1l2(ifc, pr, arg); +} + +// ---------------------------------------------------------------------- +// MMIO + +static inline void +hfcpci_writeb(struct hfcpci_adapter *adapter, u8 b, unsigned char offset) +{ + writeb(b, adapter->mmio + offset); +} + +static inline u8 +hfcpci_readb(struct hfcpci_adapter *adapter, unsigned char offset) +{ + return readb(adapter->mmio + offset); +} + +// ---------------------------------------------------------------------- +// magic to define the various F/Z counter accesses + +#define DECL_B_F(r, f) \ +static inline u8 \ +get_b_##r##_##f (struct hfcpci_bcs *bcs) \ +{ \ + u16 off = bcs->channel ? OFF_B2_##r##_##f : OFF_B1_##r##_##f; \ + \ + return *(bcs->adapter->fifo + off); \ +} \ + \ +static inline void \ +set_b_##r##_##f (struct hfcpci_bcs *bcs, u8 f) \ +{ \ + u16 off = bcs->channel ? OFF_B2_##r##_##f : OFF_B1_##r##_##f; \ + \ + *(bcs->adapter->fifo + off) = f; \ +} + +#define OFF_B1_rx_f1 0x6080 +#define OFF_B2_rx_f1 0x6180 +#define OFF_B1_rx_f2 0x6081 +#define OFF_B2_rx_f2 0x6181 + +#define OFF_B1_tx_f1 0x2080 +#define OFF_B2_tx_f1 0x2180 +#define OFF_B1_tx_f2 0x2081 +#define OFF_B2_tx_f2 0x2181 + +DECL_B_F(rx, f1) +DECL_B_F(rx, f2) +DECL_B_F(tx, f1) +DECL_B_F(tx, f2) + +#undef DECL_B_F + +#define DECL_B_Z(r, z) \ +static inline u16 \ +get_b_##r##_##z (struct hfcpci_bcs *bcs, u8 f) \ +{ \ + u16 off = bcs->channel ? OFF_B2_##r##_##z : OFF_B1_##r##_##z; \ + \ + return le16_to_cpu(*((u16 *) (bcs->adapter->fifo + off + f * 4))); \ +} \ + \ +static inline void \ +set_b_##r##_##z(struct hfcpci_bcs *bcs, u8 f, u16 z) \ +{ \ + u16 off = bcs->channel ? OFF_B2_##r##_##z : OFF_B1_##r##_##z; \ + \ + *((u16 *) (bcs->adapter->fifo + off + f * 4)) = cpu_to_le16(z); \ +} + +#define OFF_B1_rx_z1 0x6000 +#define OFF_B2_rx_z1 0x6100 +#define OFF_B1_rx_z2 0x6002 +#define OFF_B2_rx_z2 0x6102 + +#define OFF_B1_tx_z1 0x2000 +#define OFF_B2_tx_z1 0x2100 +#define OFF_B1_tx_z2 0x2002 +#define OFF_B2_tx_z2 0x2102 + +DECL_B_Z(rx, z1) +DECL_B_Z(rx, z2) +DECL_B_Z(tx, z1) +DECL_B_Z(tx, z2) + +#undef DECL_B_Z + +#define DECL_D_F(r, f) \ +static inline u8 \ +get_d_##r##_##f (struct hfcpci_adapter *adapter) \ +{ \ + u16 off = OFF_D_##r##_##f; \ + \ + return *(adapter->fifo + off) & 0xf; \ +} \ + \ +static inline void \ +set_d_##r##_##f (struct hfcpci_adapter *adapter, u8 f) \ +{ \ + u16 off = OFF_D_##r##_##f; \ + \ + *(adapter->fifo + off) = f | 0x10; \ +} + +#define OFF_D_rx_f1 0x60a0 +#define OFF_D_rx_f2 0x60a1 + +#define OFF_D_tx_f1 0x20a0 +#define OFF_D_tx_f2 0x20a1 + +DECL_D_F(rx, f1) +DECL_D_F(rx, f2) +DECL_D_F(tx, f1) +DECL_D_F(tx, f2) + +#undef DECL_D_F + +#define DECL_D_Z(r, z) \ +static inline u16 \ +get_d_##r##_##z (struct hfcpci_adapter *adapter, u8 f) \ +{ \ + u16 off = OFF_D_##r##_##z; \ + \ + return le16_to_cpu(*((u16 *) (adapter->fifo + off + (f | 0x10) * 4)));\ +} \ + \ +static inline void \ +set_d_##r##_##z(struct hfcpci_adapter *adapter, u8 f, u16 z) \ +{ \ + u16 off = OFF_D_##r##_##z; \ + \ + *((u16 *) (adapter->fifo + off + (f | 0x10) * 4)) = cpu_to_le16(z); \ +} + +#define OFF_D_rx_z1 0x6080 +#define OFF_D_rx_z2 0x6082 + +#define OFF_D_tx_z1 0x2080 +#define OFF_D_tx_z2 0x2082 + +DECL_D_Z(rx, z1) +DECL_D_Z(rx, z2) +DECL_D_Z(tx, z1) +DECL_D_Z(tx, z2) + +#undef DECL_B_Z + +// ---------------------------------------------------------------------- +// fill b / d fifos + +static inline void +hfcpci_fill_d_fifo(struct hfcpci_adapter *adapter) +{ + u8 f1, f2; + u16 z1, z2; + int cnt, fcnt; + char *fifo_adr = adapter->fifo; + struct sk_buff *tx_skb = adapter->tx_skb; + + f1 = get_d_tx_f1(adapter); + f2 = get_d_tx_f2(adapter); + DBG(DBG_D_XMIT, "f1 %#x f2 %#x", f1, f2); + + fcnt = f1 - f2; + if (fcnt < 0) + fcnt += MAX_D_FRAMES; + + if (fcnt) { + printk("BUG\n"); + return; + } + + z1 = get_d_tx_z1(adapter, f1); + z2 = get_d_tx_z2(adapter, f1); //XXX + DBG(DBG_D_XMIT, "z1 %#x z2 %#x", z1, z2); + + cnt = z2 - z1; + if (cnt <= 0) + cnt += D_FIFO_SIZE; + + if (tx_skb->len > cnt) { + printk("BUG\n"); + return; + } + + cnt = tx_skb->len; + if (z1 + cnt <= D_FIFO_END) { + memcpy(fifo_adr + z1, tx_skb->data, cnt); + } else { + memcpy(fifo_adr + z1, tx_skb->data, D_FIFO_END - z1); + memcpy(fifo_adr + D_FIFO_START, + tx_skb->data + (D_FIFO_END - z1), + cnt - (D_FIFO_END - z1)); + } + z1 += cnt; + if (z1 >= D_FIFO_END) + z1 -= D_FIFO_SIZE; + + f1 = (f1 + 1) & (MAX_D_FRAMES - 1); + mb(); + set_d_tx_z1(adapter, f1, z1); + mb(); + set_d_tx_f1(adapter, f1); +} + +static inline void +hfcpci_fill_b_fifo_hdlc(struct hfcpci_bcs *bcs) +{ + u8 f1, f2; + u16 z1, z2; + int cnt, fcnt; + char *fifo_adr = bcs->adapter->fifo + (bcs->channel ? 0x2000 : 0x0000); + struct sk_buff *tx_skb = bcs->tx_skb; + + f1 = get_b_tx_f1(bcs); + f2 = get_b_tx_f2(bcs); + DBG(DBG_B_XMIT, "f1 %#x f2 %#x", f1, f2); + + fcnt = f1 - f2; + if (fcnt < 0) + fcnt += MAX_B_FRAMES; + + if (fcnt) { + printk("BUG\n"); + return; + } + + z1 = get_b_tx_z1(bcs, f1); + z2 = get_b_tx_z2(bcs, f1); //XXX + DBG(DBG_B_XMIT, "z1 %#x z2 %#x", z1, z2); + + cnt = z2 - z1; + if (cnt <= 0) + cnt += B_FIFO_SIZE; + + if (tx_skb->len > cnt) { + printk("BUG\n"); + return; + } + + cnt = tx_skb->len; + if (z1 + cnt <= B_FIFO_END) { + memcpy(fifo_adr + z1, tx_skb->data, cnt); + } else { + memcpy(fifo_adr + z1, tx_skb->data, B_FIFO_END - z1); + memcpy(fifo_adr + B_FIFO_START, + tx_skb->data + (B_FIFO_END - z1), + cnt - (B_FIFO_END - z1)); + } + z1 += cnt; + if (z1 >= B_FIFO_END) + z1 -= B_FIFO_SIZE; + + f1 = (f1 + 1) & (MAX_B_FRAMES - 1); + mb(); + set_b_tx_z1(bcs, f1, z1); + mb(); + set_b_tx_f1(bcs, f1); +} + +static inline void +hfcpci_fill_b_fifo_trans(struct hfcpci_bcs *bcs) +{ + int cnt; + char *fifo_adr = bcs->adapter->fifo + (bcs->channel ? 0x2000 : 0x0000); + struct sk_buff *tx_skb = bcs->tx_skb; + u8 f1, f2; + u16 z1, z2; + + f1 = get_b_tx_f1(bcs); + f2 = get_b_tx_f2(bcs); + + if (f1 != f2) + BUG(); + + z1 = get_b_tx_z1(bcs, f1); + z2 = get_b_tx_z2(bcs, f1); + + cnt = z2 - z1; + if (cnt <= 0) + cnt += B_FIFO_SIZE; + + if (tx_skb->len > cnt) + BUG(); + + if (z1 + cnt <= B_FIFO_END) { + memcpy(fifo_adr + z1, tx_skb->data, cnt); + } else { + memcpy(fifo_adr + z1, tx_skb->data, B_FIFO_END - z1); + memcpy(fifo_adr + B_FIFO_START, + tx_skb->data + (B_FIFO_END - z1), + cnt - (B_FIFO_END - z1)); + } + z1 += cnt; + if (z1 >= B_FIFO_END) + z1 -= B_FIFO_SIZE; + + mb(); + set_b_tx_z1(bcs, f1, z1); +} + +static inline void +hfcpci_fill_b_fifo(struct hfcpci_bcs *bcs) +{ + if (!bcs->tx_skb) { + DBG(DBG_WARN, "?"); + return; + } + + switch (bcs->mode) { + case L1_MODE_TRANS: + hfcpci_fill_b_fifo_trans(bcs); + break; + case L1_MODE_HDLC: + hfcpci_fill_b_fifo_hdlc(bcs); + break; + default: + DBG(DBG_WARN, "?"); + } +} + +static void hfcpci_clear_b_rx_fifo(struct hfcpci_bcs *bcs); +static void hfcpci_clear_b_tx_fifo(struct hfcpci_bcs *bcs); + +static void +hfcpci_b_mode(struct hfcpci_bcs *bcs, int mode) +{ + struct hfcpci_adapter *adapter = bcs->adapter; + + DBG(DBG_B_XMIT, "B%d mode %d --> %d", + bcs->channel + 1, bcs->mode, mode); + + if (bcs->mode == mode) + return; + + switch (mode) { + case L1_MODE_NULL: + if (bcs->channel == 0) { + adapter->sctrl &= ~SCTRL_B1_ENA; + adapter->sctrl_r &= ~SCTRL_B1_ENA; + adapter->fifo_en &= ~HFCPCI_FIFOEN_B1; + adapter->int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); + } else { + adapter->sctrl &= ~SCTRL_B2_ENA; + adapter->sctrl_r &= ~SCTRL_B2_ENA; + adapter->fifo_en &= ~HFCPCI_FIFOEN_B2; + adapter->int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); + } + break; + case L1_MODE_TRANS: + case L1_MODE_HDLC: + hfcpci_clear_b_rx_fifo(bcs); + hfcpci_clear_b_tx_fifo(bcs); + if (bcs->channel == 0) { + adapter->sctrl |= SCTRL_B1_ENA; + adapter->sctrl_r |= SCTRL_B1_ENA; + adapter->fifo_en |= HFCPCI_FIFOEN_B1; + adapter->int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); + + if (mode == L1_MODE_TRANS) + adapter->ctmt |= 1; + else + adapter->ctmt &= ~1; + + } else { + adapter->sctrl |= SCTRL_B2_ENA; + adapter->sctrl_r |= SCTRL_B2_ENA; + adapter->fifo_en |= HFCPCI_FIFOEN_B2; + adapter->int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); + + if (mode == L1_MODE_TRANS) + adapter->ctmt |= 2; + else + adapter->ctmt &= ~2; + + } + break; + } + hfcpci_writeb(adapter, adapter->int_m1, HFCPCI_INT_M1); + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + hfcpci_writeb(adapter, adapter->sctrl, HFCPCI_SCTRL); + hfcpci_writeb(adapter, adapter->sctrl_r, HFCPCI_SCTRL_R); + hfcpci_writeb(adapter, adapter->ctmt, HFCPCI_CTMT); + hfcpci_writeb(adapter, adapter->conn, HFCPCI_CONNECT); + + bcs->mode = mode; +} + +// ---------------------------------------------------------------------- +// Layer 1 state machine + +static struct Fsm l1fsm; + +enum { + ST_L1_F0, + ST_L1_F2, + ST_L1_F3, + ST_L1_F4, + ST_L1_F5, + ST_L1_F6, + ST_L1_F7, + ST_L1_F8, +}; + +#define L1_STATE_COUNT (ST_L1_F8+1) + +static char *strL1State[] = +{ + "ST_L1_F0", + "ST_L1_F2", + "ST_L1_F3", + "ST_L1_F4", + "ST_L1_F5", + "ST_L1_F6", + "ST_L1_F7", + "ST_L1_F8", +}; + +enum { + EV_PH_F0, + EV_PH_1, + EV_PH_F2, + EV_PH_F3, + EV_PH_F4, + EV_PH_F5, + EV_PH_F6, + EV_PH_F7, + EV_PH_F8, + EV_PH_ACTIVATE_REQ, + EV_PH_DEACTIVATE_REQ, + EV_TIMER3, +}; + +#define L1_EVENT_COUNT (EV_TIMER3 + 1) + +static char *strL1Event[] = +{ + "EV_PH_F0", + "EV_PH_1", + "EV_PH_F2", + "EV_PH_F3", + "EV_PH_F4", + "EV_PH_F5", + "EV_PH_F6", + "EV_PH_F7", + "EV_PH_F8", + "EV_PH_ACTIVATE_REQ", + "EV_PH_DEACTIVATE_REQ", + "EV_TIMER3", +}; + +static void l1_ignore(struct FsmInst *fi, int event, void *arg) +{ +} + +static void l1_go_f3(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_F3); +} + +static void l1_go_f3_deact_ind(struct FsmInst *fi, int event, void *arg) +{ + struct hfcpci_adapter *adapter = fi->userdata; + + FsmChangeState(fi, ST_L1_F3); + D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL); +} + +static void l1_go_f4(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_F3); +} + +static void l1_go_f5(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_F3); +} + +static void l1_go_f6(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_F6); +} + +static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg) +{ + struct hfcpci_adapter *adapter = fi->userdata; + + FsmChangeState(fi, ST_L1_F6); + D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL); +} + +static void l1_go_f7(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_F7); +} + +static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg) +{ + struct hfcpci_adapter *adapter = fi->userdata; + + FsmChangeState(fi, ST_L1_F7); + D_L1L2(adapter, PH_ACTIVATE | INDICATION, NULL); +} + +static void l1_go_f8(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_L1_F8); +} + +static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg) +{ + struct hfcpci_adapter *adapter = fi->userdata; + + FsmChangeState(fi, ST_L1_F8); + D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL); +} + +static void l1_act_req(struct FsmInst *fi, int event, void *arg) +{ + struct hfcpci_adapter *adapter = fi->userdata; + + hfcpci_writeb(adapter, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION, HFCPCI_STATES); +} + +static struct FsmNode L1FnList[] __initdata = +{ + {ST_L1_F2, EV_PH_F3, l1_go_f3}, + {ST_L1_F2, EV_PH_F6, l1_go_f6}, + {ST_L1_F2, EV_PH_F7, l1_go_f7_act_ind}, + + {ST_L1_F3, EV_PH_F3, l1_ignore}, + {ST_L1_F3, EV_PH_F4, l1_go_f4}, + {ST_L1_F3, EV_PH_F5, l1_go_f5}, + {ST_L1_F3, EV_PH_F6, l1_go_f6}, + {ST_L1_F3, EV_PH_F7, l1_go_f7_act_ind}, + {ST_L1_F3, EV_PH_ACTIVATE_REQ, l1_act_req}, + + {ST_L1_F4, EV_PH_F7, l1_ignore}, + {ST_L1_F4, EV_PH_F3, l1_go_f3}, + {ST_L1_F4, EV_PH_F5, l1_go_f5}, + {ST_L1_F4, EV_PH_F6, l1_go_f6}, + {ST_L1_F4, EV_PH_F7, l1_go_f7}, + + {ST_L1_F5, EV_PH_F7, l1_ignore}, + {ST_L1_F5, EV_PH_F3, l1_go_f3}, + {ST_L1_F5, EV_PH_F6, l1_go_f6}, + {ST_L1_F5, EV_PH_F7, l1_go_f7}, + + {ST_L1_F6, EV_PH_F7, l1_ignore}, + {ST_L1_F6, EV_PH_F3, l1_go_f3}, + {ST_L1_F6, EV_PH_F7, l1_go_f7_act_ind}, + {ST_L1_F6, EV_PH_F8, l1_go_f8}, + + {ST_L1_F7, EV_PH_F7, l1_ignore}, + {ST_L1_F7, EV_PH_F3, l1_go_f3_deact_ind}, + {ST_L1_F7, EV_PH_F6, l1_go_f6_deact_ind}, + {ST_L1_F7, EV_PH_F8, l1_go_f8_deact_ind}, + + {ST_L1_F8, EV_PH_F7, l1_ignore}, + {ST_L1_F8, EV_PH_F3, l1_go_f3}, + {ST_L1_F8, EV_PH_F6, l1_go_f6}, + {ST_L1_F8, EV_PH_F7, l1_go_f7_act_ind}, + +}; + +static void l1m_debug(struct FsmInst *fi, char *fmt, ...) +{ + va_list args; + char buf[256]; + + va_start(args, fmt); + vsprintf(buf, fmt, args); + DBG(DBG_L1M, "%s", buf); + va_end(args); +} + +// ---------------------------------------------------------------------- +// clear FIFOs + +static void +hfcpci_clear_d_rx_fifo(struct hfcpci_adapter *adapter) +{ + u8 fifo_state; + + DBG(DBG_D_RECV, ""); + + fifo_state = adapter->fifo_en & HFCPCI_FIFOEN_DRX; + + if (fifo_state) { // enabled + // XXX locking + adapter->fifo_en &= ~fifo_state; + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + } + + adapter->last_fcnt = 0; + + set_d_rx_z1(adapter, MAX_D_FRAMES - 1, D_FIFO_END - 1); + set_d_rx_z2(adapter, MAX_D_FRAMES - 1, D_FIFO_END - 1); + mb(); + set_d_rx_f1(adapter, MAX_D_FRAMES - 1); + set_d_rx_f2(adapter, MAX_D_FRAMES - 1); + mb(); + + if (fifo_state) { + adapter->fifo_en |= fifo_state; + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + } +} + +static void +hfcpci_clear_b_rx_fifo(struct hfcpci_bcs *bcs) +{ + struct hfcpci_adapter *adapter = bcs->adapter; + int nr = bcs->channel; + u8 fifo_state; + + DBG(DBG_B_RECV, ""); + + fifo_state = adapter->fifo_en & + (nr ? HFCPCI_FIFOEN_B2RX : HFCPCI_FIFOEN_B1RX); + + if (fifo_state) { // enabled + adapter->fifo_en &= ~fifo_state; + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + } + + bcs->last_fcnt = 0; + + set_b_rx_z1(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1); + set_b_rx_z2(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1); + mb(); + set_b_rx_f1(bcs, MAX_B_FRAMES - 1); + set_b_rx_f2(bcs, MAX_B_FRAMES - 1); + mb(); + + if (fifo_state) { + adapter->fifo_en |= fifo_state; + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + } +} + +// XXX clear d_tx_fifo? + +static void +hfcpci_clear_b_tx_fifo(struct hfcpci_bcs *bcs) +{ + struct hfcpci_adapter *adapter = bcs->adapter; + int nr = bcs->channel; + u8 fifo_state; + + fifo_state = adapter->fifo_en & + (nr ? HFCPCI_FIFOEN_B2TX : HFCPCI_FIFOEN_B1TX); + + if (fifo_state) { // enabled + adapter->fifo_en &= ~fifo_state; + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + } + + bcs->last_fcnt = 0; + + set_b_rx_z1(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1); + set_b_rx_z2(bcs, MAX_B_FRAMES - 1, B_FIFO_END - 1); + mb(); + set_b_rx_f1(bcs, MAX_B_FRAMES - 1); + set_b_rx_f2(bcs, MAX_B_FRAMES - 1); + mb(); + + if (fifo_state) { + adapter->fifo_en |= fifo_state; + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + } +} + +// ---------------------------------------------------------------------- +// receive messages from upper layers + +static void +hfcpci_d_l2l1(struct hisax_if *ifc, int pr, void *arg) +{ + struct hfcpci_adapter *adapter = ifc->priv; + struct sk_buff *skb = arg; + + DBG(DBG_PR, "pr %#x", pr); + + switch (pr) { + case PH_ACTIVATE | REQUEST: + FsmEvent(&adapter->l1m, EV_PH_ACTIVATE_REQ, NULL); + break; + case PH_DEACTIVATE | REQUEST: + FsmEvent(&adapter->l1m, EV_PH_DEACTIVATE_REQ, NULL); + break; + case PH_DATA | REQUEST: + DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len); + DBG_SKB(DBG_D_XMIT, skb); + if (adapter->l1m.state != ST_L1_F7) { + DBG(DBG_WARN, "L1 wrong state %d", adapter->l1m.state); + break; + } + if (adapter->tx_skb) + BUG(); + + adapter->tx_skb = skb; + hfcpci_fill_d_fifo(adapter); + break; + } +} + +static void +hfcpci_b_l2l1(struct hisax_if *ifc, int pr, void *arg) +{ + struct hfcpci_bcs *bcs = ifc->priv; + struct sk_buff *skb = arg; + int mode; + + DBG(DBG_PR, "pr %#x", pr); + + switch (pr) { + case PH_DATA | REQUEST: + if (bcs->tx_skb) + BUG(); + + bcs->tx_skb = skb; + DBG_SKB(DBG_B_XMIT, skb); + hfcpci_fill_b_fifo(bcs); + break; + case PH_ACTIVATE | REQUEST: + mode = (int) arg; + DBG(DBG_PR,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode); + hfcpci_b_mode(bcs, mode); + B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL); + break; + case PH_DEACTIVATE | REQUEST: + DBG(DBG_PR,"B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1); + hfcpci_b_mode(bcs, L1_MODE_NULL); + B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL); + break; + } +} + +// ---------------------------------------------------------------------- +// receive IRQ + +static inline void +hfcpci_d_recv_irq(struct hfcpci_adapter *adapter) +{ + struct sk_buff *skb; + char *fifo_adr = adapter->fifo + 0x4000; + char *p; + int cnt, fcnt; + int loop = 5; + u8 f1, f2; + u16 z1, z2; + + while (loop-- > 0) { + f1 = get_d_rx_f1(adapter); + f2 = get_d_rx_f2(adapter); + DBG(DBG_D_RECV, "f1 %#x f2 %#x", f1, f2); + + fcnt = f1 - f2; + if (fcnt < 0) + fcnt += 16; + + if (!fcnt) + return; + + if (fcnt < adapter->last_fcnt) + /* overrun */ + hfcpci_clear_d_rx_fifo(adapter); + // XXX init last_fcnt + + z1 = get_d_rx_z1(adapter, f2); + z2 = get_d_rx_z2(adapter, f2); + DBG(DBG_D_RECV, "z1 %#x z2 %#x", z1, z2); + + cnt = z1 - z2; + if (cnt < 0) + cnt += D_FIFO_SIZE; + cnt++; + + if (cnt < 4) { + DBG(DBG_WARN, "frame too short"); + goto next; + } + if (fifo_adr[z1] != 0) { + DBG(DBG_WARN, "CRC error"); + goto next; + } + cnt -= 3; + skb = dev_alloc_skb(cnt); + if (!skb) { + DBG(DBG_WARN, "no mem"); + goto next; + } + p = skb_put(skb, cnt); + if (z2 + cnt <= D_FIFO_END) { + memcpy(p, fifo_adr + z2, cnt); + } else { + memcpy(p, fifo_adr + z2, D_FIFO_END - z2); + memcpy(p + (D_FIFO_END - z2), fifo_adr + D_FIFO_START, + cnt - (D_FIFO_END - z2)); + } + + DBG_SKB(DBG_D_RECV, skb); + D_L1L2(adapter, PH_DATA | INDICATION, skb); + + next: + if (++z1 >= D_FIFO_END) + z1 -= D_FIFO_START; + + f2 = (f2 + 1) & (MAX_D_FRAMES - 1); + mb(); + set_d_rx_z2(adapter, f2, z1); + mb(); + set_d_rx_f2(adapter, f2); + + adapter->last_fcnt = fcnt - 1; + } +} + +static inline void +hfcpci_b_recv_hdlc_irq(struct hfcpci_adapter *adapter, int nr) +{ + struct hfcpci_bcs *bcs = &adapter->bcs[nr]; + struct sk_buff *skb; + char *fifo_adr = adapter->fifo + (nr ? 0x6000 : 0x4000); + char *p; + int cnt, fcnt; + int loop = 5; + u8 f1, f2; + u16 z1, z2; + + while (loop-- > 0) { + f1 = get_b_rx_f1(bcs); + f2 = get_b_rx_f2(bcs); + DBG(DBG_B_RECV, "f1 %d f2 %d", f1, f2); + + fcnt = f1 - f2; + if (fcnt < 0) + fcnt += 32; + + if (!fcnt) + return; + + if (fcnt < bcs->last_fcnt) + /* overrun */ + hfcpci_clear_b_rx_fifo(bcs); + // XXX init last_fcnt + + z1 = get_b_rx_z1(bcs, f2); + z2 = get_b_rx_z2(bcs, f2); + DBG(DBG_B_RECV, "z1 %d z2 %d", z1, z2); + + cnt = z1 - z2; + if (cnt < 0) + cnt += B_FIFO_SIZE; + cnt++; + + if (cnt < 4) { + DBG(DBG_WARN, "frame too short"); + goto next; + } + if (fifo_adr[z1] != 0) { + DBG(DBG_WARN, "CRC error"); + goto next; + } + cnt -= 3; + skb = dev_alloc_skb(cnt); + if (!skb) { + DBG(DBG_WARN, "no mem"); + goto next; + } + p = skb_put(skb, cnt); + if (z2 + cnt <= B_FIFO_END) { + memcpy(p, fifo_adr + z2, cnt); + } else { + memcpy(p, fifo_adr + z2, B_FIFO_END - z2); + memcpy(p + (B_FIFO_END - z2), fifo_adr + B_FIFO_START, + cnt - (B_FIFO_END - z2)); + } + + DBG_SKB(DBG_B_RECV, skb); + B_L1L2(bcs, PH_DATA | INDICATION, skb); + + next: + if (++z1 >= B_FIFO_END) + z1 -= B_FIFO_SIZE; + + f2 = (f2 + 1) & (MAX_B_FRAMES - 1); + mb(); + set_b_rx_z2(bcs, f2, z1); + mb(); + set_b_rx_f2(bcs, f2); + + bcs->last_fcnt = fcnt - 1; + } +} + +static inline void +hfcpci_b_recv_trans_irq(struct hfcpci_adapter *adapter, int nr) +{ + struct hfcpci_bcs *bcs = &adapter->bcs[nr]; + struct sk_buff *skb; + char *fifo_adr = adapter->fifo + (nr ? 0x6000 : 0x4000); + char *p; + int cnt; + int loop = 5; + u8 f1, f2; + u16 z1, z2; + + f1 = get_b_rx_f1(bcs); + f2 = get_b_rx_f2(bcs); + + if (f1 != f2) + BUG(); + + while (loop-- > 0) { + z1 = get_b_rx_z1(bcs, f2); + z2 = get_b_rx_z2(bcs, f2); + + cnt = z1 - z2; + if (!cnt) + /* no data available */ + return; + + if (cnt < 0) + cnt += B_FIFO_SIZE; + + if (cnt > HFCPCI_BTRANS_THRESHOLD) + cnt = HFCPCI_BTRANS_THRESHOLD; + + skb = dev_alloc_skb(cnt); + if (!skb) { + DBG(DBG_WARN, "no mem"); + goto next; + } + + p = skb_put(skb, cnt); + if (z2 + cnt <= 0x2000) { + memcpy(p, fifo_adr + z2, cnt); + } else { + memcpy(p, fifo_adr + z2, 0x2000 - z2); + p += 0x2000 - z2; + memcpy(p, fifo_adr + 0x200, cnt - (0x2000 - z2)); + } + + DBG_SKB(DBG_B_RECV, skb); + B_L1L2(bcs, PH_DATA | INDICATION, skb); + + next: + z2 += cnt; + if (z2 >= 0x2000) + z2 -= B_FIFO_SIZE; + + mb(); + set_b_rx_z2(bcs, f2, z2); + // XXX always receive buffers of a given size + } +} + +static inline void +hfcpci_b_recv_irq(struct hfcpci_adapter *adapter, int nr) +{ + DBG(DBG_B_RECV, ""); + + switch (adapter->bcs[nr].mode) { + case L1_MODE_NULL: + DBG(DBG_WARN, "?"); + break; + + case L1_MODE_HDLC: + hfcpci_b_recv_hdlc_irq(adapter, nr); + break; + + case L1_MODE_TRANS: + hfcpci_b_recv_trans_irq(adapter, nr); + break; + } +} + +// ---------------------------------------------------------------------- +// transmit IRQ + +// XXX make xmit FIFO deeper than 1 + +static inline void +hfcpci_d_xmit_irq(struct hfcpci_adapter *adapter) +{ + struct sk_buff *skb; + + DBG(DBG_D_XMIT, ""); + + skb = adapter->tx_skb; + if (!skb) { + DBG(DBG_WARN, "?"); + return; + } + + adapter->tx_skb = NULL; + D_L1L2(adapter, PH_DATA | CONFIRM, (void *) skb->truesize); + dev_kfree_skb_irq(skb); +} + +static inline void +hfcpci_b_xmit_irq(struct hfcpci_adapter *adapter, int nr) +{ + struct hfcpci_bcs *bcs = &adapter->bcs[nr]; + struct sk_buff *skb; + + DBG(DBG_B_XMIT, ""); + + skb = bcs->tx_skb; + if (!skb) { + DBG(DBG_WARN, "?"); + return; + } + + bcs->tx_skb = NULL; + B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize); + dev_kfree_skb_irq(skb); +} + +// ---------------------------------------------------------------------- +// Layer 1 state change IRQ + +static inline void +hfcpci_state_irq(struct hfcpci_adapter *adapter) +{ + u8 val; + + val = hfcpci_readb(adapter, HFCPCI_STATES); + DBG(DBG_L1M, "STATES %#x", val); + FsmEvent(&adapter->l1m, val & 0xf, NULL); +} + +// ---------------------------------------------------------------------- +// Timer IRQ + +static inline void +hfcpci_timer_irq(struct hfcpci_adapter *adapter) +{ + hfcpci_writeb(adapter, adapter->ctmt | HFCPCI_CLTIMER, HFCPCI_CTMT); +} + +// ---------------------------------------------------------------------- +// IRQ handler + +static void +hfcpci_irq(int intno, void *dev, struct pt_regs *regs) +{ + struct hfcpci_adapter *adapter = dev; + int loop = 15; + u8 val, stat; + + if (!(adapter->int_m2 & 0x08)) + return; /* not initialised */ // XX + + stat = hfcpci_readb(adapter, HFCPCI_STATUS); + if (!(stat & HFCPCI_ANYINT)) + return; + + spin_lock(&adapter->hw_lock); + while (loop-- > 0) { + val = hfcpci_readb(adapter, HFCPCI_INT_S1); + DBG(DBG_IRQ, "stat %02x s1 %02x", stat, val); + val &= adapter->int_m1; + + if (!val) + break; + + if (val & 0x08) + hfcpci_b_recv_irq(adapter, 0); + + if (val & 0x10) + hfcpci_b_recv_irq(adapter, 1); + + if (val & 0x01) + hfcpci_b_xmit_irq(adapter, 0); + + if (val & 0x02) + hfcpci_b_xmit_irq(adapter, 1); + + if (val & 0x20) + hfcpci_d_recv_irq(adapter); + + if (val & 0x04) + hfcpci_d_xmit_irq(adapter); + + if (val & 0x40) + hfcpci_state_irq(adapter); + + if (val & 0x80) + hfcpci_timer_irq(adapter); + } + spin_unlock(&adapter->hw_lock); +} + +// ---------------------------------------------------------------------- +// reset hardware + +static void +hfcpci_reset(struct hfcpci_adapter *adapter) +{ + /* disable all interrupts */ + adapter->int_m1 = 0; + adapter->int_m2 = 0; + hfcpci_writeb(adapter, adapter->int_m1, HFCPCI_INT_M1); + hfcpci_writeb(adapter, adapter->int_m2, HFCPCI_INT_M2); + + /* reset */ + hfcpci_writeb(adapter, HFCPCI_RESET, HFCPCI_CIRM); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((30 * HZ) / 1000); + hfcpci_writeb(adapter, 0, HFCPCI_CIRM); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((20 * HZ) / 1000); + if (hfcpci_readb(adapter, HFCPCI_STATUS) & 2) // XX + printk(KERN_WARNING "HFC-PCI init bit busy\n"); +} + +// ---------------------------------------------------------------------- +// init hardware + +static void +hfcpci_hw_init(struct hfcpci_adapter *adapter) +{ + adapter->fifo_en = 0x30; /* only D fifos enabled */ // XX + hfcpci_writeb(adapter, adapter->fifo_en, HFCPCI_FIFO_EN); + + /* no echo connect , threshold */ + adapter->trm = HFCPCI_BTRANS_THRESMASK; + hfcpci_writeb(adapter, adapter->trm, HFCPCI_TRM); + + /* ST-Bit delay for TE-Mode */ + hfcpci_writeb(adapter, CLKDEL_TE, HFCPCI_CLKDEL); + + /* S/T Auto awake */ + adapter->sctrl_e = HFCPCI_AUTO_AWAKE; + hfcpci_writeb(adapter, adapter->sctrl_e, HFCPCI_SCTRL_E); + + /* no exchange */ + adapter->bswapped = 0; + /* we are in TE mode */ + adapter->nt_mode = 0; + + adapter->ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER; + hfcpci_writeb(adapter, adapter->ctmt, HFCPCI_CTMT); + + adapter->int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | + HFCPCI_INTS_L1STATE; + hfcpci_writeb(adapter, adapter->int_m1, HFCPCI_INT_M1); + + /* clear already pending ints */ + hfcpci_readb(adapter, HFCPCI_INT_S1); + + adapter->l1m.state = 2; + hfcpci_writeb(adapter, HFCPCI_LOAD_STATE | 2, HFCPCI_STATES); // XX /* HFC ST 2 */ + udelay(10); + hfcpci_writeb(adapter, 2, HFCPCI_STATES); /* HFC ST 2 */ + + /* HFC Master Mode */ + adapter->mst_m = HFCPCI_MASTER; + hfcpci_writeb(adapter, adapter->mst_m, HFCPCI_MST_MODE); + + /* set tx_lo mode, error in datasheet ! */ + adapter->sctrl = 0x40; + hfcpci_writeb(adapter, adapter->sctrl, HFCPCI_SCTRL); + + adapter->sctrl_r = 0; + hfcpci_writeb(adapter, adapter->sctrl_r, HFCPCI_SCTRL_R); + + // XXX + /* Init GCI/IOM2 in master mode */ + /* Slots 0 and 1 are set for B-chan 1 and 2 */ + /* D- and monitor/CI channel are not enabled */ + /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */ + /* STIO2 is used as data input, B1+B2 from IOM->ST */ + /* ST B-channel send disabled -> continous 1s */ + /* The IOM slots are always enabled */ + adapter->conn = 0; /* set data flow directions */ + hfcpci_writeb(adapter, adapter->conn, HFCPCI_CONNECT); + hfcpci_writeb(adapter, 0x80, HFCPCI_B1_SSL); /* B1-Slot 0 STIO1 out enabled */ + hfcpci_writeb(adapter, 0x81, HFCPCI_B2_SSL); /* B2-Slot 1 STIO1 out enabled */ + hfcpci_writeb(adapter, 0x80, HFCPCI_B1_RSL); /* B1-Slot 0 STIO2 in enabled */ + hfcpci_writeb(adapter, 0x81, HFCPCI_B2_RSL); /* B2-Slot 1 STIO2 in enabled */ + + /* Finally enable IRQ output */ + adapter->int_m2 = HFCPCI_IRQ_ENABLE; + hfcpci_writeb(adapter, adapter->int_m2, HFCPCI_INT_M2); + + hfcpci_readb(adapter, HFCPCI_INT_S2); +} + +// ---------------------------------------------------------------------- +// probe / remove + +static struct hfcpci_adapter * __devinit +new_adapter(struct pci_dev *pdev) +{ + struct hfcpci_adapter *adapter; + struct hisax_b_if *b_if[2]; + int i; + + adapter = kmalloc(sizeof(struct hfcpci_adapter), GFP_KERNEL); + if (!adapter) + return NULL; + + memset(adapter, 0, sizeof(struct hfcpci_adapter)); + + SET_MODULE_OWNER(&adapter->d_if); + adapter->d_if.ifc.priv = adapter; + adapter->d_if.ifc.l2l1 = hfcpci_d_l2l1; + + for (i = 0; i < 2; i++) { + adapter->bcs[i].adapter = adapter; + adapter->bcs[i].channel = i; + adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i]; + adapter->bcs[i].b_if.ifc.l2l1 = hfcpci_b_l2l1; + } + + pci_set_drvdata(pdev, adapter); + + for (i = 0; i < 2; i++) + b_if[i] = &adapter->bcs[i].b_if; + + hisax_register(&adapter->d_if, b_if, "hfcpci", protocol); + + return adapter; +} + +static void delete_adapter(struct hfcpci_adapter *adapter) +{ + hisax_unregister(&adapter->d_if); + kfree(adapter); +} + +static int __devinit hfcpci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct hfcpci_adapter *adapter; + int retval; + + DBG(DBG_INFO, ""); + retval = -ENOMEM; + adapter = new_adapter(pdev); + if (!adapter) + goto err; + + retval = pci_enable_device(pdev); + if (retval) + goto err_free; + + adapter->irq = pdev->irq; + retval = request_irq(adapter->irq, hfcpci_irq, SA_SHIRQ, + "hfcpci", adapter); + if (retval) + goto err_free; + + retval = -EBUSY; + if (!request_mem_region(pci_resource_start(pdev, 1), 256, "hfcpci")) + goto err_free_irq; + + adapter->mmio = ioremap(pci_resource_start(pdev, 1), 256); // XX pci_io + if (!adapter->mmio) + goto err_release_region; + + /* Allocate 32K for FIFOs */ + if (pci_set_dma_mask(pdev, 0xffffffff)) + goto err_unmap; + + adapter->fifo = pci_alloc_consistent(pdev, 32768, &adapter->fifo_dma); + if (!adapter->fifo) + goto err_unmap; + + pci_write_config_dword(pdev, HFCPCI_MWBA, (u32) adapter->fifo_dma); + pci_set_master(pdev); + + adapter->l1m.fsm = &l1fsm; + adapter->l1m.state = ST_L1_F0; +#ifdef CONFIG_HISAX_DEBUG + adapter->l1m.debug = 1; +#else + adapter->l1m.debug = 0; +#endif + adapter->l1m.userdata = adapter; + adapter->l1m.printdebug = l1m_debug; + FsmInitTimer(&adapter->l1m, &adapter->timer); + + hfcpci_reset(adapter); + hfcpci_hw_init(adapter); + + printk(KERN_INFO "hisax_hfcpci: found adapter %s at %s\n", + (char *) ent->driver_data, pdev->slot_name); + + return 0; + + err_unmap: + iounmap(adapter->mmio); + err_release_region: + release_mem_region(pci_resource_start(pdev, 1), 256); + err_free_irq: + free_irq(adapter->irq, adapter); + err_free: + delete_adapter(adapter); + err: + return retval; +} + +static void __devexit hfcpci_remove(struct pci_dev *pdev) +{ + struct hfcpci_adapter *adapter = pci_get_drvdata(pdev); + + hfcpci_reset(adapter); + +// del_timer(&cs->hw.hfcpci.timer); XX + + /* disable DMA */ + pci_disable_device(pdev); + pci_write_config_dword(pdev, HFCPCI_MWBA, 0); + pci_free_consistent(pdev, 32768, adapter->fifo, adapter->fifo_dma); + + iounmap(adapter->mmio); + release_mem_region(pci_resource_start(pdev, 1), 256); + free_irq(adapter->irq, adapter); + delete_adapter(adapter); +} + +static struct pci_driver hfcpci_driver = { + name: "hfcpci", + probe: hfcpci_probe, + remove: hfcpci_remove, + id_table: hfcpci_ids, +}; + +static int __init hisax_hfcpci_init(void) +{ + int retval; + + printk(KERN_INFO "hisax_hfcpcipnp: HFC PCI ISDN driver v0.0.1\n"); + + l1fsm.state_count = L1_STATE_COUNT; + l1fsm.event_count = L1_EVENT_COUNT; + l1fsm.strState = strL1State; + l1fsm.strEvent = strL1Event; + retval = FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList)); + if (retval) + goto err; + + retval = pci_module_init(&hfcpci_driver); + if (retval) + goto err_fsm; + + return 0; + + err_fsm: + FsmFree(&l1fsm); + err: + return retval; +} + +static void __exit hisax_hfcpci_exit(void) +{ + FsmFree(&l1fsm); + pci_unregister_driver(&hfcpci_driver); +} + +module_init(hisax_hfcpci_init); +module_exit(hisax_hfcpci_exit); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/hisax/hisax_hfcpci.h linux-2.5/drivers/isdn/hisax/hisax_hfcpci.h --- linux-2.5.5/drivers/isdn/hisax/hisax_hfcpci.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/isdn/hisax/hisax_hfcpci.h Tue Feb 26 21:24:48 2002 @@ -0,0 +1,40 @@ +#include "hisax_if.h" +#include "hisax_isac.h" +#include + +struct hfcpci_bcs { + struct hisax_b_if b_if; + struct hfcpci_adapter *adapter; + int mode; + int channel; + int last_fcnt; + + struct sk_buff *tx_skb; +}; + +struct hfcpci_adapter { + struct hisax_d_if d_if; + spinlock_t hw_lock; + unsigned int irq; + void *mmio; + u8 *fifo; + dma_addr_t fifo_dma; + + struct FsmInst l1m; + struct FsmTimer timer; + struct sk_buff *tx_skb; + int last_fcnt; + + u8 int_m1, int_m2; + u8 fifo_en; + u8 trm; + u8 sctrl, sctrl_r, sctrl_e; + u8 nt_mode; + u8 ctmt; + u8 mst_m; + u8 conn; + u8 bswapped; + + struct hfcpci_bcs bcs[2]; +}; + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/hisax/hisax_isac.c linux-2.5/drivers/isdn/hisax/hisax_isac.c --- linux-2.5.5/drivers/isdn/hisax/hisax_isac.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/isdn/hisax/hisax_isac.c Fri Feb 8 15:46:33 2002 @@ -44,6 +44,7 @@ MODULE_AUTHOR("Kai Germaschewski /Karsten Keil "); MODULE_DESCRIPTION("ISAC/ISAC-SX driver"); +MODULE_LICENSE("GPL"); #define DBG_WARN 0x0001 #define DBG_IRQ 0x0002 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/hisax/md5sums.asc linux-2.5/drivers/isdn/hisax/md5sums.asc --- linux-2.5.5/drivers/isdn/hisax/md5sums.asc Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/isdn/hisax/md5sums.asc Fri Feb 8 03:15:29 2002 @@ -1,3 +1,6 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + # This are valid md5sums for certificated HiSax driver. # The certification is valid only if the md5sums of all files match. # The certification is valid only for ELSA Microlink PCI, @@ -6,17 +9,25 @@ # in the moment. # Read ../../../Documentation/isdn/HiSax.cert for more informations. # -d08b59f56fb9ed1fbd17713342c75081 isac.c -e81e6e96f307e55f8b9777aca2b356d9 isdnl1.c -cfd2527d9fb01885484cba74bfc67121 isdnl2.c -8c6829f11459f9d044b5768803fb646d isdnl3.c -d40f88dff4191d2660240749cbdcb688 tei.c -3bd3bd05ee4cb25ffe046200b569a83a callc.c -d518f52402ebc3f1be84e09af375313c cert.c -c425de1f8be86e84006de63c9bb3cc5f l3dss1.c -4c411e29d4103ba60e9af4e3e1234a99 l3_1tr6.c -68c6cc2784f208e3247a5a555918d014 elsa.c -8d63a85d7222cf7b40e663e543191d8f diva.c -8c8cb4ce621fb84d8e337a696e75b0df sedlbauer.c -ebe5613d535748409407568435b2be97 hfc_pci.c +cd4a9917e1147039d5dfc66440d42054 isac.c +211840e78b56c9d4753be9c85da21a50 isdnl1.c +5ce9b1fff42a02f9c2eb4fb81c701b1f isdnl2.c +6948de0c43513dd23c6706feb5fc2209 isdnl3.c +3730780b69368218d756024165efea79 tei.c +16e72710eb58da01415b877490f5d2ac callc.c +6abc55c77e0f3149ae9334f3257a1a1a cert.c +27bdb2800d4590e00da20eff241edc47 l3dss1.c +df8bb877b854c4302d396b554e4e84ef l3_1tr6.c +3d22d2f2fe9af693eb3b471beecf596d elsa.c +fd6aedade5b5bbd73683a3de878b76d2 diva.c +def8d69efd25186878dc123df73d9319 sedlbauer.c +6c5bd0fdc59f33319823fa5367357983 hfc_pci.c # end of md5sums +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: For info see http://www.gnupg.org + +iD8DBQE8UYO9DiY0VZsg4ukRAqLzAKCKK7rFSNAWpBMtpJZ0kYvF+y+b1wCZAY8u +hf6AL732sGhUsfRpwwdENVU= +=B3yd +-----END PGP SIGNATURE----- diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/hisax/st5481_init.c linux-2.5/drivers/isdn/hisax/st5481_init.c --- linux-2.5.5/drivers/isdn/hisax/st5481_init.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/isdn/hisax/st5481_init.c Thu Dec 13 16:32:35 2001 @@ -178,7 +178,7 @@ static struct usb_driver st5481_usb_driver = { name: "st5481_usb", probe: probe_st5481, - disconnect: disconnect_st5481, + disconnect: __devexit_p(disconnect_st5481), id_table: st5481_ids, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/hisax/st5481_usb.c linux-2.5/drivers/isdn/hisax/st5481_usb.c --- linux-2.5.5/drivers/isdn/hisax/st5481_usb.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/isdn/hisax/st5481_usb.c Tue Feb 26 21:24:48 2002 @@ -416,7 +416,7 @@ for (j = 0; j < 2; j++) { retval = -ENOMEM; - urb[j] = usb_alloc_urb(num_packet, GFP_KERNEL); + urb[j] = usb_alloc_urb(num_packets, GFP_KERNEL); if (!urb[j]) goto err; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/isdn_audio.c linux-2.5/drivers/isdn/isdn_audio.c --- linux-2.5.5/drivers/isdn/isdn_audio.c Wed Feb 20 02:10:52 2002 +++ linux-2.5/drivers/isdn/isdn_audio.c Fri Feb 8 02:58:29 2002 @@ -227,10 +227,8 @@ : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff) : "memory", "ax"); #else - while (n--) { - *buff = table[*buff]; - buff++; - } + while (n--) + *buff = table[*(unsigned char *)buff], buff++; #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/isdn/tpam/tpam_main.c linux-2.5/drivers/isdn/tpam/tpam_main.c --- linux-2.5.5/drivers/isdn/tpam/tpam_main.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/isdn/tpam/tpam_main.c Sat Jan 5 00:51:29 2002 @@ -254,7 +254,7 @@ name: "tpam", id_table: tpam_pci_tbl, probe: tpam_probe, - remove: tpam_remove, + remove: __devexit_p(tpam_remove), }; static int __init tpam_init(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/macintosh/Makefile linux-2.5/drivers/macintosh/Makefile --- linux-2.5.5/drivers/macintosh/Makefile Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/macintosh/Makefile Thu Dec 27 16:32:31 2001 @@ -32,9 +32,11 @@ obj-$(CONFIG_MAC_HID) += mac_hid.o obj-$(CONFIG_INPUT_ADBHID) += adbhid.o obj-$(CONFIG_PPC_RTC) += rtc.o +obj-$(CONFIG_ANSLCD) += ans-lcd.o obj-$(CONFIG_ADB_PMU) += via-pmu.o obj-$(CONFIG_ADB_CUDA) += via-cuda.o +obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o obj-$(CONFIG_ADB) += adb.o obj-$(CONFIG_ADB_KEYBOARD) += mac_keyb.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/macintosh/adb.c linux-2.5/drivers/macintosh/adb.c --- linux-2.5.5/drivers/macintosh/adb.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/macintosh/adb.c Thu Dec 27 16:32:31 2001 @@ -34,6 +34,7 @@ #include #include #include +#include #include #ifdef CONFIG_PPC #include @@ -78,7 +79,7 @@ static int adb_inited = 0; static pid_t adb_probe_task_pid; static int adb_probe_task_flag; -static wait_queue_head_t adb_probe_task_wq; +static struct completion adb_probe_task_comp; static int sleepy_trackpad; int __adb_probe_sync; @@ -318,7 +319,7 @@ if (machine_is_compatible("AAPL,PowerBook1998") || machine_is_compatible("PowerBook1,1")) sleepy_trackpad = 1; - init_waitqueue_head(&adb_probe_task_wq); + init_completion(&adb_probe_task_comp); adbdev_init(); adb_reset_bus(); } @@ -435,7 +436,7 @@ static void adb_probe_wakeup(struct adb_request *req) { - wake_up(&adb_probe_task_wq); + complete(&adb_probe_task_comp); } static struct adb_request adb_sreq; @@ -484,20 +485,11 @@ if ((flags & ADBREQ_SYNC) && (current->pid && adb_probe_task_pid && adb_probe_task_pid == current->pid)) { - DECLARE_WAITQUEUE(wait, current); req->done = adb_probe_wakeup; - add_wait_queue(&adb_probe_task_wq, &wait); rc = adb_controller->send_request(req, 0); if (rc || req->complete) goto bail; - for (;;) { - set_current_state(TASK_UNINTERRUPTIBLE); - if (req->complete) - break; - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&adb_probe_task_wq, &wait); + wait_for_completion(&adb_probe_task_comp); rc = 0; goto bail; } @@ -705,17 +697,16 @@ return ret; req = NULL; + spin_lock_irqsave(&state->lock, flags); add_wait_queue(&state->wait_queue, &wait); current->state = TASK_INTERRUPTIBLE; for (;;) { - spin_lock_irqsave(&state->lock, flags); req = state->completed; if (req != NULL) state->completed = req->next; else if (atomic_read(&state->n_pending) == 0) ret = -EIO; - spin_unlock_irqrestore(&state->lock, flags); if (req != NULL || ret != 0) break; @@ -727,12 +718,15 @@ ret = -ERESTARTSYS; break; } + spin_unlock_irqrestore(&state->lock, flags); schedule(); + spin_lock_irqsave(&state->lock, flags); } current->state = TASK_RUNNING; remove_wait_queue(&state->wait_queue, &wait); - + spin_unlock_irqrestore(&state->lock, flags); + if (ret) return ret; @@ -755,6 +749,8 @@ if (count < 2 || count > sizeof(req->data)) return -EINVAL; + if (adb_controller == NULL) + return -ENXIO; ret = verify_area(VERIFY_READ, buf, count); if (ret) return ret; @@ -774,7 +770,10 @@ goto out; atomic_inc(&state->n_pending); - if (adb_controller == NULL) return -ENXIO; + + /* If a probe is in progress, wait for it to complete */ + while (adb_probe_task_pid != 0 || test_bit(0, &adb_probe_task_flag)) + schedule(); /* Special case for ADB_BUSRESET request, all others are sent to the controller */ @@ -782,6 +781,8 @@ &&(req->data[1] == ADB_BUSRESET)) { ret = do_adb_reset_bus(); atomic_dec(&state->n_pending); + if (ret == 0) + ret = count; goto out; } else { req->reply_expected = ((req->data[1] & 0xc) == 0xc); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/macintosh/adbhid.c linux-2.5/drivers/macintosh/adbhid.c --- linux-2.5.5/drivers/macintosh/adbhid.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/macintosh/adbhid.c Sun Jan 20 17:11:46 2002 @@ -77,6 +77,7 @@ int mouse_kind; unsigned char *keycode; char name[64]; + char phys[32]; }; static struct adbhid *adbhid[16] = { 0 }; @@ -273,26 +274,39 @@ break; case 0x1f: /* Powerbook button device */ { + int down = (data[1] == (data[1] & 0xf)); #ifdef CONFIG_PMAC_BACKLIGHT int backlight = get_backlight_level(); - +#endif /* * XXX: Where is the contrast control for the passive? * -- Cort */ - switch (data[1]) { + switch (data[1] & 0x0f) { case 0x8: /* mute */ + input_report_key(&adbhid[id]->input, KEY_MUTE, + data[1] == (data[1] & 0xf)); break; - case 0x7: /* contrast decrease */ + case 0x7: /* volume decrease */ + input_report_key(&adbhid[id]->input, KEY_VOLUMEDOWN, + data[1] == (data[1] & 0xf)); break; - case 0x6: /* contrast increase */ + case 0x6: /* volume increase */ + input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, + data[1] == (data[1] & 0xf)); + break; + + case 0xb: /* eject */ + input_report_key(&adbhid[id]->input, KEY_EJECTCD, + data[1] == (data[1] & 0xf)); break; +#ifdef CONFIG_PMAC_BACKLIGHT case 0xa: /* brightness decrease */ - if (backlight < 0) + if (!down || backlight < 0) break; if (backlight > BACKLIGHT_OFF) set_backlight_level(backlight-1); @@ -301,15 +315,15 @@ break; case 0x9: /* brightness increase */ - if (backlight < 0) + if (!down || backlight < 0) break; if (backlight < BACKLIGHT_MAX) set_backlight_level(backlight+1); else set_backlight_level(BACKLIGHT_MAX); break; - } #endif /* CONFIG_PMAC_BACKLIGHT */ + } } break; } @@ -420,6 +434,7 @@ return; memset(adbhid[id], 0, sizeof(struct adbhid)); + sprintf(adbhid[id]->phys, "adb%d:%d.%02x/input0", id, default_id, original_handler_id); adbhid[id]->id = default_id; adbhid[id]->original_handler_id = original_handler_id; @@ -427,6 +442,7 @@ adbhid[id]->mouse_kind = mouse_kind; adbhid[id]->input.private = adbhid[id]; adbhid[id]->input.name = adbhid[id]->name; + adbhid[id]->input.phys = adbhid[id]->phys; adbhid[id]->input.idbus = BUS_ADB; adbhid[id]->input.idvendor = 0x0001; adbhid[id]->input.idproduct = (id << 12) | (default_id << 8) | original_handler_id; @@ -439,8 +455,7 @@ return; } - sprintf(adbhid[id]->name, "ADB keyboard on ID %d:%d.%02x", - id, default_id, original_handler_id); + sprintf(adbhid[id]->name, "ADB keyboard"); memcpy(adbhid[id]->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes)); @@ -487,8 +502,7 @@ break; case ADB_MOUSE: - sprintf(adbhid[id]->name, "ADB mouse on ID %d:%d.%02x", - id, default_id, original_handler_id); + sprintf(adbhid[id]->name, "ADB mouse"); adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); adbhid[id]->input.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); @@ -498,12 +512,15 @@ case ADB_MISC: switch (original_handler_id) { case 0x02: /* Adjustable keyboard button device */ - sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons on ID %d:%d.%02x", - id, default_id, original_handler_id); + sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons"); break; case 0x1f: /* Powerbook button device */ - sprintf(adbhid[id]->name, "ADB Powerbook buttons on ID %d:%d.%02x", - id, default_id, original_handler_id); + sprintf(adbhid[id]->name, "ADB Powerbook buttons"); + adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + set_bit(KEY_MUTE, adbhid[id]->input.keybit); + set_bit(KEY_VOLUMEUP, adbhid[id]->input.keybit); + set_bit(KEY_VOLUMEDOWN, adbhid[id]->input.keybit); + set_bit(KEY_EJECTCD, adbhid[id]->input.keybit); break; } if (adbhid[id]->name[0]) @@ -520,8 +537,8 @@ input_register_device(&adbhid[id]->input); - printk(KERN_INFO "input%d: ADB HID on ID %d:%d.%02x\n", - adbhid[id]->input.number, id, default_id, original_handler_id); + printk(KERN_INFO "input: %s on adb%d:%d.%02x\n", + adbhid[id]->name, id, default_id, original_handler_id); if (default_id == ADB_KEYBOARD) { /* HACK WARNING!! This should go away as soon there is an utility @@ -542,16 +559,38 @@ } +static u16 +adbhid_input_reregister(int id, int default_id, int org_handler_id, + int cur_handler_id, int mk) +{ + if (adbhid[id]) { + if (adbhid[id]->input.idproduct != + ((id << 12)|(default_id << 8)|org_handler_id)) { + adbhid_input_unregister(id); + adbhid_input_register(id, default_id, org_handler_id, + cur_handler_id, mk); + } + } else + adbhid_input_register(id, default_id, org_handler_id, + cur_handler_id, mk); + return 1< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ANSLCD_ADDR 0xf301c000 +#define ANSLCD_CTRL_IX 0x00 +#define ANSLCD_DATA_IX 0x10 + +static unsigned long anslcd_short_delay = 80; +static unsigned long anslcd_long_delay = 3280; +static volatile unsigned char* anslcd_ptr; + +#undef DEBUG + +static void __pmac +anslcd_write_byte_ctrl ( unsigned char c ) +{ +#ifdef DEBUG + printk(KERN_DEBUG "LCD: CTRL byte: %02x\n",c); +#endif + out_8(anslcd_ptr + ANSLCD_CTRL_IX, c); + switch(c) { + case 1: + case 2: + case 3: + udelay(anslcd_long_delay); break; + default: udelay(anslcd_short_delay); + } +} + +static void __pmac +anslcd_write_byte_data ( unsigned char c ) +{ + out_8(anslcd_ptr + ANSLCD_DATA_IX, c); + udelay(anslcd_short_delay); +} + +static ssize_t __pmac +anslcd_write( struct file * file, const char * buf, + size_t count, loff_t *ppos ) +{ + const char * p = buf; + int i; + +#ifdef DEBUG + printk(KERN_DEBUG "LCD: write\n"); +#endif + + if ( verify_area(VERIFY_READ, buf, count) ) + return -EFAULT; + for ( i = *ppos; count > 0; ++i, ++p, --count ) + { + char c; + __get_user(c, p); + anslcd_write_byte_data( c ); + } + *ppos = i; + return p - buf; +} + +static int __pmac +anslcd_ioctl( struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg ) +{ + char ch, *temp; + +#ifdef DEBUG + printk(KERN_DEBUG "LCD: ioctl(%d,%d)\n",cmd,arg); +#endif + + switch ( cmd ) + { + case ANSLCD_CLEAR: + anslcd_write_byte_ctrl ( 0x38 ); + anslcd_write_byte_ctrl ( 0x0f ); + anslcd_write_byte_ctrl ( 0x06 ); + anslcd_write_byte_ctrl ( 0x01 ); + anslcd_write_byte_ctrl ( 0x02 ); + return 0; + case ANSLCD_SENDCTRL: + temp = (char *) arg; + __get_user(ch, temp); + for (; ch; temp++) { /* FIXME: This is ugly, but should work, as a \0 byte is not a valid command code */ + anslcd_write_byte_ctrl ( ch ); + __get_user(ch, temp); + } + return 0; + case ANSLCD_SETSHORTDELAY: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + anslcd_short_delay=arg; + return 0; + case ANSLCD_SETLONGDELAY: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + anslcd_long_delay=arg; + return 0; + default: + return -EINVAL; + } +} + +static int __pmac +anslcd_open( struct inode * inode, struct file * file ) +{ + return 0; +} + +struct file_operations anslcd_fops = { + write: anslcd_write, + ioctl: anslcd_ioctl, + open: anslcd_open, +}; + +static struct miscdevice anslcd_dev = { + ANSLCD_MINOR, + "anslcd", + &anslcd_fops +}; + +const char anslcd_logo[] = "********************" /* Line #1 */ + "* LINUX! *" /* Line #3 */ + "* Welcome to *" /* Line #2 */ + "********************"; /* Line #4 */ + +int __init +anslcd_init(void) +{ + int a; + struct device_node* node; + + node = find_devices("lcd"); + if (!node || !node->parent) + return -ENODEV; + if (strcmp(node->parent->name, "gc")) + return -ENODEV; + + anslcd_ptr = (volatile unsigned char*)ioremap(ANSLCD_ADDR, 0x20); + + misc_register(&anslcd_dev); + +#ifdef DEBUG + printk(KERN_DEBUG "LCD: init\n"); +#endif + + anslcd_write_byte_ctrl ( 0x38 ); + anslcd_write_byte_ctrl ( 0x0c ); + anslcd_write_byte_ctrl ( 0x06 ); + anslcd_write_byte_ctrl ( 0x01 ); + anslcd_write_byte_ctrl ( 0x02 ); + for(a=0;a<80;a++) { + anslcd_write_byte_data(anslcd_logo[a]); + } + return 0; +} + +__initcall(anslcd_init); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/macintosh/apm_emu.c linux-2.5/drivers/macintosh/apm_emu.c --- linux-2.5.5/drivers/macintosh/apm_emu.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/macintosh/apm_emu.c Wed Jan 23 01:11:51 2002 @@ -0,0 +1,546 @@ +/* APM emulation layer for PowerMac + * + * Copyright 2001 Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * Lots of code inherited from apm.c, see appropriate notice in + * arch/i386/kernel/apm.c + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#undef DEBUG + +#ifdef DEBUG +#define DBG(args...) printk(KERN_DEBUG args) +//#define DBG(args...) xmon_printf(args) +#else +#define DBG(args...) do { } while (0) +#endif + +/* + * The apm_bios device is one of the misc char devices. + * This is its minor number. + */ +#define APM_MINOR_DEV 134 + +/* + * Maximum number of events stored + */ +#define APM_MAX_EVENTS 20 + +#define FAKE_APM_BIOS_VERSION 0x0101 + +#define APM_USER_NOTIFY_TIMEOUT (5*HZ) + +/* + * The per-file APM data + */ +struct apm_user { + int magic; + struct apm_user * next; + int suser: 1; + int suspend_waiting: 1; + int suspends_pending; + int suspends_read; + int event_head; + int event_tail; + apm_event_t events[APM_MAX_EVENTS]; +}; + +/* + * The magic number in apm_user + */ +#define APM_BIOS_MAGIC 0x4101 + +/* + * Local variables + */ +static int suspends_pending; + +static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); +static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); +static struct apm_user * user_list; + +static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier apm_sleep_notifier = { + apm_notify_sleep, + SLEEP_LEVEL_USERLAND, +}; + +static char driver_version[] = "0.5"; /* no spaces */ + +#ifdef DEBUG +static char * apm_event_name[] = { + "system standby", + "system suspend", + "normal resume", + "critical resume", + "low battery", + "power status change", + "update time", + "critical suspend", + "user standby", + "user suspend", + "system standby resume", + "capabilities change" +}; +#define NR_APM_EVENT_NAME \ + (sizeof(apm_event_name) / sizeof(apm_event_name[0])) + +#endif + +static int queue_empty(struct apm_user *as) +{ + return as->event_head == as->event_tail; +} + +static apm_event_t get_queued_event(struct apm_user *as) +{ + as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; + return as->events[as->event_tail]; +} + +static void queue_event(apm_event_t event, struct apm_user *sender) +{ + struct apm_user * as; + + DBG("apm_emu: queue_event(%s)\n", apm_event_name[event-1]); + if (user_list == NULL) + return; + for (as = user_list; as != NULL; as = as->next) { + if (as == sender) + continue; + as->event_head = (as->event_head + 1) % APM_MAX_EVENTS; + if (as->event_head == as->event_tail) { + static int notified; + + if (notified++ == 0) + printk(KERN_ERR "apm_emu: an event queue overflowed\n"); + as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; + } + as->events[as->event_head] = event; + if (!as->suser) + continue; + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + as->suspends_pending++; + suspends_pending++; + break; + case APM_NORMAL_RESUME: + as->suspend_waiting = 0; + break; + } + } + wake_up_interruptible(&apm_waitqueue); +} + +static int check_apm_user(struct apm_user *as, const char *func) +{ + if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { + printk(KERN_ERR "apm_emu: %s passed bad filp\n", func); + return 1; + } + return 0; +} + +static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos) +{ + struct apm_user * as; + int i; + apm_event_t event; + DECLARE_WAITQUEUE(wait, current); + + as = fp->private_data; + if (check_apm_user(as, "read")) + return -EIO; + if (count < sizeof(apm_event_t)) + return -EINVAL; + if (queue_empty(as)) { + if (fp->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&apm_waitqueue, &wait); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty(as) && !signal_pending(current)) { + schedule(); + goto repeat; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&apm_waitqueue, &wait); + } + i = count; + while ((i >= sizeof(event)) && !queue_empty(as)) { + event = get_queued_event(as); + DBG("apm_emu: do_read, returning: %s\n", apm_event_name[event-1]); + if (copy_to_user(buf, &event, sizeof(event))) { + if (i < count) + break; + return -EFAULT; + } + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + as->suspends_read++; + break; + } + buf += sizeof(event); + i -= sizeof(event); + } + if (i < count) + return count - i; + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +static unsigned int do_poll(struct file *fp, poll_table * wait) +{ + struct apm_user * as; + + as = fp->private_data; + if (check_apm_user(as, "poll")) + return 0; + poll_wait(fp, &apm_waitqueue, wait); + if (!queue_empty(as)) + return POLLIN | POLLRDNORM; + return 0; +} + +static int do_ioctl(struct inode * inode, struct file *filp, + u_int cmd, u_long arg) +{ + struct apm_user * as; + DECLARE_WAITQUEUE(wait, current); + + as = filp->private_data; + if (check_apm_user(as, "ioctl")) + return -EIO; + if (!as->suser) + return -EPERM; + switch (cmd) { + case APM_IOC_SUSPEND: + /* If a suspend message was sent to userland, we + * consider this as a confirmation message + */ + if (as->suspends_read > 0) { + as->suspends_read--; + as->suspends_pending--; + suspends_pending--; + } else { + // Route to PMU suspend ? + break; + } + as->suspend_waiting = 1; + add_wait_queue(&apm_waitqueue, &wait); + DBG("apm_emu: ioctl waking up sleep waiter !\n"); + wake_up(&apm_suspend_waitqueue); + mb(); + while(as->suspend_waiting && !signal_pending(current)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&apm_waitqueue, &wait); + break; + default: + return -EINVAL; + } + return 0; +} + +static int do_release(struct inode * inode, struct file * filp) +{ + struct apm_user * as; + + as = filp->private_data; + if (check_apm_user(as, "release")) + return 0; + filp->private_data = NULL; + lock_kernel(); + if (as->suspends_pending > 0) { + suspends_pending -= as->suspends_pending; + if (suspends_pending <= 0) + wake_up(&apm_suspend_waitqueue); + } + if (user_list == as) + user_list = as->next; + else { + struct apm_user * as1; + + for (as1 = user_list; + (as1 != NULL) && (as1->next != as); + as1 = as1->next) + ; + if (as1 == NULL) + printk(KERN_ERR "apm: filp not in user list\n"); + else + as1->next = as->next; + } + unlock_kernel(); + kfree(as); + return 0; +} + +static int do_open(struct inode * inode, struct file * filp) +{ + struct apm_user * as; + + as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL); + if (as == NULL) { + printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n", + sizeof(*as)); + return -ENOMEM; + } + as->magic = APM_BIOS_MAGIC; + as->event_tail = as->event_head = 0; + as->suspends_pending = 0; + as->suspends_read = 0; + /* + * XXX - this is a tiny bit broken, when we consider BSD + * process accounting. If the device is opened by root, we + * instantly flag that we used superuser privs. Who knows, + * we might close the device immediately without doing a + * privileged operation -- cevans + */ + as->suser = capable(CAP_SYS_ADMIN); + as->next = user_list; + user_list = as; + filp->private_data = as; + + DBG("apm_emu: opened by %s, suser: %d\n", current->comm, (int)as->suser); + + return 0; +} + +/* Wait for all clients to ack the suspend request. APM API + * doesn't provide a way to NAK, but this could be added + * here. + */ +static int wait_all_suspend(void) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&apm_suspend_waitqueue, &wait); + DBG("apm_emu: wait_all_suspend(), suspends_pending: %d\n", suspends_pending); + while(suspends_pending > 0) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&apm_suspend_waitqueue, &wait); + + DBG("apm_emu: wait_all_suspend() - complete !\n"); + + return 1; +} + +static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when) +{ + switch(when) { + case PBOOK_SLEEP_REQUEST: + queue_event(APM_SYS_SUSPEND, NULL); + if (!wait_all_suspend()) + return PBOOK_SLEEP_REFUSE; + break; + case PBOOK_SLEEP_REJECT: + case PBOOK_WAKE: + queue_event(APM_NORMAL_RESUME, NULL); + break; + } + return PBOOK_SLEEP_OK; +} + +#define APM_CRITICAL 10 +#define APM_LOW 30 + +static int apm_emu_get_info(char *buf, char **start, off_t fpos, int length) +{ + /* Arguments, with symbols from linux/apm_bios.h. Information is + from the Get Power Status (0x0a) call unless otherwise noted. + + 0) Linux driver version (this will change if format changes) + 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. + 2) APM flags from APM Installation Check (0x00): + bit 0: APM_16_BIT_SUPPORT + bit 1: APM_32_BIT_SUPPORT + bit 2: APM_IDLE_SLOWS_CLOCK + bit 3: APM_BIOS_DISABLED + bit 4: APM_BIOS_DISENGAGED + 3) AC line status + 0x00: Off-line + 0x01: On-line + 0x02: On backup power (BIOS >= 1.1 only) + 0xff: Unknown + 4) Battery status + 0x00: High + 0x01: Low + 0x02: Critical + 0x03: Charging + 0x04: Selected battery not present (BIOS >= 1.2 only) + 0xff: Unknown + 5) Battery flag + bit 0: High + bit 1: Low + bit 2: Critical + bit 3: Charging + bit 7: No system battery + 0xff: Unknown + 6) Remaining battery life (percentage of charge): + 0-100: valid + -1: Unknown + 7) Remaining battery life (time units): + Number of remaining minutes or seconds + -1: Unknown + 8) min = minutes; sec = seconds */ + + unsigned short ac_line_status = 0xff; + unsigned short battery_status = 0xff; + unsigned short battery_flag = 0xff; + int percentage = -1; + int time_units = -1; + int real_count = 0; + int i; + char * p = buf; + + ac_line_status = ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0); + for (i=0; i> 8) & 0xff, + FAKE_APM_BIOS_VERSION & 0xff, + 0, + ac_line_status, + battery_status, + battery_flag, + percentage, + time_units, + "min"); + + return p - buf; +} + +static struct file_operations apm_bios_fops = { + owner: THIS_MODULE, + read: do_read, + poll: do_poll, + ioctl: do_ioctl, + open: do_open, + release: do_release, +}; + +static struct miscdevice apm_device = { + APM_MINOR_DEV, + "apm_bios", + &apm_bios_fops +}; + +static int __init apm_emu_init(void) +{ + struct proc_dir_entry *apm_proc; + + if (sys_ctrler != SYS_CTRLER_PMU) { + printk(KERN_INFO "apm_emu: Requires a machine with a PMU.\n"); + return -ENODEV; + } + + apm_proc = create_proc_info_entry("apm", 0, NULL, apm_emu_get_info); + if (apm_proc) + SET_MODULE_OWNER(apm_proc); + + misc_register(&apm_device); + + pmu_register_sleep_notifier(&apm_sleep_notifier); + + printk(KERN_INFO "apm_emu: APM Emulation %s initialized.\n", driver_version); + + return 0; +} + +static void __exit apm_emu_exit(void) +{ + pmu_unregister_sleep_notifier(&apm_sleep_notifier); + misc_deregister(&apm_device); + remove_proc_entry("apm", NULL); + + printk(KERN_INFO "apm_emu: APM Emulation removed.\n"); +} + +module_init(apm_emu_init); +module_exit(apm_emu_exit); + +MODULE_AUTHOR("Benjamin Herrenschmidt"); +MODULE_DESCRIPTION("APM emulation layer for PowerMac"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/macintosh/mac_hid.c linux-2.5/drivers/macintosh/mac_hid.c --- linux-2.5.5/drivers/macintosh/mac_hid.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/macintosh/mac_hid.c Thu Dec 27 16:32:31 2001 @@ -200,15 +200,15 @@ 0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0, /* 0x00-0x07 */ 0, 0, 0, 0, KEY_LANG1, KEY_LANG2, 0, 0, /* 0x08-0x0f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ - 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, 0, 0, /* 0x18-0x1f */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, KEY_VOLUMEUP, 0,/* 0x18-0x1f */ + 0, 0, 0, 0, 0, KEY_VOLUMEDOWN, KEY_MUTE, 0, /* 0x20-0x27 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ 0, 0, 0, 0, 0, KEY_KPSLASH, 0, KEY_SYSRQ, /* 0x30-0x37 */ - KEY_RIGHTALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f */ + KEY_RIGHTALT, 0, 0, KEY_EJECTCD, 0, 0, 0, 0, /* 0x38-0x3f */ 0, 0, 0, 0, 0, 0, 0, KEY_HOME, /* 0x40-0x47 */ KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48-0x4f */ KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50-0x57 */ - 0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, KEY_POWER, 0, /* 0x58-0x5f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ 0, 0, 0, 0, 0, 0, 0, KEY_MACRO, /* 0x68-0x6f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/macintosh/macserial.c linux-2.5/drivers/macintosh/macserial.c --- linux-2.5.5/drivers/macintosh/macserial.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/macintosh/macserial.c Mon Feb 4 22:15:16 2002 @@ -39,7 +39,8 @@ #include #include #include -#include +#include +#include #include #include #ifdef CONFIG_KGDB @@ -58,6 +59,7 @@ #endif #define SUPPORT_SERIAL_DMA +#define MACSERIAL_VERSION "2.0" /* * It would be nice to dynamically allocate everything that @@ -1030,7 +1032,7 @@ { unsigned long flags; - OPNDBG("setting up ttys%d SCC...\n", info->line); + OPNDBG("setting up ttyS%d SCC...\n", info->line); save_flags(flags); cli(); /* Disable interrupts */ @@ -1178,7 +1180,7 @@ } memset(info->curregs, 0, sizeof(info->curregs)); - memset(info->curregs, 0, sizeof(info->pendregs)); + memset(info->pendregs, 0, sizeof(info->pendregs)); info->flags &= ~ZILOG_INITIALIZED; } @@ -1193,69 +1195,34 @@ { int delay = 0; - if (feature_test(info->dev_node, FEATURE_Serial_enable) < 0) - return 0; /* don't have serial power control */ - - /* The timings looks strange but that's the ones MacOS seems - to use for the internal modem. I think we can use a lot faster - ones, at least whe not using the modem, this should be tested. - */ if (state) { - PWRDBG("ttyS%02d: powering up hardware\n", info->line); - if (feature_test(info->dev_node, FEATURE_Serial_enable) == 0) { - feature_set(info->dev_node, FEATURE_Serial_enable); - mdelay(10); - feature_set(info->dev_node, FEATURE_Serial_reset); - mdelay(15); - feature_clear(info->dev_node, FEATURE_Serial_reset); - mdelay(10); - } - if (info->zs_chan_a == info->zs_channel) - feature_set(info->dev_node, FEATURE_Serial_IO_A); - else - feature_set(info->dev_node, FEATURE_Serial_IO_B); - delay = 10; - if (info->is_cobalt_modem) { - feature_set_modem_power(info->dev_node, 1); + PWRDBG("ttyS%d: powering up hardware\n", info->line); + pmac_call_feature( + PMAC_FTR_SCC_ENABLE, + info->dev_node, info->port_type, 1); + if (info->is_internal_modem) { + pmac_call_feature( + PMAC_FTR_MODEM_ENABLE, + info->dev_node, 0, 1); delay = 2500; /* wait for 2.5s before using */ - } -#ifdef CONFIG_PMAC_PBOOK - if (info->is_irda) - pmu_enable_irled(1); -#endif /* CONFIG_PMAC_PBOOK */ + } else if (info->is_irda) + mdelay(50); /* Do better here once the problems + * with blocking have been ironed out + */ } else { /* TODO: Make that depend on a timer, don't power down * immediately */ - PWRDBG("ttyS%02d: shutting down hardware\n", info->line); - if (info->is_cobalt_modem) { - PWRDBG("ttyS%02d: shutting down modem\n", info->line); - feature_set_modem_power(info->dev_node, 0); - } -#ifdef CONFIG_PMAC_PBOOK - if (info->is_irda) - pmu_enable_irled(0); -#endif /* CONFIG_PMAC_PBOOK */ - - if (info->zs_chan_a == info->zs_channel && !info->is_irda) { - PWRDBG("ttyS%02d: shutting down SCC channel A\n", info->line); - feature_clear(info->dev_node, FEATURE_Serial_IO_A); - } else if (!info->is_irda) { - PWRDBG("ttyS%02d: shutting down SCC channel B\n", info->line); - feature_clear(info->dev_node, FEATURE_Serial_IO_B); - } - /* XXX for now, shut down SCC core only on powerbooks */ - if (is_powerbook - && !(feature_test(info->dev_node, FEATURE_Serial_IO_A) || - feature_test(info->dev_node, FEATURE_Serial_IO_B))) { - PWRDBG("ttyS%02d: shutting down SCC core\n", info->line); - feature_set(info->dev_node, FEATURE_Serial_reset); - mdelay(15); - feature_clear(info->dev_node, FEATURE_Serial_reset); - mdelay(25); - feature_clear(info->dev_node, FEATURE_Serial_enable); - mdelay(5); - } + PWRDBG("ttyS%d: shutting down hardware\n", info->line); + if (info->is_internal_modem) { + PWRDBG("ttyS%d: shutting down modem\n", info->line); + pmac_call_feature( + PMAC_FTR_MODEM_ENABLE, + info->dev_node, 0, 0); + } + pmac_call_feature( + PMAC_FTR_SCC_ENABLE, + info->dev_node, info->port_type, 0); } return delay; } @@ -1988,7 +1955,7 @@ return; } - OPNDBG("rs_close ttys%d, count = %d\n", info->line, info->count); + OPNDBG("rs_close ttyS%d, count = %d\n", info->line, info->count); if ((tty->count == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty @@ -2003,7 +1970,7 @@ } if (--info->count < 0) { printk(KERN_ERR "rs_close: bad serial port count for " - "ttys%d: %d\n", info->line, info->count); + "ttyS%d: %d\n", info->line, info->count); info->count = 0; } if (info->count) { @@ -2220,7 +2187,7 @@ */ retval = 0; add_wait_queue(&info->open_wait, &wait); - OPNDBG("block_til_ready before block: ttys%d, count = %d\n", + OPNDBG("block_til_ready before block: ttyS%d, count = %d\n", info->line, info->count); cli(); if (!tty_hung_up_p(filp)) @@ -2255,7 +2222,7 @@ retval = -ERESTARTSYS; break; } - OPNDBG("block_til_ready blocking: ttys%d, count = %d\n", + OPNDBG("block_til_ready blocking: ttyS%d, count = %d\n", info->line, info->count); schedule(); } @@ -2264,7 +2231,7 @@ if (!tty_hung_up_p(filp)) info->count++; info->blocked_open--; - OPNDBG("block_til_ready after blocking: ttys%d, count = %d\n", + OPNDBG("block_til_ready after blocking: ttyS%d, count = %d\n", info->line, info->count); if (retval) return retval; @@ -2365,7 +2332,7 @@ info->session = current->session; info->pgrp = current->pgrp; - OPNDBG("rs_open ttys%d successful...\n", info->line); + OPNDBG("rs_open ttyS%d successful...\n", info->line); return 0; } @@ -2373,14 +2340,14 @@ static void show_serial_version(void) { - printk(KERN_INFO "PowerMac Z8530 serial driver version 2.0\n"); + printk(KERN_INFO "PowerMac Z8530 serial driver version " MACSERIAL_VERSION "\n"); } /* * Initialize one channel, both the mac_serial and mac_zschannel * structs. We use the dev_node field of the mac_serial struct. */ -static void +static int chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan, struct mac_zschannel *zs_chan_a) { @@ -2410,12 +2377,15 @@ /* setup misc varariables */ zss->kgdb_channel = 0; - zss->is_cobalt_modem = device_is_compatible(ch, "cobalt"); - /* XXX tested only with wallstreet PowerBook, - should do no harm anyway */ + /* For now, we assume you either have a slot-names property + * with "Modem" in it, or your channel is compatible with + * "cobalt". Might need additional fixups + */ + zss->is_internal_modem = device_is_compatible(ch, "cobalt"); conn = get_property(ch, "AAPL,connector", &len); zss->is_irda = conn && (strcmp(conn, "infrared") == 0); + zss->port_type = PMAC_SCC_ASYNC; /* 1999 Powerbook G3 has slot-names property instead */ slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len); if (slots && slots->count > 0) { @@ -2424,8 +2394,29 @@ else if (strcmp(slots->name, "Modem") == 0) zss->is_internal_modem = 1; } + if (zss->is_irda) + zss->port_type = PMAC_SCC_IRDA; + if (zss->is_internal_modem) { + struct device_node* i2c_modem = find_devices("i2c-modem"); + if (i2c_modem) { + char* mid = get_property(i2c_modem, "modem-id", NULL); + if (mid) switch(*mid) { + case 0x04 : + case 0x05 : + case 0x07 : + case 0x08 : + case 0x0b : + case 0x0c : + zss->port_type = PMAC_SCC_I2S1; + } + printk(KERN_INFO "macserial: i2c-modem detected, id: %d\n", + mid ? (*mid) : 0); + } else { + printk(KERN_INFO "macserial: serial modem detected\n"); + } + } - if (zss->has_dma) { + while (zss->has_dma) { zss->dma_priv = NULL; /* it seems that the last two addresses are the DMA controllers */ @@ -2436,11 +2427,69 @@ zss->tx_dma_irq = ch->intrs[1].line; zss->rx_dma_irq = ch->intrs[2].line; spin_lock_init(&zss->rx_dma_lock); + break; } init_timer(&zss->powerup_timer); zss->powerup_timer.function = powerup_done; zss->powerup_timer.data = (unsigned long) zss; + return 0; +} + +/* + * /proc fs routines. TODO: Add status lines & error stats + */ +static inline int +line_info(char *buf, struct mac_serial *info) +{ + int ret=0; + unsigned char* connector; + int lenp; + + ret += sprintf(buf, "%d: port:0x%X irq:%d", info->line, info->port, info->irq); + + connector = get_property(info->dev_node, "AAPL,connector", &lenp); + if (connector) + ret+=sprintf(buf+ret," con:%s ", connector); + if (info->is_internal_modem) { + if (!connector) + ret+=sprintf(buf+ret," con:"); + ret+=sprintf(buf+ret,"%s", " (internal modem)"); + } + if (info->is_irda) { + if (!connector) + ret+=sprintf(buf+ret," con:"); + ret+=sprintf(buf+ret,"%s", " (IrDA)"); + } + ret+=sprintf(buf+ret,"\n"); + + return ret; +} + +int macserial_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int l, len = 0; + off_t begin = 0; + struct mac_serial *info; + + len += sprintf(page, "serinfo:1.0 driver:" MACSERIAL_VERSION "\n"); + for (info = zs_chain; info && len < 4000; info = info->zs_next) { + l = line_info(page + len, info); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (off-begin); + return ((count < begin+len-off) ? count : begin+len-off); } /* Ask the PROM how many Z8530s we have and initialize their zs_channels */ @@ -2495,13 +2544,15 @@ continue; /* set up A side */ - chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan); + if (chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan)) + continue; ++zs_chan; /* set up B side, if it exists */ if (nchan > 1) - chan_init(&zs_soft[chip + 1 - chan_a_index], - zs_chan, zs_chan - 1); + if (chan_init(&zs_soft[chip + 1 - chan_a_index], + zs_chan, zs_chan - 1)) + continue; ++zs_chan; } *pp = 0; @@ -2527,13 +2578,35 @@ if (zs_chain == 0) probe_sccs(); - /* XXX assume it's a powerbook if we have a via-pmu */ + /* XXX assume it's a powerbook if we have a via-pmu + * + * This is OK for core99 machines as well. + */ is_powerbook = find_devices("via-pmu") != 0; - /* Register the interrupt handler for each one */ + /* Register the interrupt handler for each one + * We also request the OF resources here as probe_sccs() + * might be called too early for that + */ save_flags(flags); cli(); for (i = 0; i < zs_channels_found; ++i) { + struct device_node* ch = zs_soft[i].dev_node; + if (!request_OF_resource(ch, 0, NULL)) { + printk(KERN_ERR "macserial: can't request IO resource !\n"); + return -ENODEV; + } if (zs_soft[i].has_dma) { + if (!request_OF_resource(ch, ch->n_addrs - 2, " (tx dma)")) { + printk(KERN_ERR "macserial: can't request TX DMA resource !\n"); + zs_soft[i].has_dma = 0; + goto no_dma; + } + if (!request_OF_resource(ch, ch->n_addrs - 1, " (rx dma)")) { + release_OF_resource(ch, ch->n_addrs - 2); + printk(KERN_ERR "macserial: can't request RX DMA resource !\n"); + zs_soft[i].has_dma = 0; + goto no_dma; + } if (request_irq(zs_soft[i].tx_dma_irq, rs_txdma_irq, 0, "SCC-txdma", &zs_soft[i])) printk(KERN_ERR "macserial: can't get irq %d\n", @@ -2545,6 +2618,7 @@ zs_soft[i].rx_dma_irq); disable_irq(zs_soft[i].rx_dma_irq); } +no_dma: if (request_irq(zs_soft[i].irq, rs_interrupt, 0, "SCC", &zs_soft[i])) printk(KERN_ERR "macserial: can't get irq %d\n", @@ -2560,6 +2634,7 @@ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "macserial"; #ifdef CONFIG_DEVFS_FS serial_driver.name = "tts/%d"; #else @@ -2579,7 +2654,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -2596,6 +2673,7 @@ serial_driver.hangup = rs_hangup; serial_driver.break_ctl = rs_break; serial_driver.wait_until_sent = rs_wait_until_sent; + serial_driver.read_proc = macserial_read_proc; /* * The callout device is just like normal device except for @@ -2609,6 +2687,8 @@ #endif /* CONFIG_DEVFS_FS */ callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); @@ -2675,21 +2755,11 @@ connector = get_property(info->dev_node, "AAPL,connector", &lenp); if (connector) printk(", port = %s", connector); - if (info->is_cobalt_modem) - printk(" (cobalt modem)"); - else if (info->is_internal_modem) + if (info->is_internal_modem) printk(" (internal modem)"); if (info->is_irda) printk(" (IrDA)"); printk("\n"); - -#ifndef CONFIG_XMON -#ifdef CONFIG_KGDB - if (!info->kgdb_channel) -#endif /* CONFIG_KGDB */ - /* By default, disable the port */ - set_scc_power(info, 0); -#endif /* CONFIG_XMON */ } tmp_buf = 0; @@ -2710,6 +2780,12 @@ if (zs_soft[i].has_dma) { free_irq(zs_soft[i].tx_dma_irq, &zs_soft[i]); free_irq(zs_soft[i].rx_dma_irq, &zs_soft[i]); + } + release_OF_resource(zs_soft[i].dev_node, 0); + if (zs_soft[i].has_dma) { + struct device_node* ch = zs_soft[i].dev_node; + release_OF_resource(ch, ch->n_addrs - 2); + release_OF_resource(ch, ch->n_addrs - 1); } } restore_flags(flags); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/macintosh/macserial.h linux-2.5/drivers/macintosh/macserial.h --- linux-2.5.5/drivers/macintosh/macserial.h Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/macintosh/macserial.h Thu Dec 27 16:32:31 2001 @@ -111,8 +111,8 @@ char kgdb_channel; /* Kgdb is running on this channel */ char is_cons; /* Is this our console. */ char is_internal_modem; /* is connected to an internal modem */ - char is_cobalt_modem; /* is a gatwick-based cobalt modem */ char is_irda; /* is connected to an IrDA codec */ + int port_type; /* Port type for pmac_feature */ unsigned char tx_active; /* character is being xmitted */ unsigned char tx_stopped; /* output is suspended */ unsigned char power_wait; /* waiting for power-up delay to expire */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/macintosh/mediabay.c linux-2.5/drivers/macintosh/mediabay.c --- linux-2.5.5/drivers/macintosh/mediabay.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/macintosh/mediabay.c Thu Dec 27 16:32:31 2001 @@ -25,9 +25,13 @@ #include #include #include -#include +#include +#include #include #include +#include +#include +#include #include #include @@ -40,7 +44,7 @@ #endif #undef MB_USE_INTERRUPTS -#undef MB_DEBUG +#define MB_DEBUG #define MB_IGNORE_SIGNALS #ifdef MB_DEBUG @@ -49,24 +53,46 @@ #define MBDBG(fmt, arg...) do { } while (0) #endif -struct media_bay_hw { - unsigned char b0; - unsigned char contents; - unsigned char b2; - unsigned char b3; +/* Type of media bay */ +enum { + mb_ohare, + mb_heathrow, + mb_keylargo +}; + +#define MB_FCR32(bay, r) ((bay)->base + ((r) >> 2)) +#define MB_FCR8(bay, r) (((volatile u8*)((bay)->base)) + (r)) + +#define MB_IN32(bay,r) (in_le32(MB_FCR32(bay,r))) +#define MB_OUT32(bay,r,v) (out_le32(MB_FCR32(bay,r), (v))) +#define MB_BIS(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) | (v))) +#define MB_BIC(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) & ~(v))) +#define MB_IN8(bay,r) (in_8(MB_FCR8(bay,r))) +#define MB_OUT8(bay,r,v) (out_8(MB_FCR8(bay,r), (v))) + +struct media_bay_info; + +struct mb_ops { + char* name; + u8 (*content)(struct media_bay_info* bay); + void (*power)(struct media_bay_info* bay, int on_off); + int (*setup_bus)(struct media_bay_info* bay, u8 device_id); + void (*un_reset)(struct media_bay_info* bay); + void (*un_reset_ide)(struct media_bay_info* bay); }; struct media_bay_info { - volatile struct media_bay_hw* addr; - volatile u8* extint_gpio; + volatile u32* base; int content_id; int state; int last_value; int value_count; int timer; struct device_node* dev_node; - int pismo; /* New PowerBook3,1 */ - int gpio_cache; + int mb_type; + struct mb_ops* ops; + int index; + int cached_gpio; #ifdef CONFIG_BLK_DEV_IDE unsigned long cd_base; int cd_index; @@ -77,33 +103,12 @@ #define MAX_BAYS 2 -static volatile struct media_bay_info media_bays[MAX_BAYS]; +static struct media_bay_info media_bays[MAX_BAYS]; int media_bay_count = 0; -inline int mb_content(volatile struct media_bay_info *bay) -{ - if (bay->pismo) { - unsigned char new_gpio = in_8(bay->extint_gpio + 0xe) & 2; - if (new_gpio) { - bay->gpio_cache = new_gpio; - return MB_NO; - } else if (bay->gpio_cache != new_gpio) { - /* make sure content bits are set */ - feature_set(bay->dev_node, FEATURE_Mediabay_content); - udelay(5); - bay->gpio_cache = new_gpio; - } - return (in_le32((unsigned*)bay->addr) >> 4) & 0xf; - } else { - int cont = (in_8(&bay->addr->contents) >> 4) & 7; - return (cont == 7) ? MB_NO : cont; - } -} - #ifdef CONFIG_BLK_DEV_IDE /* check the busy bit in the media-bay ide interface (assumes the media-bay contains an ide device) */ -//#define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0xc0) == 0x40) #define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0x80) == 0) #endif @@ -116,7 +121,7 @@ * Consider the media-bay ID value stable if it is the same for * this number of milliseconds */ -#define MB_STABLE_DELAY 40 +#define MB_STABLE_DELAY 100 /* Wait after powering up the media bay this delay in ms * timeout bumped for some powerbooks @@ -166,175 +171,259 @@ mb_powering_down /* Powering down (avoid too fast down/up) */ }; -static void poll_media_bay(int which); -static void set_media_bay(int which, int id); -static void set_mb_power(int which, int onoff); -static void media_bay_step(int i); -static int media_bay_task(void *); +#define MB_POWER_SOUND 0x08 +#define MB_POWER_FLOPPY 0x04 +#define MB_POWER_ATA 0x02 +#define MB_POWER_PCI 0x01 +#define MB_POWER_OFF 0x00 -#ifdef MB_USE_INTERRUPTS -static void media_bay_intr(int irq, void *devid, struct pt_regs *regs); -#endif +/* + * Functions for polling content of media bay + */ + +static u8 __pmac +ohare_mb_content(struct media_bay_info *bay) +{ + return (MB_IN32(bay, OHARE_MBCR) >> 12) & 7; +} + +static u8 __pmac +heathrow_mb_content(struct media_bay_info *bay) +{ + return (MB_IN32(bay, HEATHROW_MBCR) >> 12) & 7; +} + +static u8 __pmac +keylargo_mb_content(struct media_bay_info *bay) +{ + int new_gpio; + + new_gpio = MB_IN8(bay, KL_GPIO_MEDIABAY_IRQ) & KEYLARGO_GPIO_INPUT_DATA; + if (new_gpio) { + bay->cached_gpio = new_gpio; + return MB_NO; + } else if (bay->cached_gpio != new_gpio) { + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); + (void)MB_IN32(bay, KEYLARGO_MBCR); + udelay(5); + MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F); + (void)MB_IN32(bay, KEYLARGO_MBCR); + udelay(5); + bay->cached_gpio = new_gpio; + } + return (MB_IN32(bay, KEYLARGO_MBCR) >> 4) & 7; +} /* - * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL - * register is always set when there is something in the media bay. - * This causes problems for the interrupt code if we attach an interrupt - * handler to the media-bay interrupt, because it tends to go into - * an infinite loop calling the media bay interrupt handler. - * Therefore we do it all by polling the media bay once each tick. + * Functions for powering up/down the bay, puts the bay device + * into reset state as well */ -void __pmac -media_bay_init(void) +static void __pmac +ohare_mb_power(struct media_bay_info* bay, int on_off) { - struct device_node *np; - int n,i; - - for (i=0; in_addrs == 0) - continue; - media_bays[n].addr = (volatile struct media_bay_hw *) - ioremap(np->addrs[0].address, sizeof(struct media_bay_hw)); + MB_BIC(bay, OHARE_MBCR, 0x00000F00); +} - media_bays[n].pismo = device_is_compatible(np, "keylargo-media-bay"); - if (media_bays[n].pismo) { - if (!np->parent || strcmp(np->parent->name, "mac-io")) { - printk(KERN_ERR "Pismo media-bay has no mac-io parent !\n"); - continue; - } - media_bays[n].extint_gpio = ioremap(np->parent->addrs[0].address - + 0x58, 0x10); - } +static void __pmac +heathrow_mb_power(struct media_bay_info* bay, int on_off) +{ + if (on_off) { + /* Power up device, assert it's reset line */ + MB_BIC(bay, HEATHROW_FCR, HRW_BAY_RESET_N); + MB_BIC(bay, HEATHROW_FCR, HRW_BAY_POWER_N); + } else { + /* Disable all devices */ + MB_BIC(bay, HEATHROW_FCR, HRW_BAY_DEV_MASK); + MB_BIC(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); + /* Cut power from bay, release reset line */ + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_POWER_N); + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); + MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); + } + MB_BIC(bay, HEATHROW_MBCR, 0x00000F00); +} -#ifdef MB_USE_INTERRUPTS - if (np->n_intrs == 0) { - printk(KERN_ERR "media bay %d has no irq\n",n); - continue; - } +static void __pmac +keylargo_mb_power(struct media_bay_info* bay, int on_off) +{ + if (on_off) { + /* Power up device, assert it's reset line */ + MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); + MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); + } else { + /* Disable all devices */ + MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); + MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); + /* Cut power from bay, release reset line */ + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); + MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); + } + MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F); +} - if (request_irq(np->intrs[0].line, media_bay_intr, 0, "Media bay", (void *)n)) { - printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", - np->intrs[0].line, n); - continue; - } -#endif - media_bay_count++; - - media_bays[n].dev_node = np; +/* + * Functions for configuring the media bay for a given type of device, + * enable the related busses + */ - /* Force an immediate detect */ - set_mb_power(n,0); - mdelay(MB_POWER_DELAY); - if(!media_bays[n].pismo) - out_8(&media_bays[n].addr->contents, 0x70); - mdelay(MB_STABLE_DELAY); - media_bays[n].content_id = MB_NO; - media_bays[n].last_value = mb_content(&media_bays[n]); - media_bays[n].value_count = MS_TO_HZ(MB_STABLE_DELAY); - media_bays[n].state = mb_empty; - do { - mdelay(1000/HZ); - media_bay_step(n); - } while((media_bays[n].state != mb_empty) && - (media_bays[n].state != mb_up)); +static int __pmac +ohare_mb_setup_bus(struct media_bay_info* bay, u8 device_id) +{ + switch(device_id) { + case MB_FD: + case MB_FD1: + MB_BIS(bay, OHARE_FCR, OH_BAY_FLOPPY_ENABLE); + MB_BIS(bay, OHARE_FCR, OH_FLOPPY_ENABLE); + return 0; + case MB_CD: + MB_BIC(bay, OHARE_FCR, OH_IDE1_RESET_N); + MB_BIS(bay, OHARE_FCR, OH_BAY_IDE_ENABLE); + return 0; + case MB_PCI: + MB_BIS(bay, OHARE_FCR, OH_BAY_PCI_ENABLE); + return 0; + } + return -ENODEV; +} - n++; - np=np->next; +static int __pmac +heathrow_mb_setup_bus(struct media_bay_info* bay, u8 device_id) +{ + switch(device_id) { + case MB_FD: + case MB_FD1: + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_FLOPPY_ENABLE); + MB_BIS(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); + return 0; + case MB_CD: + MB_BIC(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_IDE_ENABLE); + return 0; + case MB_PCI: + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_PCI_ENABLE); + return 0; } + return -ENODEV; +} - if (media_bay_count) - { - printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count); +static int __pmac +keylargo_mb_setup_bus(struct media_bay_info* bay, u8 device_id) +{ + switch(device_id) { + case MB_CD: + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE); + MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); + MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); + return 0; + case MB_PCI: + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_PCI_ENABLE); + return 0; + case MB_SOUND: + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_SOUND_ENABLE); + return 0; + } + return -ENODEV; +} -#ifdef CONFIG_PMAC_PBOOK - pmu_register_sleep_notifier(&mb_sleep_notifier); -#endif /* CONFIG_PMAC_PBOOK */ +/* + * Functions for tweaking resets + */ - kernel_thread(media_bay_task, NULL, - CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - } +static void __pmac +ohare_mb_un_reset(struct media_bay_info* bay) +{ + MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N); } -#ifdef MB_USE_INTERRUPTS static void __pmac -media_bay_intr(int irq, void *devid, struct pt_regs *regs) +heathrow_mb_un_reset(struct media_bay_info* bay) { + MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); +} + +static void __pmac +keylargo_mb_un_reset(struct media_bay_info* bay) +{ + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); +} + +static void __pmac +ohare_mb_un_reset_ide(struct media_bay_info* bay) +{ + MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N); +} + +static void __pmac +heathrow_mb_un_reset_ide(struct media_bay_info* bay) +{ + MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); } -#endif static void __pmac -set_mb_power(int which, int onoff) +keylargo_mb_un_reset_ide(struct media_bay_info* bay) { - volatile struct media_bay_info* mb = &media_bays[which]; + MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); +} +static inline void __pmac +set_mb_power(struct media_bay_info* bay, int onoff) +{ + /* Power up up and assert the bay reset line */ if (onoff) { - feature_set(mb->dev_node, FEATURE_Mediabay_power); - udelay(10); - feature_set(mb->dev_node, FEATURE_Mediabay_reset); - udelay(10); - mb->state = mb_powering_up; - MBDBG("mediabay%d: powering up\n", which); - } else { - feature_clear(mb->dev_node, FEATURE_Mediabay_floppy_enable); - if (mb->pismo) - feature_clear(mb->dev_node, FEATURE_IDE0_enable); - else - feature_clear(mb->dev_node, FEATURE_IDE1_enable); - feature_clear(mb->dev_node, FEATURE_Mediabay_IDE_switch); - feature_clear(mb->dev_node, FEATURE_Mediabay_PCI_enable); - feature_clear(mb->dev_node, FEATURE_SWIM3_enable); - feature_clear(mb->dev_node, FEATURE_Mediabay_power); - mb->state = mb_powering_down; - MBDBG("mediabay%d: powering down\n", which); + bay->ops->power(bay, 1); + bay->state = mb_powering_up; + MBDBG("mediabay%d: powering up\n", bay->index); + } else { + /* Make sure everything is powered down & disabled */ + bay->ops->power(bay, 0); + bay->state = mb_powering_down; + MBDBG("mediabay%d: powering down\n", bay->index); } - mb->timer = MS_TO_HZ(MB_POWER_DELAY); + bay->timer = MS_TO_HZ(MB_POWER_DELAY); } static void __pmac -set_media_bay(int which, int id) +poll_media_bay(struct media_bay_info* bay) { - volatile struct media_bay_info* bay; + int id = bay->ops->content(bay); - bay = &media_bays[which]; - - switch (id) { - case MB_CD: - if (bay->pismo) { - feature_set(bay->dev_node, FEATURE_Mediabay_IDE_switch); - udelay(10); - feature_set(bay->dev_node, FEATURE_IDE0_enable); - udelay(10); - feature_set(bay->dev_node, FEATURE_IDE0_reset); - } else { - feature_set(bay->dev_node, FEATURE_IDE1_enable); - udelay(10); - feature_set(bay->dev_node, FEATURE_IDE1_reset); + if (id == bay->last_value) { + if (id != bay->content_id + && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) { + /* If the device type changes without going thru "MB_NO", we force + a pass by "MB_NO" to make sure things are properly reset */ + if ((id != MB_NO) && (bay->content_id != MB_NO)) { + id = MB_NO; + MBDBG("mediabay%d: forcing MB_NO\n", bay->index); } - printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which); - break; - case MB_FD: - case MB_FD1: - feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable); - feature_set(bay->dev_node, FEATURE_SWIM3_enable); - printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which); - break; - case MB_NO: - break; - default: - printk(KERN_INFO "media bay %d contains an unknown device (%d)\n", - which, id); - break; + MBDBG("mediabay%d: switching to %d\n", bay->index, id); + set_mb_power(bay, id != MB_NO); + bay->content_id = id; + if (id == MB_NO) { +#ifdef CONFIG_BLK_DEV_IDE + bay->cd_retry = 0; +#endif + printk(KERN_INFO "media bay %d is empty\n", bay->index); + } + } + } else { + bay->last_value = id; + bay->value_count = 0; } } @@ -412,11 +501,11 @@ static void __pmac media_bay_step(int i) { - volatile struct media_bay_info* bay = &media_bays[i]; + struct media_bay_info* bay = &media_bays[i]; /* We don't poll when powering down */ if (bay->state != mb_powering_down) - poll_media_bay(i); + poll_media_bay(bay); /* If timer expired or polling IDE busy, run state machine */ if ((bay->state != mb_ide_waiting) && (bay->timer != 0) && ((--bay->timer) != 0)) @@ -424,13 +513,17 @@ switch(bay->state) { case mb_powering_up: - set_media_bay(i, bay->last_value); + if (bay->ops->setup_bus(bay, bay->last_value) < 0) { + MBDBG("mediabay%d: device not supported (kind:%d)\n", i, bay->content_id); + set_mb_power(bay, 0); + break; + } bay->timer = MS_TO_HZ(MB_RESET_DELAY); bay->state = mb_enabling_bay; MBDBG("mediabay%d: enabling (kind:%d)\n", i, bay->content_id); break; case mb_enabling_bay: - feature_clear(bay->dev_node, FEATURE_Mediabay_reset); + bay->ops->un_reset(bay); bay->timer = MS_TO_HZ(MB_SETUP_DELAY); bay->state = mb_resetting; MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id); @@ -444,16 +537,13 @@ } #ifdef CONFIG_BLK_DEV_IDE MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id); - if (bay->pismo) - feature_clear(bay->dev_node, FEATURE_IDE0_reset); - else - feature_clear(bay->dev_node, FEATURE_IDE1_reset); + bay->ops->un_reset_ide(bay); bay->timer = MS_TO_HZ(MB_IDE_WAIT); bay->state = mb_ide_resetting; #else printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i); - set_mb_power(i, 0); -#endif // #ifdef CONFIG_BLK_DEV_IDE + set_mb_power(bay, 0); +#endif /* CONFIG_BLK_DEV_IDE */ break; #ifdef CONFIG_BLK_DEV_IDE @@ -481,7 +571,7 @@ /* We eventually do a retry */ bay->cd_retry++; printk("IDE register error\n"); - set_mb_power(i, 0); + set_mb_power(bay, 0); } else { printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index); MBDBG("mediabay %d IDE ready\n", i); @@ -491,10 +581,10 @@ if (bay->timer == 0) { printk("\nIDE Timeout in bay %d !\n", i); MBDBG("mediabay%d: nIDE Timeout !\n", i); - set_mb_power(i, 0); + set_mb_power(bay, 0); } break; -#endif // #ifdef CONFIG_BLK_DEV_IDE +#endif /* CONFIG_BLK_DEV_IDE */ case mb_powering_down: bay->state = mb_empty; @@ -514,7 +604,7 @@ bay->content_id = MB_NO; } } -#endif +#endif /* CONFIG_BLK_DEV_IDE */ MBDBG("mediabay%d: end of power down\n", i); break; } @@ -526,7 +616,7 @@ * with the IDE driver. It needs to be a thread because * ide_register can't be called from interrupt context. */ -int __pmac +static int __pmac media_bay_task(void *x) { int i; @@ -547,37 +637,12 @@ } } -void __pmac -poll_media_bay(int which) +#ifdef MB_USE_INTERRUPTS +static void __pmac +media_bay_intr(int irq, void *devid, struct pt_regs *regs) { - volatile struct media_bay_info* bay = &media_bays[which]; - int id = mb_content(bay); - - if (id == bay->last_value) { - if (id != bay->content_id - && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) { - /* If the device type changes without going thru "MB_NO", we force - a pass by "MB_NO" to make sure things are properly reset */ - if ((id != MB_NO) && (bay->content_id != MB_NO)) { - id = MB_NO; - MBDBG("mediabay%d: forcing MB_NO\n", which); - } - MBDBG("mediabay%d: switching to %d\n", which, id); - set_mb_power(which, id != MB_NO); - bay->content_id = id; - if (id == MB_NO) { -#ifdef CONFIG_BLK_DEV_IDE - bay->cd_retry = 0; -#endif - printk(KERN_INFO "media bay %d is empty\n", which); - } - } - } else { - bay->last_value = id; - bay->value_count = 0; - } } - +#endif #ifdef CONFIG_PMAC_PBOOK /* @@ -586,7 +651,7 @@ int __pmac mb_notify_sleep(struct pmu_sleep_notifier *self, int when) { - volatile struct media_bay_info* bay; + struct media_bay_info* bay; int i; switch (when) { @@ -597,7 +662,7 @@ case PBOOK_SLEEP_NOW: for (i=0; ipismo) - out_8(&bay->addr->contents, 0x70); - mdelay(MB_STABLE_DELAY); - if (mb_content(bay) != bay->content_id) + if (bay->ops->content(bay) != bay->content_id) continue; - set_mb_power(i, 1); + set_mb_power(bay, 1); bay->last_value = bay->content_id; bay->value_count = MS_TO_HZ(MB_STABLE_DELAY); bay->timer = MS_TO_HZ(MB_POWER_DELAY); @@ -634,4 +696,135 @@ return PBOOK_SLEEP_OK; } #endif /* CONFIG_PMAC_PBOOK */ + + +/* Definitions of "ops" structures. + */ +static struct mb_ops ohare_mb_ops __pmacdata = { + name: "Ohare", + content: ohare_mb_content, + power: ohare_mb_power, + setup_bus: ohare_mb_setup_bus, + un_reset: ohare_mb_un_reset, + un_reset_ide: ohare_mb_un_reset_ide, +}; + +static struct mb_ops heathrow_mb_ops __pmacdata = { + name: "Heathrow", + content: heathrow_mb_content, + power: heathrow_mb_power, + setup_bus: heathrow_mb_setup_bus, + un_reset: heathrow_mb_un_reset, + un_reset_ide: heathrow_mb_un_reset_ide, +}; + +static struct mb_ops keylargo_mb_ops __pmacdata = { + name: "KeyLargo", + content: keylargo_mb_content, + power: keylargo_mb_power, + setup_bus: keylargo_mb_setup_bus, + un_reset: keylargo_mb_un_reset, + un_reset_ide: keylargo_mb_un_reset_ide, +}; + +/* + * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL + * register is always set when there is something in the media bay. + * This causes problems for the interrupt code if we attach an interrupt + * handler to the media-bay interrupt, because it tends to go into + * an infinite loop calling the media bay interrupt handler. + * Therefore we do it all by polling the media bay once each tick. + */ + +void __pmac +media_bay_init(void) +{ + struct device_node *np; + int n,i; + + for (i=0; iparent || np->n_addrs == 0 || !request_OF_resource(np, 0, NULL)) { + np = np->next; + printk(KERN_ERR "media-bay: Can't request IO resource !\n"); + continue; + } + bay->mb_type = mb_ohare; + + if (device_is_compatible(np, "keylargo-media-bay")) { + bay->mb_type = mb_keylargo; + bay->ops = &keylargo_mb_ops; + } else if (device_is_compatible(np, "heathrow-media-bay")) { + bay->mb_type = mb_heathrow; + bay->ops = &heathrow_mb_ops; + } else if (device_is_compatible(np, "ohare-media-bay")) { + bay->mb_type = mb_ohare; + bay->ops = &ohare_mb_ops; + } else { + printk(KERN_ERR "mediabay: Unknown bay type !\n"); + np = np->next; + continue; + } + bay->base = (volatile u32*)ioremap(np->parent->addrs[0].address, 0x1000); + + /* Enable probe logic on keylargo */ + if (bay->mb_type == mb_keylargo) + MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); +#ifdef MB_USE_INTERRUPTS + if (np->n_intrs == 0) { + printk(KERN_ERR "media bay %d has no irq\n",n); + np = np->next; + continue; + } + + if (request_irq(np->intrs[0].line, media_bay_intr, 0, "Media bay", (void *)n)) { + printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", + np->intrs[0].line, n); + np = np->next; + continue; + } +#endif + media_bay_count++; + + printk(KERN_INFO "mediabay%d: Registered %s media-bay\n", n, bay->ops->name); + bay->dev_node = np; + bay->index = n; + + /* Force an immediate detect */ + set_mb_power(bay, 0); + mdelay(MB_POWER_DELAY); + bay->content_id = MB_NO; + bay->last_value = bay->ops->content(bay); + bay->value_count = MS_TO_HZ(MB_STABLE_DELAY); + bay->state = mb_empty; + do { + mdelay(1000/HZ); + media_bay_step(n); + } while((bay->state != mb_empty) && + (bay->state != mb_up)); + + n++; + np=np->next; + } + + if (media_bay_count) + { +#ifdef CONFIG_PMAC_PBOOK + pmu_register_sleep_notifier(&mb_sleep_notifier); +#endif /* CONFIG_PMAC_PBOOK */ + + kernel_thread(media_bay_task, NULL, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + } +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/macintosh/rtc.c linux-2.5/drivers/macintosh/rtc.c --- linux-2.5.5/drivers/macintosh/rtc.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/macintosh/rtc.c Thu Dec 27 16:32:31 2001 @@ -34,14 +34,13 @@ void get_rtc_time(struct rtc_time *t) { unsigned long nowtime; - + nowtime = (ppc_md.get_rtc_time)(); to_tm(nowtime, t); t->tm_year -= 1900; - t->tm_mon -= 1; - t->tm_wday -= 1; + t->tm_mon -= 1; /* Make sure userland has a 0-based month */ } /* Set the current date and time in the real time clock. */ @@ -49,7 +48,8 @@ { unsigned long nowtime; - nowtime = mktime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); + nowtime = mktime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); (ppc_md.set_rtc_time)(nowtime); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/macintosh/via-cuda.c linux-2.5/drivers/macintosh/via-cuda.c --- linux-2.5.5/drivers/macintosh/via-cuda.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/macintosh/via-cuda.c Thu Dec 27 16:32:31 2001 @@ -191,6 +191,8 @@ if (via == NULL) return -ENODEV; + request_OF_resource(vias, 0, NULL); + if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) { printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ); return -EAGAIN; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/macintosh/via-pmu.c linux-2.5/drivers/macintosh/via-pmu.c --- linux-2.5.5/drivers/macintosh/via-pmu.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/macintosh/via-pmu.c Fri Mar 1 15:07:38 2002 @@ -9,9 +9,9 @@ * and the RTC (real time clock) chip. * * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. + * Copyright (C) 2001 Benjamin Herrenschmidt * - * todo: - Check this driver for smp safety (new Core99 motherboards). - * - Cleanup synchro between VIA interrupt and GPIO-based PMU + * todo: - Cleanup synchro between VIA interrupt and GPIO-based PMU * interrupt. * * @@ -45,10 +45,12 @@ #include #include #include -#include +#include #include #include +#include #include +#include #ifdef CONFIG_PMAC_BACKLIGHT #include #endif @@ -56,9 +58,13 @@ /* Some compile options */ #undef SUSPEND_USES_PMU #define DEBUG_SLEEP +#undef HACKED_PCI_SAVE /* Misc minor number allocated for /dev/pmu */ -#define PMU_MINOR 154 +#define PMU_MINOR 154 + +/* How many iterations between battery polls */ +#define BATTERY_POLLING_COUNT 2 static volatile unsigned char *via; @@ -108,7 +114,7 @@ static struct adb_request *current_req; static struct adb_request *last_req; static struct adb_request *req_awaiting_reply; -static unsigned char interrupt_data[32]; +static unsigned char interrupt_data[256]; /* Made bigger: I've been told that might happen */ static unsigned char *reply_ptr; static int data_index; static int data_len; @@ -126,9 +132,26 @@ static int pmu_version; static int drop_interrupts; #ifdef CONFIG_PMAC_PBOOK +static int option_lid_wakeup = 1; static int sleep_in_progress; +static int can_sleep; +#endif /* CONFIG_PMAC_PBOOK */ + +static struct proc_dir_entry *proc_pmu_root; +static struct proc_dir_entry *proc_pmu_info; +static struct proc_dir_entry *proc_pmu_options; + +#ifdef CONFIG_PMAC_PBOOK +int pmu_battery_count; +int pmu_cur_battery; +unsigned int pmu_power_flags; +struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES]; +static int query_batt_timer = BATTERY_POLLING_COUNT; +static struct adb_request batt_req; +static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES]; #endif /* CONFIG_PMAC_PBOOK */ +int __fake_sleep; int asleep; struct notifier_block *sleep_notifier_list; @@ -153,15 +176,22 @@ static void pmu_done(struct adb_request *req); static void pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs); -static void set_volume(int level); static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs); +static int proc_get_info(char *page, char **start, off_t off, + int count, int *eof, void *data); #ifdef CONFIG_PMAC_BACKLIGHT static int pmu_set_backlight_level(int level, void* data); static int pmu_set_backlight_enable(int on, int level, void* data); #endif /* CONFIG_PMAC_BACKLIGHT */ #ifdef CONFIG_PMAC_PBOOK static void pmu_pass_intr(unsigned char *data, int len); -#endif +static int proc_get_batt(char *page, char **start, off_t off, + int count, int *eof, void *data); +#endif /* CONFIG_PMAC_PBOOK */ +static int proc_read_options(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int proc_write_options(struct file *file, const char *buffer, + unsigned long count, void *data); #ifdef CONFIG_ADB struct adb_driver via_pmu_driver = { @@ -309,6 +339,10 @@ } else pmu_kind = PMU_UNKNOWN; +#ifdef CONFIG_PMAC_PBOOK + if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) + can_sleep = 1; +#endif /* CONFIG_PMAC_PBOOK */ via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000); out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ @@ -362,9 +396,14 @@ if (vias == NULL) return -ENODEV; + request_OF_resource(vias, 0, NULL); + bright_req_1.complete = 1; bright_req_2.complete = 1; bright_req_3.complete = 1; +#ifdef CONFIG_PMAC_PBOOK + batt_req.complete = 1; +#endif if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU", (void *)0)) { @@ -388,6 +427,46 @@ register_backlight_controller(&pmu_backlight_controller, NULL, "pmu"); #endif /* CONFIG_PMAC_BACKLIGHT */ +#ifdef CONFIG_PMAC_PBOOK + if (machine_is_compatible("AAPL,3400/2400") || + machine_is_compatible("AAPL,3500")) + pmu_battery_count = 1; + else if (machine_is_compatible("AAPL,PowerBook1998") || + machine_is_compatible("PowerBook1,1")) + pmu_battery_count = 2; + else { + struct device_node* prim = find_devices("power-mgt"); + u32 *prim_info = NULL; + if (prim) + prim_info = (u32 *)get_property(prim, "prim-info", NULL); + if (prim_info) { + /* Other stuffs here yet unknown */ + pmu_battery_count = (prim_info[6] >> 16) & 0xff; + } + } +#endif /* CONFIG_PMAC_PBOOK */ + /* Create /proc/pmu */ + proc_pmu_root = proc_mkdir("pmu", 0); + if (proc_pmu_root) { + int i; + proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root, + proc_get_info, NULL); +#ifdef CONFIG_PMAC_PBOOK + for (i=0; inlink = 1; + proc_pmu_options->read_proc = proc_read_options; + proc_pmu_options->write_proc = proc_write_options; + } + } + /* Make sure PMU settle down before continuing. This is _very_ important * since the IDE probe may shut interrupts down for quite a bit of time. If * a PMU communication is pending while this happens, the PMU may timeout @@ -448,8 +527,8 @@ pmu_request(&req, NULL, 1, PMU_GET_VERSION); while (!req.complete) pmu_poll(); - if (req.reply_len > 1) - pmu_version = req.reply[1]; + if (req.reply_len > 0) + pmu_version = req.reply[0]; return 1; } @@ -460,6 +539,263 @@ return pmu_kind; } +#ifdef CONFIG_PMAC_PBOOK + +/* + * WARNING ! This code probably needs some debugging... -- BenH. + */ +static void __pmac +done_battery_state_ohare(struct adb_request* req) +{ + unsigned int bat_flags = 0; + int current = 0; + unsigned int capa, max, voltage, time; + int lrange[] = { 0, 275, 850, 1680, 2325, + 2765, 3160, 3500, 3830, 4115, + 4360, 4585, 4795, 4990, 5170, + 5340, 5510, 5710, 5930, 6150, + 6370, 6500 + }; + + if (req->reply[0] & 0x01) + pmu_power_flags |= PMU_PWR_AC_PRESENT; + else + pmu_power_flags &= ~PMU_PWR_AC_PRESENT; + + if (req->reply[0] & 0x04) { + int vb, i, j, charge, pcharge; + bat_flags |= PMU_BATT_PRESENT; + vb = (req->reply[1] << 8) | req->reply[2]; + voltage = ((vb * 2650) + 726650)/100; + current = *((signed char *)&req->reply[5]); + if ((req->reply[0] & 0x01) == 0 && (current > 200)) + vb += (current - 200) * 15; + else if (req->reply[0] & 0x02) + vb = (vb - 10) * 100; + i = (33000 - vb) / 10; + j = i - (i % 100); + if (j <= 0) + charge = 0; + else if (j >= 21) + charge = 650000; + else + charge = (lrange[j + 1] - lrange[j]) * (i - j) + (lrange[j] * 100); + charge = (1000 - charge / 650) / 10; + if (req->reply[0] & 0x40) { + pcharge = (req->reply[6] << 8) + req->reply[7]; + if (pcharge > 6500) + pcharge = 6500; + pcharge *= 100; + pcharge = (1000 - pcharge / 650) / 10; + if (pcharge < charge) + charge = pcharge; + } + capa = charge; + max = 100; + time = (charge * 274) / current; + current = -current; + + } else + capa = max = current = voltage = time = 0; + + if ((req->reply[0] & 0x02) && (current > 0)) + bat_flags |= PMU_BATT_CHARGING; + if (req->reply[0] & 0x04) /* CHECK THIS ONE */ + bat_flags |= PMU_BATT_PRESENT; + + pmu_batteries[pmu_cur_battery].flags = bat_flags; + pmu_batteries[pmu_cur_battery].charge = capa; + pmu_batteries[pmu_cur_battery].max_charge = max; + pmu_batteries[pmu_cur_battery].current = current; + pmu_batteries[pmu_cur_battery].voltage = voltage; + pmu_batteries[pmu_cur_battery].time_remaining = time; +} + +static void __pmac +done_battery_state_smart(struct adb_request* req) +{ + /* format: + * [0] : format of this structure (known: 3,4,5) + * [1] : flags + * + * format 3 & 4: + * + * [2] : charge + * [3] : max charge + * [4] : current + * [5] : voltage + * + * format 5: + * + * [2][3] : charge + * [4][5] : max charge + * [6][7] : current + * [8][9] : voltage + */ + + unsigned int bat_flags = 0; + int current; + unsigned int capa, max, voltage; + + if (req->reply[1] & 0x01) + pmu_power_flags |= PMU_PWR_AC_PRESENT; + else + pmu_power_flags &= ~PMU_PWR_AC_PRESENT; + + + if (req->reply[1] & 0x04) { + bat_flags |= PMU_BATT_PRESENT; + switch(req->reply[0]) { + case 3: + case 4: capa = req->reply[2]; + max = req->reply[3]; + current = *((signed char *)&req->reply[4]); + voltage = req->reply[5]; + break; + case 5: capa = (req->reply[2] << 8) | req->reply[3]; + max = (req->reply[4] << 8) | req->reply[5]; + current = *((signed short *)&req->reply[6]); + voltage = (req->reply[8] << 8) | req->reply[9]; + break; + default: + printk(KERN_WARNING "pmu.c : unrecognized battery info, len: %d, %02x %02x %02x %02x\n", + req->reply_len, req->reply[0], req->reply[1], req->reply[2], req->reply[3]); + break; + } + } else + capa = max = current = voltage = 0; + + if ((req->reply[1] & 0x01) && (current > 0)) + bat_flags |= PMU_BATT_CHARGING; + + pmu_batteries[pmu_cur_battery].flags = bat_flags; + pmu_batteries[pmu_cur_battery].charge = capa; + pmu_batteries[pmu_cur_battery].max_charge = max; + pmu_batteries[pmu_cur_battery].current = current; + pmu_batteries[pmu_cur_battery].voltage = voltage; + if (current) { + if ((req->reply[1] & 0x01) && (current > 0)) + pmu_batteries[pmu_cur_battery].time_remaining + = ((max-capa) * 3600) / current; + else + pmu_batteries[pmu_cur_battery].time_remaining + = (capa * 3600) / (-current); + } else + pmu_batteries[pmu_cur_battery].time_remaining = 0; + + pmu_cur_battery = (pmu_cur_battery + 1) % pmu_battery_count; +} + +static void __pmac +query_battery_state(void) +{ + if (!batt_req.complete) + return; + if (pmu_kind == PMU_OHARE_BASED) + pmu_request(&batt_req, done_battery_state_ohare, + 1, PMU_BATTERY_STATE); + else + pmu_request(&batt_req, done_battery_state_smart, + 2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1); +} + +#endif /* CONFIG_PMAC_PBOOK */ + +static int +proc_get_info(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char* p = page; + + p += sprintf(p, "PMU driver version : %d\n", PMU_DRIVER_VERSION); + p += sprintf(p, "PMU firmware version : %02x\n", pmu_version); +#ifdef CONFIG_PMAC_PBOOK + p += sprintf(p, "AC Power : %d\n", + ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0)); + p += sprintf(p, "Battery count : %d\n", pmu_battery_count); +#endif /* CONFIG_PMAC_PBOOK */ + + return p - page; +} + +#ifdef CONFIG_PMAC_PBOOK +static int +proc_get_batt(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int batnum = (int)data; + char *p = page; + + p += sprintf(p, "\n"); + p += sprintf(p, "flags : %08x\n", + pmu_batteries[batnum].flags); + p += sprintf(p, "charge : %d\n", + pmu_batteries[batnum].charge); + p += sprintf(p, "max_charge : %d\n", + pmu_batteries[batnum].max_charge); + p += sprintf(p, "current : %d\n", + pmu_batteries[batnum].current); + p += sprintf(p, "voltage : %d\n", + pmu_batteries[batnum].voltage); + p += sprintf(p, "time rem. : %d\n", + pmu_batteries[batnum].time_remaining); + + return p - page; +} +#endif /* CONFIG_PMAC_PBOOK */ + +static int +proc_read_options(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + +#ifdef CONFIG_PMAC_PBOOK + if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep) + p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup); +#endif /* CONFIG_PMAC_PBOOK */ + + return p - page; +} + +static int +proc_write_options(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char tmp[33]; + char *label, *val; + unsigned long fcount = count; + + if (!count) + return -EINVAL; + if (count > 32) + count = 32; + if (copy_from_user(tmp, buffer, count)) + return -EFAULT; + tmp[count] = 0; + + label = tmp; + while(*label == ' ') + label++; + val = label; + while(*val && (*val != '=')) { + if (*val == ' ') + *val = 0; + val++; + } + if ((*val) == 0) + return -EINVAL; + *(val++) = 0; + while(*val == ' ') + val++; +#ifdef CONFIG_PMAC_PBOOK + if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep) + if (!strcmp(label, "lid_wakeup")) + option_lid_wakeup = ((*val) == '1'); +#endif /* CONFIG_PMAC_PBOOK */ + return fcount; +} + #ifdef CONFIG_ADB /* Send an ADB command */ static int __openfirmware @@ -622,11 +958,7 @@ for (i = 0; i < nbytes; ++i) req->data[i] = va_arg(list, int); va_end(list); - if (pmu_data_len[req->data[0]][1] != 0) { - req->reply[0] = ADB_RET_OK; - req->reply_len = 1; - } else - req->reply_len = 0; + req->reply_len = 0; req->reply_expected = 0; return pmu_queue_request(req); } @@ -835,27 +1167,22 @@ spin_lock_irqsave(&pmu_lock, flags); ++disable_poll; - while ((intr = in_8(&via[IFR])) != 0) { + for (;;) { + intr = in_8(&via[IFR]) & (SR_INT | CB1_INT); + if (intr == 0) + break; if (++nloop > 1000) { printk(KERN_DEBUG "PMU: stuck in intr loop, " - "intr=%x pmu_state=%d\n", intr, pmu_state); + "intr=%x, ier=%x pmu_state=%d\n", + intr, in_8(&via[IER]), pmu_state); break; } out_8(&via[IFR], intr); if (intr & SR_INT) pmu_sr_intr(regs); - else if (intr & CB1_INT) + if (intr & CB1_INT) adb_int_pending = 1; } - /* This is not necessary except if synchronous ADB requests are done - * with interrupts off, which should not happen. Since I'm not sure - * this "wiring" will remain, I'm commenting it out for now. Please do - * not remove. -- BenH. - */ -#if 0 - if (gpio_reg && !pmu_suspended && (in_8(gpio_reg + 0x9) & 0x02) == 0) - adb_int_pending = 1; -#endif if (pmu_state == idle) { if (adb_int_pending) { @@ -866,9 +1193,8 @@ wait_for_ack(); send_byte(PMU_INT_ACK); adb_int_pending = 0; - } else if (current_req) { + } else if (current_req) pmu_start(); - } } --disable_poll; @@ -878,8 +1204,10 @@ static void __openfirmware gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) { - adb_int_pending = 1; - via_pmu_interrupt(0, 0, 0); + if ((in_8(gpio_reg + 0x9) & 0x02) == 0) { + adb_int_pending = 1; + via_pmu_interrupt(0, 0, 0); + } } static void __openfirmware @@ -1040,16 +1368,25 @@ adb_input(data+1, len-1, regs, 1); #endif /* CONFIG_ADB */ } - } else if (data[0] == 0x08 && len == 3) { - /* sound/brightness buttons pressed */ + } else { + /* Sound/brightness button pressed */ + if ((data[0] & PMU_INT_SNDBRT) && len == 3) { #ifdef CONFIG_PMAC_BACKLIGHT - set_backlight_level(data[1] >> 4); + set_backlight_level(data[1] >> 4); #endif - set_volume(data[2]); - } else { + } #ifdef CONFIG_PMAC_PBOOK - pmu_pass_intr(data, len); -#endif + /* Environement or tick interrupt, query batteries */ + if (pmu_battery_count && (data[0] & PMU_INT_TICK)) { + if ((--query_batt_timer) == 0) { + query_battery_state(); + query_batt_timer = BATTERY_POLLING_COUNT; + } + } else if (pmu_battery_count && (data[0] & PMU_INT_ENVIRONMENT)) + query_battery_state(); + if (data[0]) + pmu_pass_intr(data, len); +#endif /* CONFIG_PMAC_PBOOK */ } } @@ -1116,11 +1453,6 @@ pmu_poll(); } -static void __openfirmware -set_volume(int level) -{ -} - void __openfirmware pmu_restart(void) { @@ -1266,10 +1598,14 @@ * PCI devices which may get powered off when we sleep. */ static struct pci_save { +#ifndef HACKED_PCI_SAVE u16 command; u16 cache_lat; u16 intr; u32 rom_address; +#else + u32 config[16]; +#endif } *pbook_pci_saves; static int n_pbook_pci_saves; @@ -1293,14 +1629,24 @@ return; pci_for_each_dev(pd) { +#ifndef HACKED_PCI_SAVE pci_read_config_word(pd, PCI_COMMAND, &ps->command); pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat); pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr); pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address); +#else + int i; + for (i=1;i<16;i++) + pci_read_config_dword(pd, i<<4, &ps->config[i]); +#endif ++ps; } } +/* For this to work, we must take care of a few things: If gmac was enabled + * during boot, it will be in the pci dev list. If it's disabled at this point + * (and it will probably be), then you can't access it's config space. + */ static void __openfirmware pbook_pci_restore(void) { @@ -1310,7 +1656,13 @@ int j; pci_for_each_dev(pd) { +#ifdef HACKED_PCI_SAVE + int i; ps++; + for (i=2;i<16;i++) + pci_write_config_dword(pd, i<<4, ps->config[i]); + pci_write_config_dword(pd, 4, ps->config[1]); +#else if (ps->command == 0) continue; pci_read_config_word(pd, PCI_COMMAND, &cmd); @@ -1330,8 +1682,8 @@ ps->intr); pci_write_config_word(pd, PCI_COMMAND, ps->command); break; - /* other header types not restored at present */ } +#endif } } @@ -1370,7 +1722,7 @@ } mdelay(50); } -#endif /* DEBUG_SLEEP */ +#endif /* * Put the powerbook to sleep. @@ -1403,6 +1755,15 @@ out_8(&via[IER], IER_SET | SR_INT | CB1_INT); } +static inline void wakeup_decrementer(void) +{ + set_dec(tb_ticks_per_jiffy); + /* No currently-supported powerbook has a 601, + * so use get_tbl, not native + */ + last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); +} + #define GRACKLE_PM (1<<7) #define GRACKLE_DOZE (1<<5) #define GRACKLE_NAP (1<<4) @@ -1434,7 +1795,11 @@ * BenH: Moved to _after_ sleep request and changed video * drivers to vmalloc() during sleep request. This way, all * vmalloc's are done before actual sleep of block drivers */ - fsync_dev(0); + sys_sync(); + + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + (HZ/2); time_before(jiffies, wait); ) + mb(); /* Sleep can fail now. May not be very robust but useful for debugging */ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); @@ -1443,13 +1808,9 @@ return -EBUSY; } - /* Give the disks a little time to actually finish writing */ - for (wait = jiffies + (HZ/2); time_before(jiffies, wait); ) - mb(); - /* Wait for completion of async backlight requests */ while (!bright_req_1.complete || !bright_req_2.complete || - !bright_req_3.complete) + !bright_req_3.complete || !batt_req.complete) pmu_poll(); /* Turn off various things. Darwin does some retry tests here... */ @@ -1495,7 +1856,7 @@ /* The VIA is supposed not to be restored correctly*/ save_via_state(); /* We shut down some HW */ - feature_prepare_for_sleep(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); pci_read_config_word(grackle, 0x70, &pmcr1); /* Apparently, MacOS uses NAP mode for Grackle ??? */ @@ -1512,7 +1873,7 @@ pci_write_config_word(grackle, 0x70, pmcr1); /* Make sure the PMU is idle */ - feature_wake_up(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); restore_via_state(); /* Restore L2 cache */ @@ -1522,11 +1883,6 @@ /* Restore userland MMU context */ set_context(current->active_mm->context, current->active_mm->pgd); - /* Re-enable DEC interrupts and kick DEC */ - asm volatile("mtdec %0" : : "r" (0x7fffffff)); - sti(); - asm volatile("mtdec %0" : : "r" (0x10000000)); - /* Power things up */ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); while (!req.complete) @@ -1558,6 +1914,10 @@ /* Leave some time for HW to settle down */ mdelay(100); + /* Restart jiffies & scheduling */ + wakeup_decrementer(); + sti(); + /* Notify drivers */ broadcast_wake(); @@ -1571,7 +1931,7 @@ struct adb_request req; int ret, timeout; - if (!feature_can_sleep()) { + if (!can_sleep) { printk(KERN_ERR "Sleep mode not supported on this machine\n"); return -ENOSYS; } @@ -1589,7 +1949,11 @@ * BenH: Moved to _after_ sleep request and changed video * drivers to vmalloc() during sleep request. This way, all * vmalloc's are done before actual sleep of block drivers */ - fsync_dev(0); + sys_sync(); + + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + HZ; time_before(jiffies, wait); ) + mb(); /* Sleep can fail now. May not be very robust but useful for debugging */ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); @@ -1597,14 +1961,9 @@ printk("pmu: sleep failed\n"); return -EBUSY; } - - /* Give the disks a little time to actually finish writing */ - for (wait = jiffies + HZ; time_before(jiffies, wait); ) - mb(); - /* Wait for completion of async backlight requests */ while (!bright_req_1.complete || !bright_req_2.complete || - !bright_req_3.complete) + !bright_req_3.complete || !batt_req.complete) pmu_poll(); /* Tell PMU what events will wake us up */ @@ -1614,7 +1973,8 @@ pmu_poll(); pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS, - 0, PMU_PWR_WAKEUP_KEY | PMU_PWR_WAKEUP_LID_OPEN); + 0, PMU_PWR_WAKEUP_KEY | + (option_lid_wakeup ? PMU_PWR_WAKEUP_LID_OPEN : 0)); while (!req.complete) pmu_poll(); @@ -1651,10 +2011,12 @@ /* Save the state of PCI config space for some slots */ //pbook_pci_save(); - /* Ask the PMU to put us to sleep */ - pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); - while (!req.complete && pmu_state != idle) - pmu_poll(); + if (!__fake_sleep) { + /* Ask the PMU to put us to sleep */ + pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!req.complete && pmu_state != idle) + pmu_poll(); + } out_8(&via[B], in_8(&via[B]) | TREQ); wait_for_ack(); @@ -1666,13 +2028,16 @@ * talk to the PMU after this, so I moved it to _after_ sending the * sleep command to it. Still need to be checked. */ - feature_prepare_for_sleep(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); /* Call low-level ASM sleep handler */ - low_sleep_handler(); + if (__fake_sleep) + mdelay(5000); + else + low_sleep_handler(); /* Restore Apple core ASICs state */ - feature_wake_up(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); /* Restore VIA */ restore_via_state(); @@ -1694,11 +2059,6 @@ /* Restore userland MMU context */ set_context(current->active_mm->context, current->active_mm->pgd); - /* Re-enable DEC interrupts and kick DEC */ - asm volatile("mtdec %0" : : "r" (0x7fffffff)); - sti(); - asm volatile("mtdec %0" : : "r" (0x10000000)); - /* Tell PMU we are ready */ pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); while (!req.complete) @@ -1725,6 +2085,10 @@ /* Leave some time for HW to settle down */ mdelay(100); + /* Restart jiffies & scheduling */ + wakeup_decrementer(); + sti(); + /* Notify drivers */ broadcast_wake(); @@ -1764,7 +2128,11 @@ * BenH: Moved to _after_ sleep request and changed video * drivers to vmalloc() during sleep request. This way, all * vmalloc's are done before actual sleep of block drivers */ - fsync_dev(0); + sys_sync(); + + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) + mb(); /* Sleep can fail now. May not be very robust but useful for debugging */ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); @@ -1773,13 +2141,9 @@ return -EBUSY; } - /* Give the disks a little time to actually finish writing */ - for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) - mb(); - /* Wait for completion of async backlight requests */ while (!bright_req_1.complete || !bright_req_2.complete || - !bright_req_3.complete) + !bright_req_3.complete || !batt_req.complete) pmu_poll(); /* Disable all interrupts except pmu */ @@ -1811,6 +2175,8 @@ while (!sleep_req.complete) mb(); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); + /* displacement-flush the L2 cache - necessary? */ for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000) i = *(volatile int *)p; @@ -1825,20 +2191,23 @@ /* OK, we're awake again, start restoring things */ out_be32(mem_ctrl_sleep, 0x3f); + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); pbook_pci_restore(); /* wait for the PMU interrupt sequence to complete */ while (asleep) mb(); - /* Re-enable DEC interrupts and kick DEC */ - asm volatile("mtdec %0" : : "r" (0x7fffffff)); - sti(); - asm volatile("mtdec %0" : : "r" (0x10000000)); - /* reenable interrupts */ pmac_sleep_restore_intrs(); + /* Leave some time for HW to settle down */ + mdelay(100); + + /* Restart jiffies & scheduling */ + wakeup_decrementer(); + sti(); + /* Notify drivers */ broadcast_wake(); @@ -1877,6 +2246,7 @@ spin_lock_irqsave(&all_pvt_lock, flags); for (list = &all_pmu_pvt; (list = list->next) != &all_pmu_pvt; ) { pp = list_entry(list, struct pmu_private, list); + spin_lock(&pp->lock); i = pp->rb_put + 1; if (i >= RB_SIZE) i = 0; @@ -1887,6 +2257,7 @@ pp->rb_put = i; wake_up_interruptible(&pp->wait); } + spin_unlock(&pp->lock); } spin_unlock_irqrestore(&all_pvt_lock, flags); } @@ -1914,6 +2285,7 @@ { struct pmu_private *pp = file->private_data; DECLARE_WAITQUEUE(wait, current); + unsigned long flags; int ret; if (count < 1 || pp == 0) @@ -1922,38 +2294,41 @@ if (ret) return ret; + spin_lock_irqsave(&pp->lock, flags); add_wait_queue(&pp->wait, &wait); current->state = TASK_INTERRUPTIBLE; for (;;) { ret = -EAGAIN; - spin_lock(&pp->lock); if (pp->rb_get != pp->rb_put) { int i = pp->rb_get; struct rb_entry *rp = &pp->rb_buf[i]; ret = rp->len; + spin_unlock_irqrestore(&pp->lock, flags); if (ret > count) ret = count; if (ret > 0 && copy_to_user(buf, rp->data, ret)) ret = -EFAULT; if (++i >= RB_SIZE) i = 0; + spin_lock_irqsave(&pp->lock, flags); pp->rb_get = i; } - spin_unlock(&pp->lock); if (ret >= 0) break; - if (file->f_flags & O_NONBLOCK) break; ret = -ERESTARTSYS; if (signal_pending(current)) break; + spin_unlock_irqrestore(&pp->lock, flags); schedule(); + spin_lock_irqsave(&pp->lock, flags); } current->state = TASK_RUNNING; remove_wait_queue(&pp->wait, &wait); - + spin_unlock_irqrestore(&pp->lock, flags); + return ret; } @@ -1967,14 +2342,15 @@ { struct pmu_private *pp = filp->private_data; unsigned int mask = 0; - + unsigned long flags; + if (pp == 0) return 0; poll_wait(filp, &pp->wait, wait); - spin_lock(&pp->lock); + spin_lock_irqsave(&pp->lock, flags); if (pp->rb_get != pp->rb_put) mask |= POLLIN; - spin_unlock(&pp->lock); + spin_unlock_irqrestore(&pp->lock, flags); return mask; } @@ -2023,7 +2399,7 @@ sleep_in_progress = 0; return error; case PMU_IOC_CAN_SLEEP: - return put_user(feature_can_sleep(), (__u32 *)arg); + return put_user((u32)can_sleep, (__u32 *)arg); #ifdef CONFIG_PMAC_BACKLIGHT /* Backlight should have its own device or go via @@ -2153,5 +2529,8 @@ EXPORT_SYMBOL(pmu_register_sleep_notifier); EXPORT_SYMBOL(pmu_unregister_sleep_notifier); EXPORT_SYMBOL(pmu_enable_irled); +EXPORT_SYMBOL(pmu_battery_count); +EXPORT_SYMBOL(pmu_batteries); +EXPORT_SYMBOL(pmu_power_flags); #endif /* CONFIG_PMAC_PBOOK */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/macintosh/via-pmu68k.c linux-2.5/drivers/macintosh/via-pmu68k.c --- linux-2.5.5/drivers/macintosh/via-pmu68k.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/macintosh/via-pmu68k.c Fri Mar 1 15:07:38 2002 @@ -916,7 +916,7 @@ /* Sync the disks. */ /* XXX It would be nice to have some way to ensure that * nobody is dirtying any new buffers while we wait. */ - fsync_dev(0); + sys_sync(); /* Turn off the display backlight */ save_backlight = backlight_enabled; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/md/lvm-fs.c linux-2.5/drivers/md/lvm-fs.c --- linux-2.5.5/drivers/md/lvm-fs.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/md/lvm-fs.c Fri Mar 1 19:18:06 2002 @@ -276,12 +276,12 @@ sz += sprintf(page + sz, "number: %u\n", lv->u.lv_number); sz += sprintf(page + sz, "open: %u\n", lv->u.lv_open); sz += sprintf(page + sz, "allocation: %u\n", lv->u.lv_allocation); - if(lv->u.lv_stripes > 1) { - sz += sprintf(page + sz, "stripes: %u\n", - lv->u.lv_stripes); - sz += sprintf(page + sz, "stripesize: %u\n", - lv->u.lv_stripesize); - } + if(lv->u.lv_stripes > 1) { + sz += sprintf(page + sz, "stripes: %u\n", + lv->u.lv_stripes); + sz += sprintf(page + sz, "stripesize: %u\n", + lv->u.lv_stripesize); + } sz += sprintf(page + sz, "device: %02u:%02u\n", major(lv->u.lv_dev), minor(lv->u.lv_dev)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/md/lvm.c linux-2.5/drivers/md/lvm.c --- linux-2.5.5/drivers/md/lvm.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/md/lvm.c Fri Mar 1 15:07:38 2002 @@ -878,9 +878,10 @@ P_IOCTL("BLKFLSBUF\n"); - fsync_dev(inode->i_rdev); + fsync_bdev(inode->i_bdev); invalidate_buffers(inode->i_rdev); break; + case HDIO_GETGEO: /* get disk geometry */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/md/md.c linux-2.5/drivers/md/md.c --- linux-2.5.5/drivers/md/md.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/md/md.c Fri Mar 1 15:07:38 2002 @@ -890,7 +890,8 @@ static int write_disk_sb(mdk_rdev_t * rdev) { - struct address_space *mapping = rdev->bdev->bd_inode->i_mapping; + struct block_device *bdev = rdev->bdev; + struct address_space *mapping = bdev->bd_inode->i_mapping; struct page *page; unsigned offs; int error; @@ -929,7 +930,7 @@ } printk(KERN_INFO "(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset); - fsync_dev(dev); + fsync_bdev(bdev); page = grab_cache_page(mapping, sb_offset/(PAGE_CACHE_SIZE/BLOCK_SIZE)); offs = sb_offset % (PAGE_CACHE_SIZE/BLOCK_SIZE); if (!page) @@ -946,7 +947,7 @@ UnlockPage(page); wait_on_page(page); page_cache_release(page); - fsync_dev(dev); + fsync_bdev(bdev); skip: return 0; unlock: @@ -1007,6 +1008,11 @@ struct list_head *tmp; mdk_rdev_t *rdev; + if (!mddev->sb_dirty) { + printk("hm, md_update_sb() called without ->sb_dirty == 1, from %p.\n", __builtin_return_address(0)); + return 0; + } + mddev->sb_dirty = 0; repeat: mddev->sb->utime = CURRENT_TIME; if (!(++mddev->sb->events_lo)) @@ -1727,6 +1733,7 @@ } mddev->sb->state &= ~(1 << MD_SB_CLEAN); + mddev->sb_dirty = 1; md_update_sb(mddev); /* @@ -1843,6 +1850,7 @@ printk(KERN_INFO "md: marking sb clean...\n"); mddev->sb->state |= 1 << MD_SB_CLEAN; } + mddev->sb_dirty = 1; md_update_sb(mddev); } if (ro) @@ -2466,7 +2474,6 @@ mddev->sb->working_disks++; mddev->sb_dirty = 1; - md_update_sb(mddev); /* @@ -3502,6 +3509,8 @@ continue; if (sb->active_disks == sb->raid_disks) continue; + if (mddev->sb_dirty) + md_update_sb(mddev); if (!sb->spare_disks) { printk(KERN_ERR "md%d: no spare disk to reconstruct array! " "-- continuing in degraded mode\n", mdidx(mddev)); @@ -3767,7 +3776,7 @@ printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor); return 0; } else if (md_setup_args.device_names[minor]) { - printk(KERN_WARNING "md: md=%d, Specified more then once. " + printk(KERN_WARNING "md: md=%d, Specified more than once. " "Replacing previous definition.\n", minor); } switch (get_option(&str, &level)) { /* RAID Personality */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/md/multipath.c linux-2.5/drivers/md/multipath.c --- linux-2.5.5/drivers/md/multipath.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/md/multipath.c Wed Jan 16 18:27:10 2002 @@ -703,11 +703,8 @@ md_spin_unlock_irqrestore(&retry_list_lock, flags); mddev = mp_bh->mddev; - if (mddev->sb_dirty) { - printk(KERN_INFO "dirty sb detected, updating.\n"); - mddev->sb_dirty = 0; + if (mddev->sb_dirty) md_update_sb(mddev); - } bh = &mp_bh->bh_req; dev = bh->b_dev; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/md/raid1.c linux-2.5/drivers/md/raid1.c --- linux-2.5.5/drivers/md/raid1.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/md/raid1.c Thu Feb 14 02:57:58 2002 @@ -850,7 +850,7 @@ *d = failed_desc; - if (kdev_none(sdisk->dev)) + if (kdev_none (sdisk->dev)) sdisk->used_slot = 0; /* * this really activates the spare. @@ -1078,11 +1078,8 @@ mddev = r1_bio->mddev; conf = mddev_to_conf(mddev); - if (mddev->sb_dirty) { - printk(KERN_INFO "raid1: dirty sb detected, updating.\n"); - mddev->sb_dirty = 0; + if (mddev->sb_dirty) md_update_sb(mddev); - } bio = r1_bio->master_bio; switch(r1_bio->cmd) { case SPECIAL: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/md/raid5.c linux-2.5/drivers/md/raid5.c --- linux-2.5.5/drivers/md/raid5.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/md/raid5.c Wed Jan 16 18:27:10 2002 @@ -1278,10 +1278,8 @@ handled = 0; - if (mddev->sb_dirty) { - mddev->sb_dirty = 0; + if (mddev->sb_dirty) md_update_sb(mddev); - } md_spin_lock_irq(&conf->device_lock); while (1) { struct list_head *first; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/radio/miropcm20-radio.c linux-2.5/drivers/media/radio/miropcm20-radio.c --- linux-2.5.5/drivers/media/radio/miropcm20-radio.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/media/radio/miropcm20-radio.c Fri Feb 15 15:45:03 2002 @@ -22,7 +22,7 @@ #include #include #include -#include "../../sound/aci.h" +#include "../../../sound/oss/aci.h" #include "miropcm20-rds-core.h" static int users = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/radio/miropcm20-rds-core.c linux-2.5/drivers/media/radio/miropcm20-rds-core.c --- linux-2.5.5/drivers/media/radio/miropcm20-rds-core.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/media/radio/miropcm20-rds-core.c Fri Feb 15 15:45:03 2002 @@ -21,7 +21,7 @@ #include #include #include -#include "../../sound/aci.h" +#include "../../../sound/oss/aci.h" #include "miropcm20-rds-core.h" #define DEBUG 0 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/radio/radio-gemtek-pci.c linux-2.5/drivers/media/radio/radio-gemtek-pci.c --- linux-2.5.5/drivers/media/radio/radio-gemtek-pci.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/media/radio/radio-gemtek-pci.c Mon Jan 14 23:44:46 2002 @@ -221,6 +221,7 @@ case VIDIOCGTUNER: { struct video_tuner t; + int signal; if ( copy_from_user( &t, arg, sizeof( struct video_tuner ) ) ) return -EFAULT; @@ -228,11 +229,12 @@ if ( t.tuner ) return -EINVAL; + signal = gemtek_pci_getsignal( card ); t.rangelow = GEMTEK_PCI_RANGE_LOW; t.rangehigh = GEMTEK_PCI_RANGE_HIGH; - t.flags = VIDEO_TUNER_LOW; + t.flags = VIDEO_TUNER_LOW | (7 << signal) ; t.mode = VIDEO_MODE_AUTO; - t.signal = 0xFFFF * gemtek_pci_getsignal( card ); + t.signal = 0xFFFF * signal; strcpy( t.name, "FM" ); if ( copy_to_user( arg, &t, sizeof( struct video_tuner ) ) ) @@ -282,6 +284,7 @@ a.flags |= VIDEO_AUDIO_MUTABLE; a.volume = 1; a.step = 65535; + a.mode = (1 << gemtek_pci_getsignal( card )); strcpy( a.name, "Radio" ); if ( copy_to_user( arg, &a, sizeof( struct video_audio ) ) ) @@ -424,7 +427,7 @@ name: "gemtek_pci", id_table: gemtek_pci_id, probe: gemtek_pci_probe, - remove: gemtek_pci_remove + remove: __devexit_p(gemtek_pci_remove), }; static int __init gemtek_pci_init_module( void ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/radio/radio-maxiradio.c linux-2.5/drivers/media/radio/radio-maxiradio.c --- linux-2.5.5/drivers/media/radio/radio-maxiradio.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/media/radio/radio-maxiradio.c Thu Dec 13 16:32:36 2001 @@ -376,7 +376,7 @@ name: "radio-maxiradio", id_table: maxiradio_pci_tbl, probe: maxiradio_init_one, - remove: maxiradio_remove_one, + remove: __devexit_p(maxiradio_remove_one), }; int __init maxiradio_radio_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/radio/radio-sf16fmi.c linux-2.5/drivers/media/radio/radio-sf16fmi.c --- linux-2.5.5/drivers/media/radio/radio-sf16fmi.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/media/radio/radio-sf16fmi.c Sun Jan 20 12:45:42 2002 @@ -297,6 +297,7 @@ while (id_table[i].card_vendor != 0 && dev == NULL) { dev = isapnp_find_dev(NULL, id_table[i].vendor, id_table[i].function, NULL); + i++; } if (!dev) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/Config.help linux-2.5/drivers/media/video/Config.help --- linux-2.5.5/drivers/media/video/Config.help Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/media/video/Config.help Fri Feb 15 15:55:23 2002 @@ -54,6 +54,16 @@ Say Y here to include support for the Iomega Buz video card. There is a Buz/Linux homepage at . +CONFIG_VIDEO_ZORAN_DC10 + Say Y to support the Pinnacle Systems Studio DC10 plus TV/Video + card. Linux page at + . Vendor + page at . + +CONFIG_VIDEO_ZORAN_LML33 + Say Y here to support the Linux Media Labs LML33 TV/Video card. + Resources page is at . + CONFIG_VIDEO_ZR36120 Support for ZR36120/ZR36125 based frame grabber/overlay boards. This includes the Victor II, WaveWatcher, Video Wonder, Maxi-TV, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/bttv-cards.c linux-2.5/drivers/media/video/bttv-cards.c --- linux-2.5.5/drivers/media/video/bttv-cards.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/media/video/bttv-cards.c Sun Mar 3 17:54:35 2002 @@ -39,9 +39,9 @@ #include "tuner.h" /* fwd decl */ +static void boot_msp34xx(struct bttv *btv, int pin); static void hauppauge_eeprom(struct bttv *btv); static void avermedia_eeprom(struct bttv *btv); - static void init_PXC200(struct bttv *btv); #if 0 static void init_tea5757(struct bttv *btv); @@ -55,6 +55,9 @@ static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set); static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set); static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set); +static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set); +static void windvr_audio(struct bttv *btv, struct video_audio *v, int set); +static void rv605_muxsel(struct bttv *btv, unsigned int input); /* config variables */ static int triton1=0; @@ -77,7 +80,8 @@ MODULE_PARM_DESC(triton1,"set ETBF pci config bit " "[enable bug compatibility for triton1 + others]"); MODULE_PARM(vsfx,"i"); -MODULE_PARM_DESC(vsfx,"set VSFX pci config bit [yet another chipset flaw workaround]"); +MODULE_PARM_DESC(vsfx,"set VSFX pci config bit " + "[yet another chipset flaw workaround]"); MODULE_PARM(no_overlay,"i"); MODULE_PARM(card,"1-4i"); MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list"); @@ -151,7 +155,7 @@ { 0x00041461, BTTV_AVERMEDIA98, "AVerMedia TVCapture 98" }, { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" }, - { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master" }, + { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master (CPH060)" }, { 0x1117153b, BTTV_TERRATVALUE, "Terratec TValue" }, { 0x1118153b, BTTV_TERRATVALUE, "Terratec TValue" }, @@ -161,6 +165,7 @@ { 0x1127153b, BTTV_TERRATV, "Terratec TV+" }, { 0x1134153b, BTTV_TERRATVALUE, "Terratec TValue" }, { 0x1135153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, + { 0x5018153b, BTTV_TERRATVALUE, "Terratec TValue" }, { 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, { 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, @@ -168,12 +173,14 @@ { 0x401615b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, { 0x010115cb, BTTV_GMV1, "AG GMV1" }, - { 0x010114c7, BTTV_MODTEC_205, "Modular Technology PCTV" }, + { 0x010114c7, BTTV_MODTEC_205, "Modular Technology MM205 PCTV" }, { 0x18501851, BTTV_CHRONOS_VS2, "Flyvideo 98 (LR50)/ Chronos Video Shuttle II" }, { 0x18511851, BTTV_FLYVIDEO98EZ, "Flyvideo 98EZ (LR51)/ CyberMail AV" }, { 0x18521852, BTTV_TYPHOON_TVIEW, "Flyvideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" }, { 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" }, { 0x217d6606, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0x03116000, BTTV_SENSORAY311, "Sensoray 311" }, + { 0x00790e11, BTTV_WINDVR, "Canopus WinDVR PCI" }, { 0, -1, NULL } }; @@ -276,8 +283,8 @@ },{ /* ---- card 0x08 ---------------------------------- */ - name: "Fly Video II (Bt848)", - video_inputs: 3, + name: "FlyVideo II (Bt848) LR26", + video_inputs: 4, audio_inputs: 1, tuner: 0, svhs: 2, @@ -285,9 +292,10 @@ muxsel: { 2, 3, 1, 1}, audiomux: { 0, 0xc00, 0x800, 0x400, 0xc00, 0}, needs_tvaudio: 1, + pll: PLL_28, tuner_type: -1, },{ - name: "TurboTV", + name: "IXMicro TurboTV", video_inputs: 3, audio_inputs: 1, tuner: 0, @@ -346,14 +354,14 @@ pll: PLL_28, tuner_type: -1, },{ - name: "Aimslab VHX", + name: "Aimslab Video Highway Xtreme (VHX)", video_inputs: 3, audio_inputs: 1, tuner: 0, svhs: 2, gpiomask: 7, muxsel: { 2, 3, 1, 1}, - audiomux: { 0, 1, 2, 3, 4}, + audiomux: { 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */ needs_tvaudio: 1, tuner_type: -1, },{ @@ -393,6 +401,7 @@ needs_tvaudio: 1, tuner_type: -1, audio_hook: winview_audio, + has_radio: 1, },{ name: "AVEC Intercapture", video_inputs: 3, @@ -438,7 +447,7 @@ pll: PLL_28, tuner_type: TUNER_PHILIPS_PAL_I, },{ - name: "Phoebe Tv Master + FM", + name: "Phoebe Tv Master + FM (CPH050)", video_inputs: 3, audio_inputs: 1, tuner: 0, @@ -752,6 +761,7 @@ gpiomask: 0x1f0000, muxsel: { 2, 3, 1, 1}, audiomux: { 0xe2ffff, 0xebffff, 0, 0, 0xe0ffff, 0xe2ffff }, + needs_tvaudio: 1, no_msp34xx: 1, pll: PLL_35, tuner_type: 1, @@ -788,7 +798,7 @@ video_inputs: 4, audio_inputs: 1, tuner: 0, - svhs: 2, + svhs: 3, gpiomask: 0xAA0000, muxsel: { 2,3,1,1 }, audiomux: { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000 }, @@ -860,7 +870,7 @@ },{ /* Miguel Angel Alvarez old Easy TV BT848 version (model CPH031) */ - name: "BESTBUY Easy TV", + name: "BESTBUY Easy TV (CPH031)", video_inputs: 4, audio_inputs: 1, tuner: 0, @@ -890,7 +900,7 @@ /* This is the ultimate cheapo capture card * just a BT848A on a small PCB! * Steve Hosgood */ - name: "GrandTec 'Grand Video Capture'", + name: "GrandTec 'Grand Video Capture' (Bt848)", video_inputs: 2, audio_inputs: 0, tuner: -1, @@ -904,7 +914,7 @@ tuner_type: -1, },{ /* Daniel Herrington */ - name: "Phoebe TV Master Only (No FM)", + name: "Phoebe TV Master Only (No FM) CPH060", video_inputs: 3, audio_inputs: 1, tuner: 0, @@ -917,7 +927,7 @@ tuner_type: TUNER_TEMIC_4036FY5_NTSC, },{ /* Matti Mottus */ - name: "TV Capturer", + name: "TV Capturer (CPH03X)", video_inputs: 4, audio_inputs: 1, tuner: 0, @@ -931,7 +941,7 @@ /* ---- card 0x3c ---------------------------------- */ /* Philip Blundell */ - name: "MM100PCTV", + name: "Modular Technology MM100PCTV", video_inputs: 2, audio_inputs: 2, gpiomask: 11, @@ -977,7 +987,7 @@ tuner: 0, svhs: 2, gpiomask: 0xf03f, - muxsel: { 2, 3, 0, 1}, + muxsel: { 2, 3, 1, 0 }, audiomux: { 0xbffe, 0, 0xbfff, 0, 0xbffe}, pll: PLL_28, tuner_type: TUNER_TEMIC_4006FN5_MULTI_PAL, @@ -1005,7 +1015,13 @@ svhs: 2, gpiomask: 0x18e0, muxsel: { 2, 3, 0, 1}, - audiomux: { 0,0x18e0,0x1000,0x1000,0x1080, 0x1080 }, + /* Radio changed from 1e80 to 0x800 to make + Flyvideo2000S in .hu happy (gm)*/ + /* -dk-???: set mute=0x1800 for tda9874h daughterboard */ + audiomux: { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 }, + audio_hook: fv2000s_audio, + no_msp34xx: 1, + no_tda9875: 1, needs_tvaudio: 1, pll: PLL_28, tuner_type: 5, @@ -1047,11 +1063,12 @@ tuner: 0, svhs: -1, gpiomask: 0x4f8a00, - // 0x100000: 1=MSP enabled (0=disable again) - // 0x010000: somehow influences tuner picture quality (?) - audiomux: {0x947fff, 0x987fff,0x947fff,0x947fff}, - //tvtuner, radio, external,internal,mute,stereo - muxsel: { 2, 3 ,0 ,1}, /* tuner, Composit, SVid, Composit-on-Svid-adapter*/ + // 0x100000: 1=MSP enabled (0=disable again) + // 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) + audiomux: {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff}, + // tvtuner, radio, external,internal, mute, stereo + /* tuner, Composit, SVid, Composit-on-Svid-adapter*/ + muxsel: { 2, 3 ,0 ,1}, tuner_type: TUNER_MT2032, pll: PLL_28, has_radio: 1, @@ -1106,8 +1123,84 @@ tuner_type: -1, audio_hook: pvbt878p9b_audio, has_radio: 1, -} -}; +},{ + /* Clay Kunz */ + /* you must jumper JP5 for the card to work */ + name: "Sensoray 311", + video_inputs: 5, + audio_inputs: 0, + tuner: -1, + svhs: 4, + gpiomask: 0, + muxsel: { 2, 3, 1, 0, 0}, + audiomux: { 0 }, + needs_tvaudio: 0, + tuner_type: -1, +},{ + /* Miguel Freitas */ + name: "RemoteVision MX (RV605)", + video_inputs: 16, + audio_inputs: 0, + tuner: 0, + svhs: 0, + gpiomask: 0x00, + gpiomask2: 0x07ff, + muxsel: { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03, + 0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 }, + no_msp34xx: 1, + no_tda9875: 1, + tuner_type: -1, + muxsel_hook: rv605_muxsel, +},{ + name: "Powercolor MTV878/ MTV878R/ MTV878F", + video_inputs: 3, + audio_inputs: 2, + svhs: 2, + gpiomask: 0x1C800F, // Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset + muxsel: { 2, 1, 1, }, + audiomux: { 0, 1, 2, 2, 4 }, + needs_tvaudio: 0, + tuner_type: TUNER_PHILIPS_PAL, + pll: PLL_28, + has_radio: 1, +},{ + +/* ---- card 0x4c ---------------------------------- */ + /* Masaki Suzuki */ + name: "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)", + video_inputs: 3, + audio_inputs: 1, + tuner: 0, + svhs: 2, + gpiomask: 0x140007, + muxsel: { 2, 3, 1, 1 }, + audiomux: { 0, 1, 2, 3, 4, 0 }, + tuner_type: TUNER_PHILIPS_NTSC, + audio_hook: windvr_audio, +},{ + name: "GrandTec Multi Capture Card (Bt878)", + video_inputs: 4, + audio_inputs: 0, + tuner: -1, + svhs: -1, + gpiomask: 0, + muxsel: { 2, 3, 1, 0 }, + audiomux: { 0 }, + needs_tvaudio: 0, + no_msp34xx: 1, + pll: PLL_28, + tuner_type: -1, +},{ + /* http://www.aopen.com/products/video/va1000.htm */ + name: "AOPEN VA1000", + video_inputs: 3, /* coax, AV, s-vid */ + audio_inputs: 1, + tuner: 0, + tuner_type: TUNER_LG_PAL, /* actually TP18PSB12P (PAL B/G) */ + audiomux: { 2, 0, 0, 0 }, + muxsel: { 2, 3, 1, 0 }, + pll: PLL_28, +}}; const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard)); @@ -1195,12 +1288,58 @@ * (most) board specific initialisations goes here */ +static void flyvideo_gpio(struct bttv *btv) +{ + int gpio,outbits; + int tuner=-1,ttype; + + outbits = btread(BT848_GPIO_OUT_EN); + btwrite(0x00, BT848_GPIO_OUT_EN); + udelay(8); // without this we would see the 0x1800 mask + gpio=btread(BT848_GPIO_DATA); + btwrite(outbits, BT848_GPIO_OUT_EN); + // all cards provide GPIO info, some have an additional eeprom + + // lowest 3 bytes are remote control codes (no handshake needed) + ttype=(gpio&0x0f0000)>>16; + switch(ttype) { + case 0: tuner=4; // None + break; + case 4: tuner=5; // Philips PAL + break; + case 6: tuner=37; // LG PAL (newer TAPC series) + break; + case 0xC: tuner=3; // Philips SECAM(+PAL) + break; + default: + printk(KERN_INFO "bttv%d: flyvideo_gpio: unknown tuner type.\n", btv->nr); + } + + printk(KERN_INFO "bttv%d: Flyvideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", + btv->nr, + gpio&0x400000? "yes":"no", + gpio&0x800000? "yes":"no", tuner, gpio); + + btv->tuner_type = tuner; + btv->has_radio = gpio&0x400000? 1:0; +} + int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1, 14,2,17,1, 4,1,4,3, 1,2,16,1, 4,4,4,4 }; int miro_fmtuner[] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,1,1, 1,1,1,0, 0,0,0,0, 0,0,0,0 }; -void __devinit bttv_init_card(struct bttv *btv) +/* initialization part one -- before registering i2c bus */ +void __devinit bttv_init_card1(struct bttv *btv) +{ + if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) + boot_msp34xx(btv,5); + if (btv->type == BTTV_VOODOOTV_FM) + boot_msp34xx(btv,20); +} + +/* initialization part one -- after registering i2c bus */ +void __devinit bttv_init_card2(struct bttv *btv) { /* miro/pinnacle */ if (btv->type == BTTV_MIRO || @@ -1246,6 +1385,15 @@ #endif } + if (btv->type == BTTV_FLYVIDEO_98 || + btv->type == BTTV_FLYVIDEO || + btv->type == BTTV_TYPHOON_TVIEW || + btv->type == BTTV_CHRONOS_VS2 || + btv->type == BTTV_FLYVIDEO_98FM || + btv->type == BTTV_FLYVIDEO2000 || + btv->type == BTTV_FLYVIDEO98EZ) + flyvideo_gpio(btv); + if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) { /* pick up some config infos from the eeprom */ bttv_readee(btv,eeprom_data,0xa0); @@ -1449,22 +1597,24 @@ btv->tuner_type, radio ? "yes" : "no"); } -// AVermedia specific stuff... -// from bktr_card.c + +/* ----------------------------------------------------------------------- */ +/* AVermedia specific stuff, from bktr_card.c */ + int tuner_0_table[] = { TUNER_PHILIPS_NTSC, TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL, TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL}; -/* +#if 0 int tuner_0_fm_table[] = { PHILIPS_FR1236_NTSC, PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL, PHILIPS_FR1236_SECAM, PHILIPS_FR1236_SECAM, PHILIPS_FR1236_SECAM, PHILIPS_FR1216_PAL}; -*/ +#endif int tuner_1_table[] = { TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL, @@ -1475,11 +1625,12 @@ static void __devinit avermedia_eeprom(struct bttv *btv) { - int tuner_make,tuner_tv_fm,tuner_format,tuner=0; + int tuner_make,tuner_tv_fm,tuner_format,tuner=0,remote; tuner_make = (eeprom_data[0x41] & 0x7); tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3; tuner_format = (eeprom_data[0x42] & 0xf0) >> 4; + remote = (eeprom_data[0x42] & 0x01); if (tuner_make == 0 || tuner_make == 2) if(tuner_format <=9) @@ -1492,11 +1643,32 @@ btv->nr,eeprom_data[0x41],eeprom_data[0x42]); if(tuner) { btv->tuner_type=tuner; - printk("%d\n",tuner); + printk("%d",tuner); } else - printk("Unknown type\n"); + printk("Unknown type"); + printk(" radio:%s remote control:%s\n", + tuner_tv_fm?"yes":"no", + remote?"yes":"no"); } +/* used on Voodoo TV/FM (Voodoo 200), S0 wired to 0x10000 */ +void bttv_tda9880_setnorm(struct bttv *btv, int norm) +{ + // fix up our card entry + if(norm==VIDEO_MODE_NTSC) { + bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x957fff; + bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x957fff; + dprintk("bttv_tda9880_setnorm to NTSC\n"); + } + else { + bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x947fff; + bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x947fff; + dprintk("bttv_tda9880_setnorm to PAL\n"); + } + // set GPIO according + btaor(bttv_tvcards[btv->type].audiomux[btv->audio], + ~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA); +} /* @@ -1506,7 +1678,7 @@ * Hauppauge: pin 5 * Voodoo: pin 20 */ -void __devinit bttv_boot_msp34xx(struct bttv *btv, int pin) +static void __devinit boot_msp34xx(struct bttv *btv, int pin) { int mask = (1 << pin); @@ -1918,9 +2090,115 @@ } } else { v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; } } + +/* + * Dariusz Kowalewski + * sound control for FlyVideo 2000S (with tda9874 decoder) + * based on pvbt878p9b_audio() - this is not tested, please fix!!! + */ +static void +fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned int val = 0xffff; + +#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0) + if (btv->radio_user) + return; +#else + if (btv->radio) + return; +#endif + if (set) { + if (v->mode & VIDEO_SOUND_MONO) { + val = 0x0000; + } + if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) + || (v->mode & VIDEO_SOUND_STEREO)) { + val = 0x1080; //-dk-???: 0x0880, 0x0080, 0x1800 ... + } + if (val != 0xffff) { + btaor(val, ~0x1800, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv,"fv2000s"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +/* + * sound control for Canopus WinDVR PCI + * Masaki Suzuki + */ +static void +windvr_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned long val = 0; + + if (set) { + if (v->mode & VIDEO_SOUND_MONO) + val = 0x040000; + if (v->mode & VIDEO_SOUND_LANG1) + val = 0; + if (v->mode & VIDEO_SOUND_LANG2) + val = 0x100000; + if (v->mode & VIDEO_SOUND_STEREO) + val = 0; + if (val) { + btaor(val, ~0x140000, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv,"windvr"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +/* RemoteVision MX (rv605) muxsel helper [Miguel Freitas] + * + * This is needed because rv605 don't use a normal multiplex, but a crosspoint + * switch instead (CD22M3494E). This IC can have multiple active connections + * between Xn (input) and Yn (output) pins. We need to clear any existing + * connection prior to establish a new one, pulsing the STROBE pin. + * + * The board hardwire Y0 (xpoint) to MUX1 and MUXOUT to Yin. + * GPIO pins are wired as: + * GPIO[0:3] - AX[0:3] (xpoint) - P1[0:3] (microcontroler) + * GPIO[4:6] - AY[0:2] (xpoint) - P1[4:6] (microcontroler) + * GPIO[7] - DATA (xpoint) - P1[7] (microcontroler) + * GPIO[8] - - P3[5] (microcontroler) + * GPIO[9] - RESET (xpoint) - P3[6] (microcontroler) + * GPIO[10] - STROBE (xpoint) - P3[7] (microcontroler) + * GPINTR - - P3[4] (microcontroler) + * + * The microcontroler is a 80C32 like. It should be possible to change xpoint + * configuration either directly (as we are doing) or using the microcontroler + * which is also wired to I2C interface. I have no further info on the + * microcontroler features, one would need to disassembly the firmware. + * note: the vendor refused to give any information on this product, all + * that stuff was found using a multimeter! :) + */ +static void rv605_muxsel(struct bttv *btv, unsigned int input) +{ + /* reset all conections */ + btaor(0x200,~0x200, BT848_GPIO_DATA); + mdelay(1); + btaor(0x000,~0x200, BT848_GPIO_DATA); + mdelay(1); + + /* create a new conection */ + btaor(0x080,~0x480, BT848_GPIO_DATA); + btaor(0x480,~0x480, BT848_GPIO_DATA); + mdelay(1); + btaor(0x080,~0x480, BT848_GPIO_DATA); + mdelay(1); +} + /* ----------------------------------------------------------------------- */ /* motherboard chipset specific stuff */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/bttv-driver.c linux-2.5/drivers/media/video/bttv-driver.c --- linux-2.5.5/drivers/media/video/bttv-driver.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/media/video/bttv-driver.c Tue Feb 26 21:24:48 2002 @@ -141,58 +141,63 @@ * defined way to get at the kernel page tables. */ -static inline unsigned long uvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - kva = page_address(vmalloc_to_page(adr)); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); - return ret; +/* + * Take a vmalloc address, and turn it into + * the aliased kernel virtual address.. + * + * CAREFUL! Anybody who does this gets to sit + * in their own cr*p when it comes to virtual + * cache aliases. It's _your_ problem. + * + * Also, note how it only works within one page. + * If you're doing page-crossing stuff, you're on + * your own. + * + * THIS IS BROKEN CODE! You shouldn't do things + * like this. + */ +static inline void *vmalloc_to_virt(void *addr) +{ + struct page *page = vmalloc_to_page(addr); + return page_address(page) + (~PAGE_MASK & (unsigned long)addr); } -static inline unsigned long kvirt_to_bus(unsigned long adr) +static inline unsigned long kvirt_to_bus(unsigned long addr) { - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); + unsigned long ret; + ret = virt_to_bus(vmalloc_to_virt((void *)addr)); + MDEBUG(printk("kv2b(%lx-->%lx)", addr, ret)); return ret; } /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ -static inline unsigned long kvirt_to_pa(unsigned long adr) +static inline unsigned long kvirt_to_pa(unsigned long addr) { - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); - ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); + unsigned long ret; + ret = virt_to_phys(vmalloc_to_virt((void *)addr)); + MDEBUG(printk("kv2pa(%lx-->%lx)", addr, ret)); return ret; } -static void * rvmalloc(signed long size) +static void * rvmalloc(unsigned long size) { void * mem; - unsigned long adr, page; + unsigned long adr; + size=PAGE_ALIGN(size); mem=vmalloc_32(size); if (NULL == mem) - printk(KERN_INFO "bttv: vmalloc_32(%ld) failed\n",size); + printk(KERN_INFO "bttv: vmalloc_32(%lu) failed\n",size); else { /* Clear the ram out, no junk to the user */ memset(mem, 0, size); adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -200,17 +205,16 @@ return mem; } -static void rvfree(void * mem, signed long size) +static void rvfree(void * mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (mem) { adr=(unsigned long) mem; - while (size > 0) + while ((long) size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -2794,7 +2798,8 @@ * Scan for a Bt848 card, request the irq and map the io memory */ -static void __devexit bttv_remove(struct pci_dev *pci_dev) +/* Can't be marked __devexit with a reference from bttv_probe. */ +static void bttv_remove(struct pci_dev *pci_dev) { u8 command; int j; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/bttv.h linux-2.5/drivers/media/video/bttv.h --- linux-2.5.5/drivers/media/video/bttv.h Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/media/video/bttv.h Sun Mar 3 17:54:35 2002 @@ -87,7 +87,9 @@ #define BTTV_PV_BT878P_PLUS 0x46 #define BTTV_FLYVIDEO98EZ 0x47 #define BTTV_PV_BT878P_9B 0x48 - +#define BTTV_SENSORAY311 0x49 +#define BTTV_RV605 0x4a +#define BTTV_WINDVR 0x4c /* i2c address list */ #define I2C_TSA5522 0xc2 @@ -95,7 +97,7 @@ #define I2C_TDA8425 0x82 #define I2C_TDA9840 0x84 #define I2C_TDA9850 0xb6 /* also used by 9855,9873 */ -#define I2C_TDA9874A 0xb0 /* also used by 9875 */ +#define I2C_TDA9874 0xb0 /* also used by 9875 */ #define I2C_TDA9875 0xb0 #define I2C_HAUPEE 0xa0 #define I2C_STBEE 0xae @@ -123,7 +125,7 @@ int tuner; int svhs; u32 gpiomask; - u32 muxsel[8]; + u32 muxsel[16]; u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */ u32 gpiomask2; /* GPIO MUX mask */ @@ -141,6 +143,7 @@ int tuner_type; int has_radio; void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + void (*muxsel_hook)(struct bttv *btv, unsigned int input); }; extern struct tvcard bttv_tvcards[]; @@ -148,11 +151,12 @@ /* identification / initialization of the card */ extern void bttv_idcard(struct bttv *btv); -extern void bttv_init_card(struct bttv *btv); +extern void bttv_init_card1(struct bttv *btv); +extern void bttv_init_card2(struct bttv *btv); /* card-specific funtions */ extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); -extern void bttv_boot_msp34xx(struct bttv *btv, int pin); +extern void bttv_tda9880_setnorm(struct bttv *btv, int norm); /* kernel cmd line parse helper */ extern int bttv_parse(char *str, int max, int *vals); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/bttvp.h linux-2.5/drivers/media/video/bttvp.h --- linux-2.5.5/drivers/media/video/bttvp.h Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/media/video/bttvp.h Sun Mar 3 17:54:35 2002 @@ -25,7 +25,7 @@ #ifndef _BTTVP_H_ #define _BTTVP_H_ -#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,83) +#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,91) #include @@ -136,7 +136,6 @@ unsigned int nr; unsigned short id; struct pci_dev *dev; - unsigned int irq; /* IRQ used by Bt848 card */ unsigned char revision; unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */ unsigned char *bt848_mem; /* pointer to mapped IO memory */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/cpia.c linux-2.5/drivers/media/video/cpia.c --- linux-2.5.5/drivers/media/video/cpia.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/media/video/cpia.c Tue Feb 26 21:24:48 2002 @@ -181,15 +181,14 @@ **********************************************************************/ /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); return ret; } @@ -197,12 +196,9 @@ static void *rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (!mem) return NULL; @@ -210,13 +206,9 @@ memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; @@ -224,23 +216,16 @@ static void rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - adr = (unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree(mem); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/id.h linux-2.5/drivers/media/video/id.h --- linux-2.5.5/drivers/media/video/id.h Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/media/video/id.h Sun Mar 3 17:54:35 2002 @@ -24,6 +24,12 @@ #ifndef I2C_DRIVERID_TDA7432 # define I2C_DRIVERID_TDA7432 I2C_DRIVERID_EXP0+6 #endif -#ifndef I2C_DRIVERID_TDA9874A -# define I2C_DRIVERID_TDA9874A I2C_DRIVERID_EXP0+7 +#ifndef I2C_DRIVERID_TDA9874 +# define I2C_DRIVERID_TDA9874 I2C_DRIVERID_EXP0+7 #endif + +/* algorithms */ +#ifndef I2C_ALGO_SAA7134 +# define I2C_ALGO_SAA7134 0x090000 +#endif + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/meye.c linux-2.5/drivers/media/video/meye.c --- linux-2.5.5/drivers/media/video/meye.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/media/video/meye.c Tue Feb 26 21:24:48 2002 @@ -115,34 +115,29 @@ /* Memory allocation routines (stolen from bttv-driver.c) */ /****************************************************************************/ -#define MDEBUG(x) do {} while (0) -/* #define MDEBUG(x) x */ - /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)\n", adr, ret)); return ret; } -static void *rvmalloc(signed long size) { +static void *rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (mem) { memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long)mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } @@ -150,14 +145,13 @@ return mem; } -static void rvfree(void * mem, signed long size) { - unsigned long adr, page; - +static void rvfree(void * mem, unsigned long size) { + unsigned long adr; + if (mem) { adr = (unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } @@ -1425,7 +1419,7 @@ name: "meye", id_table: meye_pci_tbl, probe: meye_probe, - remove: meye_remove, + remove: __devexit_p(meye_remove), }; static int __init meye_init_module(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/msp3400.c linux-2.5/drivers/media/video/msp3400.c --- linux-2.5.5/drivers/media/video/msp3400.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/media/video/msp3400.c Sun Mar 3 17:54:35 2002 @@ -97,6 +97,7 @@ int nicam_on; int acb; int main, second; /* sound carrier */ + int input; int muted; int left, right; /* volume */ @@ -462,6 +463,8 @@ /* turn on/off nicam + stereo */ static void msp3400c_setstereo(struct i2c_client *client, int mode) { + static char *strmode[] = { "0", "mono", "stereo", "3", + "lang1", "5", "6", "7", "lang2" }; struct msp3400c *msp = client->data; int nicam=0; /* channel source: FM/AM or nicam */ int src=0; @@ -469,7 +472,7 @@ /* switch demodulator */ switch (msp->mode) { case MSP_MODE_FM_TERRA: - dprintk("msp3400: FM setstereo: %d\n",mode); + dprintk("msp3400: FM setstereo: %s\n",strmode[mode]); msp3400c_setcarrier(client,msp->second,msp->main); switch (mode) { case VIDEO_SOUND_STEREO: @@ -483,7 +486,7 @@ } break; case MSP_MODE_FM_SAT: - dprintk("msp3400: SAT setstereo: %d\n",mode); + dprintk("msp3400: SAT setstereo: %s\n",strmode[mode]); switch (mode) { case VIDEO_SOUND_MONO: msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); @@ -502,21 +505,21 @@ case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: case MSP_MODE_AM_NICAM: - dprintk("msp3400: NICAM setstereo: %d\n",mode); + dprintk("msp3400: NICAM setstereo: %s\n",strmode[mode]); msp3400c_setcarrier(client,msp->second,msp->main); if (msp->nicam_on) nicam=0x0100; break; case MSP_MODE_BTSC: - dprintk("msp3400: BTSC setstereo: %d\n",mode); + dprintk("msp3400: BTSC setstereo: %s\n",strmode[mode]); nicam=0x0300; break; case MSP_MODE_EXTERN: - dprintk("msp3400: extern setstereo: %d\n", mode); + dprintk("msp3400: extern setstereo: %s\n",strmode[mode]); nicam = 0x0200; break; case MSP_MODE_FM_RADIO: - dprintk("msp3400: FM-Radio setstereo: %d\n", mode); + dprintk("msp3400: FM-Radio setstereo: %s\n",strmode[mode]); break; default: dprintk("msp3400: mono setstereo\n"); @@ -627,7 +630,7 @@ switch (msp->mode) { case MSP_MODE_FM_TERRA: val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18); - if (val > 32768) + if (val > 32767) val -= 65536; dprintk("msp34xx: stereo detect register: %d\n",val); @@ -822,7 +825,7 @@ msp->restart = 0; val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); - if (val > 32768) + if (val > 32767) val -= 65536; if (val1 < val) val1 = val, max1 = this; @@ -859,7 +862,7 @@ goto restart; val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); - if (val > 32768) + if (val > 32767) val -= 65536; if (val2 < val) val2 = val, max2 = this; @@ -1221,6 +1224,7 @@ static struct i2c_client client_template = { name: "(unset)", + flags: I2C_CLIENT_ALLOW_USE, driver: &driver, }; @@ -1253,6 +1257,7 @@ msp->right = 65535; msp->bass = 32768; msp->treble = 32768; + msp->input = -1; for (i = 0; i < DFP_COUNT; i++) msp->dfp_regs[i] = -1; @@ -1391,6 +1396,9 @@ - IN1 is often used for external input - Hauppauge uses IN2 for the radio */ dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg); + if (*sarg == msp->input) + break; + msp->input = *sarg; switch (*sarg) { case AUDIO_RADIO: msp->mode = MSP_MODE_FM_RADIO; @@ -1420,6 +1428,7 @@ break; case AUDC_SET_RADIO: + dprintk(KERN_DEBUG "msp34xx: AUDC_SET_RADIO\n"); msp->norm = VIDEO_MODE_RADIO; msp->watch_stereo=0; del_timer(&msp->wake_stereo); @@ -1471,6 +1480,7 @@ { struct video_audio *va = arg; + dprintk(KERN_DEBUG "msp34xx: VIDIOCGAUDIO\n"); va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE | @@ -1497,6 +1507,7 @@ { struct video_audio *va = arg; + dprintk(KERN_DEBUG "msp34xx: VIDIOCSAUDIO\n"); msp->muted = (va->flags & VIDEO_AUDIO_MUTE); msp->left = (MIN(65536 - va->balance,32768) * va->volume) / 32768; @@ -1520,6 +1531,7 @@ { struct video_channel *vc = arg; + dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN\n"); dprintk("msp34xx: switching to TV mode\n"); msp->norm = vc->norm; break; @@ -1527,6 +1539,7 @@ case VIDIOCSFREQ: { /* new channel -- kick audio carrier scan */ + dprintk(KERN_DEBUG "msp34xx: VIDIOCSFREQ\n"); msp_wake_thread(client); break; } @@ -1540,13 +1553,13 @@ /* ----------------------------------------------------------------------- */ -int msp3400_init_module(void) +static int msp3400_init_module(void) { i2c_add_driver(&driver); return 0; } -void msp3400_cleanup_module(void) +static void msp3400_cleanup_module(void) { i2c_del_driver(&driver); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/planb.c linux-2.5/drivers/media/video/planb.c --- linux-2.5.5/drivers/media/video/planb.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/media/video/planb.c Wed Jan 16 00:23:26 2002 @@ -90,11 +90,10 @@ static int planb_open(struct video_device *, int); static void planb_close(struct video_device *); static int planb_ioctl(struct video_device *, unsigned int, void *); -static int planb_init_done(struct video_device *); static int planb_mmap(struct video_device *, const char *, unsigned long); static void planb_irq(int, void *, struct pt_regs *); static void release_planb(void); -int init_planbs(struct video_init *); +static int init_planbs(void); /* ------------------ PlanB Internal Functions ------------------ */ static int planb_prepare_open(struct planb *); @@ -2079,7 +2078,6 @@ #endif pb->tab_size = PLANB_MAXLINES + 40; pb->suspend = 0; - pb->lock = 0; init_MUTEX(&pb->lock); pb->ch1_cmd = 0; pb->ch2_cmd = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/tda7432.c linux-2.5/drivers/media/video/tda7432.c --- linux-2.5.5/drivers/media/video/tda7432.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/media/video/tda7432.c Sun Mar 3 17:54:35 2002 @@ -518,7 +518,7 @@ &driver }; -int tda7432_init(void) +static int tda7432_init(void) { if ( (loudness < 0) || (loudness > 15) ) @@ -531,7 +531,7 @@ return 0; } -void tda7432_fini(void) +static void tda7432_fini(void) { i2c_del_driver(&driver); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/tda9875.c linux-2.5/drivers/media/video/tda9875.c --- linux-2.5.5/drivers/media/video/tda9875.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/media/video/tda9875.c Sun Mar 3 17:54:35 2002 @@ -147,6 +147,24 @@ } #endif +static int i2c_read_register(struct i2c_adapter *adap, int addr, int reg) +{ + unsigned char write[1]; + unsigned char read[1]; + struct i2c_msg msgs[2] = { + { addr, 0, 1, write }, + { addr, I2C_M_RD, 1, read } + }; + write[0] = reg; + + if (2 != i2c_transfer(adap,msgs,2)) { + printk(KERN_WARNING "tda9875: I/O error (read2)\n"); + return -1; + } + dprintk("tda9875: chip_read2: reg%d=0x%x\n",reg,read[0]); + return read[0]; +} + static void tda9875_set(struct i2c_client *client) { struct tda9875 *tda = client->data; @@ -215,6 +233,22 @@ * i2c interface functions * * *********************** */ +static int tda9875_checkit(struct i2c_adapter *adap, int addr) +{ + int dic,rev; + + dic=i2c_read_register(adap,addr,254); + rev=i2c_read_register(adap,addr,255); + + if(dic==0 || dic==2) { // tda9875 and tda9875A + printk("tda9875: TDA9875%s Rev.%d detected at 0x%x\n", + dic==0?"":"A", rev,addr<<1); + return 1; + } + printk("tda9875: no such chip at 0x%x (dic=0x%x rev=0x%x)\n",addr<<1,dic,rev); + return(0); +} + static int tda9875_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind) { @@ -232,6 +266,11 @@ client->adapter = adap; client->addr = addr; client->data = t; + + if(!tda9875_checkit(adap,addr)) { + kfree(t); + return 1; + } do_tda9875_init(client); MOD_INC_USE_COUNT; @@ -375,22 +414,19 @@ &driver }; -#ifdef MODULE -int init_module(void) -#else -int tda9875_init(void) -#endif +static int tda9875_init(void) { i2c_add_driver(&driver); return 0; } -#ifdef MODULE -void cleanup_module(void) +static void tda9875_fini(void) { i2c_del_driver(&driver); } -#endif + +module_init(tda9875_init); +module_exit(tda9875_fini); /* * Local variables: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/tuner.c linux-2.5/drivers/media/video/tuner.c --- linux-2.5.5/drivers/media/video/tuner.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/media/video/tuner.c Sun Mar 3 17:54:35 2002 @@ -154,7 +154,7 @@ 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, { "Alps TSBE1",TEMIC,PAL, 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, - { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modtec MM205 */ + { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */ 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632}, { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ @@ -175,7 +175,7 @@ { "Temic PAL* auto (4006 FN5)", TEMIC, PAL, 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, - { "Temic PAL (4009 FR5)", TEMIC, PAL, + { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, { "Temic NTSC (4039 FR5)", TEMIC, NTSC, 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, @@ -271,7 +271,7 @@ } #endif // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 -int mt2032_init(struct i2c_client *c) +static int mt2032_init(struct i2c_client *c) { unsigned char buf[21]; int ret,xogc,xok=0; @@ -345,7 +345,7 @@ // IsSpurInBand()? -int mt2032_spurcheck(int f1, int f2, int spectrum_from,int spectrum_to) +static int mt2032_spurcheck(int f1, int f2, int spectrum_from,int spectrum_to) { int n1=1,n2,f; @@ -373,7 +373,7 @@ return 1; } -int mt2032_compute_freq(int rfin, int if1, int if2, int spectrum_from, +static int mt2032_compute_freq(int rfin, int if1, int if2, int spectrum_from, int spectrum_to, unsigned char *buf, int *ret_sel, int xogc) //all in Hz { int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, @@ -449,7 +449,7 @@ return 0; } -int mt2032_check_lo_lock(struct i2c_client *c) +static int mt2032_check_lo_lock(struct i2c_client *c) { int try,lock=0; unsigned char buf[2]; @@ -469,7 +469,7 @@ return lock; } -int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) +static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) { unsigned char buf[2]; int tad1; @@ -505,7 +505,7 @@ } -void mt2032_set_if_freq(struct i2c_client *c,int rfin, int if1, int if2, int from, int to) +static void mt2032_set_if_freq(struct i2c_client *c,int rfin, int if1, int if2, int from, int to) { unsigned char buf[21]; int lint_try,ret,sel,lock=0; @@ -560,7 +560,7 @@ } -void mt2032_set_tv_freq(struct i2c_client *c, int freq, int norm) +static void mt2032_set_tv_freq(struct i2c_client *c, int freq, int norm) { int if2,from,to; @@ -815,14 +815,27 @@ static int tuner_probe(struct i2c_adapter *adap) { + int rc; + if (0 != addr) { normal_i2c_range[0] = addr; normal_i2c_range[1] = addr; } this_adap = 0; - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - return i2c_probe(adap, &addr_data, tuner_attach); - return 0; + switch (adap->id) { + case I2C_ALGO_BIT | I2C_HW_B_BT848: + case I2C_ALGO_SAA7134: + printk("tuner: probing %s i2c adapter [id=0x%x]\n", + adap->name,adap->id); + rc = i2c_probe(adap, &addr_data, tuner_attach); + break; + default: + printk("tuner: ignoring %s i2c adapter [id=0x%x]\n", + adap->name,adap->id); + rc = 0; + /* nothing */ + } + return rc; } static int tuner_detach(struct i2c_client *client) @@ -948,39 +961,34 @@ /* ----------------------------------------------------------------------- */ static struct i2c_driver driver = { - "i2c TV tuner driver", - I2C_DRIVERID_TUNER, - I2C_DF_NOTIFY, - tuner_probe, - tuner_detach, - tuner_command, + name: "i2c TV tuner driver", + id: I2C_DRIVERID_TUNER, + flags: I2C_DF_NOTIFY, + attach_adapter: tuner_probe, + detach_client: tuner_detach, + command: tuner_command, }; - static struct i2c_client client_template = { - "(unset)", /* name */ - -1, - 0, - 0, - NULL, - &driver + name: "(unset)", + flags: I2C_CLIENT_ALLOW_USE, + driver: &driver, }; -EXPORT_NO_SYMBOLS; - -int tuner_init_module(void) +static int tuner_init_module(void) { i2c_add_driver(&driver); return 0; } -void tuner_cleanup_module(void) +static void tuner_cleanup_module(void) { i2c_del_driver(&driver); } module_init(tuner_init_module); module_exit(tuner_cleanup_module); +EXPORT_NO_SYMBOLS; /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/tuner.h linux-2.5/drivers/media/video/tuner.h --- linux-2.5.5/drivers/media/video/tuner.h Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/media/video/tuner.h Sun Mar 3 17:54:35 2002 @@ -22,6 +22,8 @@ #ifndef _TUNER_H #define _TUNER_H +#include "id.h" + #define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */ #define TUNER_PHILIPS_PAL_I 1 #define TUNER_PHILIPS_NTSC 2 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/tvaudio.c linux-2.5/drivers/media/video/tvaudio.c --- linux-2.5.5/drivers/media/video/tvaudio.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/media/video/tvaudio.c Sun Mar 3 17:54:35 2002 @@ -120,14 +120,17 @@ /* current settings */ __u16 left,right,treble,bass,mode; int prevmode; + int norm; /* thread */ struct task_struct *thread; struct semaphore *notify; wait_queue_head_t wq; struct timer_list wt; int done; + int watch_stereo; }; +#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ /* ---------------------------------------------------------------------- */ /* i2c addresses */ @@ -139,7 +142,7 @@ I2C_TDA9840 >> 1, I2C_TDA985x_L >> 1, I2C_TDA985x_H >> 1, - I2C_TDA9874A >> 1, + I2C_TDA9874 >> 1, I2C_PIC16C54 >> 1, I2C_CLIENT_END }; static unsigned short normal_i2c_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; @@ -296,9 +299,9 @@ dprintk("%s: thread wakeup\n", chip->c.name); if (chip->done || signal_pending(current)) break; - - if (0 != chip->mode) - /* don't do anything if mode != auto */ + + /* don't do anything for radio or if mode != auto */ + if (chip->norm == VIDEO_MODE_RADIO || chip->mode != 0) continue; /* have a look what's going on */ @@ -316,7 +319,7 @@ return 0; } -void generic_checkmode(struct CHIPSTATE *chip) +static void generic_checkmode(struct CHIPSTATE *chip) { struct CHIPDESC *desc = chiplist + chip->type; int mode = desc->getmode(chip); @@ -327,12 +330,12 @@ dprintk("%s: thread checkmode\n", chip->c.name); chip->prevmode = mode; - if (mode & VIDEO_SOUND_LANG1) + if (mode & VIDEO_SOUND_STEREO) + desc->setmode(chip,VIDEO_SOUND_STEREO); + else if (mode & VIDEO_SOUND_LANG1) desc->setmode(chip,VIDEO_SOUND_LANG1); else if (mode & VIDEO_SOUND_LANG2) desc->setmode(chip,VIDEO_SOUND_LANG2); - else if (mode & VIDEO_SOUND_STEREO) - desc->setmode(chip,VIDEO_SOUND_STEREO); else desc->setmode(chip,VIDEO_SOUND_MONO); } @@ -360,7 +363,7 @@ #define TDA9840_TEST_INT1SN 0x1 /* Integration time 0.5s when set */ #define TDA9840_TEST_INTFU 0x02 /* Disables integrator function */ -int tda9840_getmode(struct CHIPSTATE *chip) +static int tda9840_getmode(struct CHIPSTATE *chip) { int val, mode; @@ -376,7 +379,7 @@ return mode; } -void tda9840_setmode(struct CHIPSTATE *chip, int mode) +static void tda9840_setmode(struct CHIPSTATE *chip, int mode) { int update = 1; int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e; @@ -502,11 +505,11 @@ * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */ #define TDA985x_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral */ -int tda9855_volume(int val) { return val/0x2e8+0x27; } -int tda9855_bass(int val) { return val/0xccc+0x06; } -int tda9855_treble(int val) { return (val/0x1c71+0x3)<<1; } +static int tda9855_volume(int val) { return val/0x2e8+0x27; } +static int tda9855_bass(int val) { return val/0xccc+0x06; } +static int tda9855_treble(int val) { return (val/0x1c71+0x3)<<1; } -int tda985x_getmode(struct CHIPSTATE *chip) +static int tda985x_getmode(struct CHIPSTATE *chip) { int mode; @@ -517,7 +520,7 @@ return mode | VIDEO_SOUND_MONO; } -void tda985x_setmode(struct CHIPSTATE *chip, int mode) +static void tda985x_setmode(struct CHIPSTATE *chip, int mode) { int update = 1; int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f; @@ -657,7 +660,7 @@ #define TDA9873_STEREO 2 /* Stereo sound is identified */ #define TDA9873_DUAL 4 /* Dual sound is identified */ -int tda9873_getmode(struct CHIPSTATE *chip) +static int tda9873_getmode(struct CHIPSTATE *chip) { int val,mode; @@ -672,7 +675,7 @@ return mode; } -void tda9873_setmode(struct CHIPSTATE *chip, int mode) +static void tda9873_setmode(struct CHIPSTATE *chip, int mode) { int sw_data = chip->shadow.bytes[TDA9873_SW+1] & ~ TDA9873_TR_MASK; /* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */ @@ -708,7 +711,7 @@ mode, sw_data); } -int tda9873_checkit(struct CHIPSTATE *chip) +static int tda9873_checkit(struct CHIPSTATE *chip) { int rc; @@ -719,10 +722,10 @@ /* ---------------------------------------------------------------------- */ -/* audio chip description - defines+functions for tda9874a */ +/* audio chip description - defines+functions for tda9874h and tda9874a */ /* Dariusz Kowalewski */ -/* Subaddresses for TDA9874A (slave rx) */ +/* Subaddresses for TDA9874H and TDA9874A (slave rx) */ #define TDA9874A_AGCGR 0x00 /* AGC gain */ #define TDA9874A_GCONR 0x01 /* general config */ #define TDA9874A_MSR 0x02 /* monitor select */ @@ -747,10 +750,10 @@ #define TDA9874A_DAICONR 0x15 /* digital audio interface config */ #define TDA9874A_I2SOSR 0x16 /* I2S-bus output select */ #define TDA9874A_I2SOLAR 0x17 /* I2S-bus output level adj. */ -#define TDA9874A_MDACOSR 0x18 /* mono DAC output select */ -#define TDA9874A_ESP 0xFF /* easy standard progr. */ +#define TDA9874A_MDACOSR 0x18 /* mono DAC output select (tda9874a) */ +#define TDA9874A_ESP 0xFF /* easy standard progr. (tda9874a) */ -/* Subaddresses for TDA9874A (slave tx) */ +/* Subaddresses for TDA9874H and TDA9874A (slave tx) */ #define TDA9874A_DSR 0x00 /* device status */ #define TDA9874A_NSR 0x01 /* NICAM status */ #define TDA9874A_NECR 0x02 /* NICAM error count */ @@ -767,37 +770,91 @@ static int tda9874a_mode = 1; /* 0: A2, 1: NICAM */ static int tda9874a_GCONR = 0xc0; /* default config. input pin: SIFSEL=0 */ +static int tda9874a_NCONR = 0x01; /* default NICAM config.: AMSEL=0,AMUTE=1 */ static int tda9874a_ESP = 0x07; /* default standard: NICAM D/K */ +static int tda9874a_dic = -1; /* device id. code */ /* insmod options for tda9874a */ static int tda9874a_SIF = -1; +static int tda9874a_AMSEL = -1; static int tda9874a_STD = -1; MODULE_PARM(tda9874a_SIF,"i"); +MODULE_PARM(tda9874a_AMSEL,"i"); MODULE_PARM(tda9874a_STD,"i"); +/* + * initialization table for tda9874 decoder: + * - carrier 1 freq. registers (3 bytes) + * - carrier 2 freq. registers (3 bytes) + * - demudulator config register + * - FM de-emphasis register (slow identification mode) + * Note: frequency registers must be written in single i2c transfer. + */ +static struct tda9874a_MODES { + char *name; + audiocmd cmd; +} tda9874a_modelist[9] = { + { "A2, B/G", + { 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x77,0xA0,0x00, 0x00,0x00 }} }, + { "A2, M (Korea)", + { 9, { TDA9874A_C1FRA, 0x5D,0xC0,0x00, 0x62,0x6A,0xAA, 0x20,0x22 }} }, + { "A2, D/K (1)", + { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x82,0x60,0x00, 0x00,0x00 }} }, + { "A2, D/K (2)", + { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x8C,0x75,0x55, 0x00,0x00 }} }, + { "A2, D/K (3)", + { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x77,0xA0,0x00, 0x00,0x00 }} }, + { "NICAM, I", + { 9, { TDA9874A_C1FRA, 0x7D,0x00,0x00, 0x88,0x8A,0xAA, 0x08,0x33 }} }, + { "NICAM, B/G", + { 9, { TDA9874A_C1FRA, 0x72,0x95,0x55, 0x79,0xEA,0xAA, 0x08,0x33 }} }, + { "NICAM, D/K", /* default */ + { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x08,0x33 }} }, + { "NICAM, L", + { 9, { TDA9874A_C1FRA, 0x87,0x6A,0xAA, 0x79,0xEA,0xAA, 0x09,0x33 }} } +}; static int tda9874a_setup(struct CHIPSTATE *chip) { chip_write(chip, TDA9874A_AGCGR, 0x00); /* 0 dB */ chip_write(chip, TDA9874A_GCONR, tda9874a_GCONR); chip_write(chip, TDA9874A_MSR, (tda9874a_mode) ? 0x03:0x02); - chip_write(chip, TDA9874A_FMMR, 0x80); + if(tda9874a_dic == 0x11) { + chip_write(chip, TDA9874A_FMMR, 0x80); + } else { /* dic == 0x07 */ + chip_cmd(chip,"tda9874_modelist",&tda9874a_modelist[tda9874a_STD].cmd); + chip_write(chip, TDA9874A_FMMR, 0x00); + } chip_write(chip, TDA9874A_C1OLAR, 0x00); /* 0 dB */ chip_write(chip, TDA9874A_C2OLAR, 0x00); /* 0 dB */ - chip_write(chip, TDA9874A_NCONR, 0x00); /* not 0x04 as doc. table 10 says! */ + chip_write(chip, TDA9874A_NCONR, tda9874a_NCONR); chip_write(chip, TDA9874A_NOLAR, 0x00); /* 0 dB */ - chip_write(chip, TDA9874A_AMCONR, 0xf9); - chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); /* 0x81 */ - chip_write(chip, TDA9874A_AOSR, 0x80); - chip_write(chip, TDA9874A_MDACOSR, (tda9874a_mode) ? 0x82:0x80); - chip_write(chip, TDA9874A_ESP, tda9874a_ESP); - + /* Note: If signal quality is poor you may want to change NICAM */ + /* error limit registers (NLELR and NUELR) to some greater values. */ + /* Then the sound would remain stereo, but won't be so clear. */ + chip_write(chip, TDA9874A_NLELR, 0x14); /* default */ + chip_write(chip, TDA9874A_NUELR, 0x50); /* default */ + + if(tda9874a_dic == 0x11) { + chip_write(chip, TDA9874A_AMCONR, 0xf9); + chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); + chip_write(chip, TDA9874A_AOSR, 0x80); + chip_write(chip, TDA9874A_MDACOSR, (tda9874a_mode) ? 0x82:0x80); + chip_write(chip, TDA9874A_ESP, tda9874a_ESP); + } else { /* dic == 0x07 */ + chip_write(chip, TDA9874A_AMCONR, 0xfb); + chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); + chip_write(chip, TDA9874A_AOSR, 0x00); // or 0x10 + } + dprintk("tda9874a_setup(): %s [0x%02X].\n", + tda9874a_modelist[tda9874a_STD].name,tda9874a_STD); return 1; } -int tda9874a_getmode(struct CHIPSTATE *chip) +static int tda9874a_getmode(struct CHIPSTATE *chip) { int dsr,nsr,mode; + int necr; /* just for debugging */ mode = VIDEO_SOUND_MONO; @@ -805,55 +862,125 @@ return mode; if(-1 == (nsr = chip_read2(chip,TDA9874A_NSR))) return mode; + if(-1 == (necr = chip_read2(chip,TDA9874A_NECR))) + return mode; + + /* need to store dsr/nsr somewhere */ + chip->shadow.bytes[MAXREGS-2] = dsr; + chip->shadow.bytes[MAXREGS-1] = nsr; if(tda9874a_mode) { - /* check also DSR.RSSF and DSR.AMSTAT bits? */ - if(nsr & 0x02) /* NSR.S/MB */ + /* Note: DSR.RSSF and DSR.AMSTAT bits are also checked. + * If NICAM auto-muting is enabled, DSR.AMSTAT=1 indicates + * that sound has (temporarily) switched from NICAM to + * mono FM (or AM) on 1st sound carrier due to high NICAM bit + * error count. So in fact there is no stereo in this case :-( + * But changing the mode to VIDEO_SOUND_MONO would switch + * external 4052 multiplexer in audio_hook(). + */ +#if 0 + if((nsr & 0x02) && !(dsr & 0x10)) /* NSR.S/MB=1 and DSR.AMSTAT=0 */ mode |= VIDEO_SOUND_STEREO; - if(nsr & 0x01) /* NSR.D/SB */ +#else + if(nsr & 0x02) /* NSR.S/MB=1 */ + mode |= VIDEO_SOUND_STEREO; +#endif + if(nsr & 0x01) /* NSR.D/SB=1 */ mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; } else { - if(dsr & 0x02) /* DSR.IDSTE */ + if(dsr & 0x02) /* DSR.IDSTE=1 */ mode |= VIDEO_SOUND_STEREO; - if(dsr & 0x04) /* DSR.IDDUA */ + if(dsr & 0x04) /* DSR.IDDUA=1 */ mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; } - dprintk("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, return: %d.\n", - dsr, nsr, mode); + dprintk("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", + dsr, nsr, necr, mode); return mode; } -void tda9874a_setmode(struct CHIPSTATE *chip, int mode) +static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) { - int aosr=0x80,mdacosr=0x82; - - /* note: TDA9874A has auto-select function for audio output */ - switch(mode) { - case VIDEO_SOUND_MONO: - case VIDEO_SOUND_STEREO: - break; - case VIDEO_SOUND_LANG1: - aosr = 0x80; /* dual A/A */ - mdacosr = (tda9874a_mode) ? 0x82:0x80; - break; - case VIDEO_SOUND_LANG2: - aosr = 0xa0; /* dual B/B */ - mdacosr = (tda9874a_mode) ? 0x83:0x81; - break; - default: - chip->mode = 0; - return; + /* Disable/enable NICAM auto-muting (based on DSR.RSSF status bit). */ + /* If auto-muting is disabled, we can hear a signal of degrading quality. */ + if(tda9874a_mode) { + if(chip->shadow.bytes[MAXREGS-2] & 0x20) /* DSR.RSSF=1 */ + tda9874a_NCONR &= 0xfe; /* enable */ + else + tda9874a_NCONR |= 0x01; /* disable */ + chip_write(chip, TDA9874A_NCONR, tda9874a_NCONR); } - chip_write(chip, TDA9874A_AOSR, aosr); - chip_write(chip, TDA9874A_MDACOSR, mdacosr); + /* Note: TDA9874A supports automatic FM dematrixing (FMMR register) + * and has auto-select function for audio output (AOSR register). + * Old TDA9874H doesn't support these features. + * TDA9874A also has additional mono output pin (OUTM), which + * on same (all?) tv-cards is not used, anyway (as well as MONOIN). + */ + if(tda9874a_dic == 0x11) { + int aosr = 0x80; + int mdacosr = (tda9874a_mode) ? 0x82:0x80; + + switch(mode) { + case VIDEO_SOUND_MONO: + case VIDEO_SOUND_STEREO: + break; + case VIDEO_SOUND_LANG1: + aosr = 0x80; /* auto-select, dual A/A */ + mdacosr = (tda9874a_mode) ? 0x82:0x80; + break; + case VIDEO_SOUND_LANG2: + aosr = 0xa0; /* auto-select, dual B/B */ + mdacosr = (tda9874a_mode) ? 0x83:0x81; + break; + default: + chip->mode = 0; + return; + } + chip_write(chip, TDA9874A_AOSR, aosr); + chip_write(chip, TDA9874A_MDACOSR, mdacosr); + + dprintk("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", + mode, aosr, mdacosr); - dprintk("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", - mode, aosr, mdacosr); + } else { /* dic == 0x07 */ + int fmmr,aosr; + + switch(mode) { + case VIDEO_SOUND_MONO: + fmmr = 0x00; /* mono */ + aosr = 0x10; /* A/A */ + break; + case VIDEO_SOUND_STEREO: + if(tda9874a_mode) { + fmmr = 0x00; + aosr = 0x00; /* handled by NICAM auto-mute */ + } else { + fmmr = (tda9874a_ESP == 1) ? 0x05 : 0x04; /* stereo */ + aosr = 0x00; + } + break; + case VIDEO_SOUND_LANG1: + fmmr = 0x02; /* dual */ + aosr = 0x10; /* dual A/A */ + break; + case VIDEO_SOUND_LANG2: + fmmr = 0x02; /* dual */ + aosr = 0x20; /* dual B/B */ + break; + default: + chip->mode = 0; + return; + } + chip_write(chip, TDA9874A_FMMR, fmmr); + chip_write(chip, TDA9874A_AOSR, aosr); + + dprintk("tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", + mode, fmmr, aosr); + } } -int tda9874a_checkit(struct CHIPSTATE *chip) +static int tda9874a_checkit(struct CHIPSTATE *chip) { int dic,sic; /* device id. and software id. codes */ @@ -864,10 +991,15 @@ dprintk("tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); - return((dic & 0xff) == 0x11); + if((dic == 0x11)||(dic == 0x07)) { + dprintk("tvaudio: found tda9874%s.\n",(dic == 0x11) ? "a (new)":"h (old)"); + tda9874a_dic = dic; /* remember device id. */ + return 1; + } + return 0; /* not found */ } -int tda9874a_initialize(struct CHIPSTATE *chip) +static int tda9874a_initialize(struct CHIPSTATE *chip) { if(tda9874a_SIF != -1) { if(tda9874a_SIF == 1) @@ -887,6 +1019,15 @@ } } + if(tda9874a_AMSEL != -1) { + if(tda9874a_AMSEL == 0) + tda9874a_NCONR = 0x01; /* auto-mute: analog mono input */ + else if(tda9874a_AMSEL == 1) + tda9874a_NCONR = 0x05; /* auto-mute: 1st carrier FM or AM */ + else + printk(KERN_WARNING "tda9874a: AMSEL parameter must be 0 or 1.\n"); + } + tda9874a_setup(chip); return 0; @@ -915,8 +1056,8 @@ #define TEA6420_S_SE 0x04 /* stereo E */ #define TEA6420_S_GMU 0x05 /* general mute */ -int tea6300_shift10(int val) { return val >> 10; } -int tea6300_shift12(int val) { return val >> 12; } +static int tea6300_shift10(int val) { return val >> 10; } +static int tea6300_shift12(int val) { return val >> 12; } /* ---------------------------------------------------------------------- */ @@ -931,8 +1072,8 @@ #define TDA8425_S1_OFF 0xEE /* audio off (mute on) */ #define TDA8425_S1_ON 0xCE /* audio on (mute off) - "linear stereo" mode */ -int tda8425_shift10(int val) { return val >> 10 | 0xc0; } -int tda8425_shift12(int val) { return val >> 12 | 0xf0; } +static int tda8425_shift10(int val) { return val >> 10 | 0xc0; } +static int tda8425_shift12(int val) { return val >> 12 | 0xf0; } /* ---------------------------------------------------------------------- */ @@ -1015,13 +1156,13 @@ }, { - name: "tda9874a", - id: I2C_DRIVERID_TDA9874A, + name: "tda9874h/a", + id: I2C_DRIVERID_TDA9874, checkit: tda9874a_checkit, initialize: tda9874a_initialize, insmodopt: &tda9874a, - addr_lo: I2C_TDA9874A >> 1, - addr_hi: I2C_TDA9874A >> 1, + addr_lo: I2C_TDA9874 >> 1, + addr_hi: I2C_TDA9874 >> 1, getmode: tda9874a_getmode, setmode: tda9874a_setmode, @@ -1160,7 +1301,7 @@ chip->c.data = chip; /* find description for the chip */ - dprintk("tvaudio: chip @ addr=0x%x\n", addr<<1); + dprintk("tvaudio: chip found @ i2c-addr=0x%x\n", addr<<1); for (desc = chiplist; desc->name != NULL; desc++) { if (0 == *(desc->insmodopt)) continue; @@ -1175,7 +1316,8 @@ dprintk("tvaudio: no matching chip description found\n"); return -EIO; } - dprintk("tvaudio: %s matches:%s%s%s\n",desc->name, + printk("tvaudio: found %s\n",desc->name); + dprintk("tvaudio: matches:%s%s%s.\n", (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "", (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "", (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : ""); @@ -1272,6 +1414,14 @@ chip_write_masked(chip,desc->inputreg,desc->inputmap[*sarg],desc->inputmask); } break; + + case AUDC_SET_RADIO: + dprintk(KERN_DEBUG "tvaudio: AUDC_SET_RADIO\n"); + chip->norm = VIDEO_MODE_RADIO; + chip->watch_stereo = 0; + /* del_timer(&chip->wt); */ + break; + /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ @@ -1290,10 +1440,12 @@ va->bass = chip->bass; va->treble = chip->treble; } - if (desc->getmode) - va->mode = desc->getmode(chip); - else - va->mode = VIDEO_SOUND_MONO; + if (chip->norm != VIDEO_MODE_RADIO) { + if (desc->getmode) + va->mode = desc->getmode(chip); + else + va->mode = VIDEO_SOUND_MONO; + } break; } @@ -1316,11 +1468,21 @@ chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); } if (desc->setmode && va->mode) { + chip->watch_stereo = 0; + /* del_timer(&chip->wt); */ chip->mode = va->mode; desc->setmode(chip,va->mode); } break; } + case VIDIOCSCHAN: + { + struct video_channel *vc = arg; + + dprintk(KERN_DEBUG "tvaudio: VIDIOCSCHAN\n"); + chip->norm = vc->norm; + break; + } case VIDIOCSFREQ: { chip->mode = 0; /* automatic */ @@ -1339,7 +1501,7 @@ static struct i2c_driver driver = { name: "generic i2c audio driver", - id: I2C_DRIVERID_TVAUDIO, /* FIXME */ + id: I2C_DRIVERID_TVAUDIO, flags: I2C_DF_NOTIFY, attach_adapter: chip_probe, detach_client: chip_detach, @@ -1349,10 +1511,11 @@ static struct i2c_client client_template = { name: "(unset)", + flags: I2C_CLIENT_ALLOW_USE, driver: &driver, }; -int audiochip_init_module(void) +static int audiochip_init_module(void) { struct CHIPDESC *desc; printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); @@ -1364,7 +1527,7 @@ return 0; } -void audiochip_cleanup_module(void) +static void audiochip_cleanup_module(void) { i2c_del_driver(&driver); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/tvaudio.h linux-2.5/drivers/media/video/tvaudio.h --- linux-2.5.5/drivers/media/video/tvaudio.h Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/media/video/tvaudio.h Sun Mar 3 17:54:35 2002 @@ -6,7 +6,7 @@ #define I2C_TDA9840 0x84 #define I2C_TDA985x_L 0xb4 /* also used by 9873 */ #define I2C_TDA985x_H 0xb6 -#define I2C_TDA9874A 0xb0 /* also used by 9875 */ +#define I2C_TDA9874 0xb0 /* also used by 9875 */ #define I2C_TEA6300 0x80 #define I2C_TEA6420 0x98 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/tvmixer.c linux-2.5/drivers/media/video/tvmixer.c --- linux-2.5.5/drivers/media/video/tvmixer.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/media/video/tvmixer.c Sun Mar 3 17:54:35 2002 @@ -8,8 +8,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -320,7 +321,7 @@ /* ----------------------------------------------------------------------- */ -int tvmixer_init_module(void) +static int tvmixer_init_module(void) { int i; @@ -330,7 +331,7 @@ return 0; } -void tvmixer_cleanup_module(void) +static void tvmixer_cleanup_module(void) { int i; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/videodev.c linux-2.5/drivers/media/video/videodev.c --- linux-2.5.5/drivers/media/video/videodev.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/media/video/videodev.c Fri Feb 8 09:10:49 2002 @@ -208,6 +208,7 @@ lock_kernel(); ret = vfl->mmap(vma, vfl, (char *)vma->vm_start, (unsigned long)(vma->vm_end-vma->vm_start)); + vma->vm_flags &= ~VM_IO; unlock_kernel(); } return ret; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/vino.c linux-2.5/drivers/media/video/vino.c --- linux-2.5.5/drivers/media/video/vino.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/media/video/vino.c Sun Mar 3 17:54:35 2002 @@ -1,6 +1,4 @@ -/* $Id: vino.c,v 1.5 1999/10/09 00:01:14 ralf Exp $ - * drivers/char/vino.c - * +/* * (incomplete) Driver for the Vino Video input system found in SGI Indys. * * Copyright (C) 1999 Ulf Carlsson (ulfc@bun.falkenberg.se) @@ -57,9 +55,7 @@ ".set\tat\n\t" ".set\tmips0" : - :"r" (virt_addr), - "r" (&ret) - :"$1"); + :"r" (virt_addr), "r" (&ret)); restore_flags(flags); return ret; @@ -83,9 +79,7 @@ ".set\tat\n\t" ".set\tmips0" : - :"r" (&value), - "r" (virt_addr) - :"$1"); + :"r" (&value), "r" (virt_addr)); restore_flags(flags); } @@ -93,45 +87,41 @@ unsigned long addr) { unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); - unsigned long flags; + unsigned long tmp, flags; - save_and_cli(flags); + __save_and_cli(flags); __asm__ __volatile__( - ".set\tmips3\n\t" + ".set\tmips3\t\t\t# vino_reg_and\n\t" ".set\tnoat\n\t" - "ld\t$1,(%0)\n\t" - "ld\t$2,(%1)\n\t" - "and\t$1,$1,$2\n\t" - "sd\t$1,(%0)\n\t" + "ld\t$1, (%1)\n\t" + "ld\t%0, (%2)\n\t" + "and\t$1, $1, %0\n\t" + "sd\t$1, (%1)\n\t" ".set\tat\n\t" ".set\tmips0" - : - :"r" (virt_addr), - "r" (&value) - :"$1","$2"); - restore_flags(flags); + : "=&r" (tmp) + : "r" (virt_addr), "r" (&value)); + __restore_flags(flags); } static __inline__ void vino_reg_or(unsigned long long value, unsigned long addr) { unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); - unsigned long flags; + unsigned long tmp, flags; save_and_cli(flags); __asm__ __volatile__( ".set\tmips3\n\t" ".set\tnoat\n\t" - "ld\t$1,(%0)\n\t" - "ld\t$2,(%1)\n\t" - "or\t$1,$1,$2\n\t" - "sd\t$1,(%0)\n\t" + "ld\t$1, (%1)\n\t" + "ld\t%0, (%2)\n\t" + "or\t$1, $1, %0\n\t" + "sd\t$1, (%1)\n\t" ".set\tat\n\t" ".set\tmips0" - : - :"r" (virt_addr), - "r" (&value) - :"$1","$2"); + : "=&r" (tmp) + : "r" (virt_addr), "r" (&value)); restore_flags(flags); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/w9966.c linux-2.5/drivers/media/video/w9966.c --- linux-2.5.5/drivers/media/video/w9966.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/media/video/w9966.c Sun Mar 3 17:54:35 2002 @@ -1,9 +1,7 @@ /* Winbond w9966cf Webcam parport driver. - Version 0.32 - - Copyright (C) 2001 Jakob Kemi + Copyright (C) 2001 Jakob Kemi This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,33 +19,16 @@ */ /* Supported devices: - *Lifeview FlyCam Supra (using the Philips saa7111a chip) - - Does any other model using the w9966 interface chip exist ? + * Lifeview FlyCam Supra (using the Philips saa7111a chip) Todo: - - *Add a working EPP mode, since DMA ECP read isn't implemented - in the parport drivers. (That's why it's so sloow) - - *Add support for other ccd-control chips than the saa7111 - please send me feedback on what kind of chips you have. - - *Add proper probing. I don't know what's wrong with the IEEE1284 - parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID) - and nibble read seems to be broken for some peripherals. - - *Add probing for onboard SRAM, port directions etc. (if possible) - - *Add support for the hardware compressed modes (maybe using v4l2) - - *Fix better support for the capture window (no skewed images, v4l - interface to capt. window) - - *Probably some bugs that I don't know of + * Add a working EPP mode + * Support other ccd-control chips than the saa7111 + (what combinations exists?) + * Add proper probing. IEEE1284 probing of w9966 chips haven't + worked since parport drivers changed in 2.4.x. + * Probe for onboard SRAM, port directions etc. (if possible) - Please support me by sending feedback! - Changes: Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE @@ -59,6 +40,8 @@ #include #include #include +#include +#include //#define DEBUG // Undef me for production @@ -99,43 +82,44 @@ #define W9966_I2C_W_CLOCK 0x01 struct w9966_dev { - unsigned char dev_state; - unsigned char i2c_state; - unsigned short ppmode; + u8 dev_state; + u8 i2c_state; + int ppmode; struct parport* pport; struct pardevice* pdev; struct video_device vdev; - unsigned short width; - unsigned short height; - unsigned char brightness; - signed char contrast; - signed char color; - signed char hue; + u16 width; + u16 height; + u8 brightness; + s8 contrast; + s8 color; + s8 hue; + u8* buffer; }; /* * Module specific properties */ -MODULE_AUTHOR("Jakob Kemi "); -MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)"); +MODULE_AUTHOR("Jakob Kemi "); +MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (FlyCam Supra and others)"); MODULE_LICENSE("GPL"); -#ifdef MODULE -static const char* pardev[] = {[0 ... W9966_MAXCAMS] = ""}; -#else -static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; -#endif -MODULE_PARM(pardev, "1-" __MODULE_STRING(W9966_MAXCAMS) "s"); -MODULE_PARM_DESC(pardev, "pardev: where to search for\n\ -\teach camera. 'aggressive' means brute-force search.\n\ -\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign -\tcam 1 to parport3 and search every parport for cam 2 etc..."); +static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "auto"}; +MODULE_PARM(pardev, "0-" __MODULE_STRING(W9966_MAXCAMS) "s"); +MODULE_PARM_DESC(pardev,"\n\ + Where to find cameras.\n\ + auto = probe all parports for camera\n\ + name = name of parport (eg parport0)\n\ + none = don't search for this camera\n\ +You can specify all cameras this way, for example: + pardev=parport2,auto,none,parport0 would search for cam1 on parport2, search\n\ + for cam2 on all parports, skip cam3 and search for cam4 on parport0"); static int parmode = 0; MODULE_PARM(parmode, "i"); -MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp"); +MODULE_PARM_DESC(parmode, "\n<0|1|2> transfer mode (0=auto, 1=ecp, 2=epp)"); static int video_nr = -1; MODULE_PARM(video_nr, "i"); @@ -277,17 +261,23 @@ case 0: if (port->modes & PARPORT_MODE_ECP) cam->ppmode = IEEE1284_MODE_ECP; - else if (port->modes & PARPORT_MODE_EPP) - cam->ppmode = IEEE1284_MODE_EPP; +/* else if (port->modes & PARPORT_MODE_EPP) + cam->ppmode = IEEE1284_MODE_EPP;*/ else - cam->ppmode = IEEE1284_MODE_ECP; + cam->ppmode = IEEE1284_MODE_ECPSWE; break; case 1: // hw- or sw-ecp - cam->ppmode = IEEE1284_MODE_ECP; + if (port->modes & PARPORT_MODE_ECP) + cam->ppmode = IEEE1284_MODE_ECP; + else + cam->ppmode = IEEE1284_MODE_ECPSWE; break; case 2: // hw- or sw-epp - cam->ppmode = IEEE1284_MODE_EPP; - break; + if (port->modes & PARPORT_MODE_EPP) + cam->ppmode = IEEE1284_MODE_EPP; + else + cam->ppmode = IEEE1284_MODE_EPPSWE; + break; } // Tell the parport driver that we exists @@ -325,6 +315,8 @@ w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); + cam->buffer = NULL; + // All ok printk( "w9966cf: Found and initialized a webcam on %s.\n", @@ -337,6 +329,12 @@ // Terminate everything gracefully static void w9966_term(struct w9966_dev* cam) { +// Delete allocated buffer if needed + if (cam->buffer != NULL) { + kfree(cam->buffer); + cam->buffer = NULL; + } + // Unregister from v4l if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) { video_unregister_device(&cam->vdev); @@ -431,9 +429,9 @@ { unsigned int i; unsigned int enh_s, enh_e; - unsigned char scale_x, scale_y; - unsigned char regs[0x1c]; - unsigned char saa7111_regs[] = { + u8 scale_x, scale_y; + u8 regs[0x1c]; + u8 saa7111_regs[] = { 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00, 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -560,7 +558,7 @@ if (state) { timeout = jiffies + 100; while (!w9966_i2c_getscl(cam)) { - if (jiffies > timeout) + if (time_after(jiffies, timeout)) return -1; } } @@ -664,6 +662,7 @@ return data; } + // Write a register to the i2c device. // Expects claimed pdev. -1 on error static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data) @@ -693,11 +692,23 @@ static int w9966_v4l_open(struct video_device *vdev, int flags) { + struct w9966_dev *cam = (struct w9966_dev*)vdev->priv; + cam->buffer = (u8*)kmalloc(W9966_RBUFFER, GFP_KERNEL); + + if (cam->buffer == NULL) + return -EFAULT; + return 0; } static void w9966_v4l_close(struct video_device *vdev) { + struct w9966_dev *cam = (struct w9966_dev*)vdev->priv; + + if (cam->buffer != NULL) { + kfree(cam->buffer); + cam->buffer = NULL; + } } static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) @@ -920,13 +931,12 @@ while(dleft > 0) { unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft; - unsigned char tbuf[W9966_RBUFFER]; - if (parport_read(cam->pport, tbuf, tsize) < tsize) { + if (parport_read(cam->pport, cam->buffer, tsize) < tsize) { w9966_pdev_release(cam); return -EFAULT; } - if (copy_to_user(dest, tbuf, tsize) != 0) { + if (copy_to_user(dest, cam->buffer, tsize) != 0) { w9966_pdev_release(cam); return -EFAULT; } @@ -948,14 +958,14 @@ for (i = 0; i < W9966_MAXCAMS; i++) { + if (strcmp(pardev[i], "none") == 0) // Skip if 'none' + continue; if (w9966_cams[i].dev_state != 0) // Cam is already assigned continue; - if ( - strcmp(pardev[i], "aggressive") == 0 || - strcmp(pardev[i], port->name) == 0 - ) { + if (strcmp(pardev[i], "auto") == 0 || + strcmp(pardev[i], port->name) == 0) { if (w9966_init(&w9966_cams[i], port) != 0) - w9966_term(&w9966_cams[i]); + w9966_term(&w9966_cams[i]); break; // return } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/media/video/zr36120.c linux-2.5/drivers/media/video/zr36120.c --- linux-2.5.5/drivers/media/video/zr36120.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/media/video/zr36120.c Sun Feb 17 23:08:54 2002 @@ -2024,7 +2024,7 @@ } static -void __exit release_zoran(int max) +void release_zoran(int max) { struct zoran *ztv; int i; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/message/i2o/README linux-2.5/drivers/message/i2o/README --- linux-2.5.5/drivers/message/i2o/README Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/message/i2o/README Sun Mar 3 17:54:35 2002 @@ -39,6 +39,9 @@ Taneli Vähäkangas, University of Helsinki Finland Fixes to i2o_config +Boji T Kannanthanam + Intel i2o controller work, extending proc/config stuff + CREDITS This work was made possible by @@ -62,32 +65,38 @@ ASUSTeK Loan of I2O motherboard +Promise + Providing a Supertrak 100 board and support info + +DPT + Providing a DPT smartraid I2O card (use dpt_i2o for this + board however) + STATUS: +o Should be stable for x86 32bit -o The core setup works within limits. -o The scsi layer seems to almost work. - I'm still chasing down the hang bug. -o The block OSM is mostly functional -o LAN OSM works with FDDI and Ethernet cards. +KNOWN ISSUES: +o Reports that intel boards die if you load i2o_block and i2o_scsi +o Some promise cards need firmware updates TO DO: General: +o Finish 64bit and big endian cleanup +o Switch to new PCI mapping layer throughout +o Hotswap of controllers o Provide hidden address space if asked o Long term message flow control o PCI IOP's without interrupts are not supported yet o Push FAIL handling into the core o DDM control interfaces for module load etc -o Add I2O 2.0 support (Deffered to 2.5 kernel) Block: -o Multiple major numbers -o Read ahead and cache handling stuff. Talk to Ingo and people +o Multiple major numbers (problem goes away in 2.5) o Power management o Finish Media changers SCSI: -o Find the right way to associate drives/luns/busses Lan: o Performance tuning @@ -95,4 +104,3 @@ Tape: o Anyone seen anything implementing this ? - (D.S: Will attempt to do so if spare cycles permit) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/message/i2o/i2o_block.c linux-2.5/drivers/message/i2o/i2o_block.c --- linux-2.5.5/drivers/message/i2o/i2o_block.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/message/i2o/i2o_block.c Thu Feb 21 01:26:10 2002 @@ -116,7 +116,7 @@ #define I2O_BSA_DSC_VOLUME_CHANGED 0x000D #define I2O_BSA_DSC_TIMEOUT 0x000E -#define I2O_UNIT(dev) (i2ob_dev[MINOR((dev)) & 0xf0]) +#define I2O_UNIT(dev) (i2ob_dev[minor((dev)) & 0xf0]) #define I2O_LOCK(unit) (i2ob_dev[(unit)].req_queue->queue_lock) /* @@ -285,6 +285,7 @@ if(req->cmd == READ) { + DEBUG("READ\n"); __raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4); while(bio) { @@ -324,6 +325,7 @@ } else if(req->cmd == WRITE) { + DEBUG("WRITE\n"); __raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4); while(bio) { @@ -419,6 +421,7 @@ * It is now ok to complete the request. */ end_that_request_last( req ); + DEBUG("IO COMPLETED\n"); } static int i2ob_flush(struct i2o_controller *c, struct i2ob_device *d, int unit) @@ -442,7 +445,7 @@ __raw_writel(i2ob_context|(unit<<8), msg+8); __raw_writel(0, msg+12); __raw_writel(60<<16, msg+16); - + DEBUG("FLUSH"); i2o_post_message(c,m); return 0; } @@ -465,6 +468,7 @@ */ if(m[0] & (1<<13)) { + DEBUG("FAIL"); /* * FAILed message from controller * We increment the error count and abort it @@ -504,7 +508,7 @@ { spin_lock_irqsave(&I2O_LOCK(c->unit), flags); dev->constipated=0; - DEBUG(("unconstipated\n")); + DEBUG("unconstipated\n"); if(i2ob_backlog_request(c, dev)==0) i2ob_request(dev->req_queue); spin_unlock_irqrestore(&I2O_LOCK(c->unit), flags); @@ -760,7 +764,7 @@ { u64 size; - if(do_i2ob_revalidate(MKDEV(MAJOR_NR, unit),0) != -EBUSY) + if(do_i2ob_revalidate(mk_kdev(MAJOR_NR, unit),0) != -EBUSY) continue; if(i2ob_query_device(&i2ob_dev[unit], 0x0004, 0, &size, 8) !=0 ) @@ -803,7 +807,7 @@ * and tell them to fix their firmware :) */ default: - printk(KERN_INFO "%s: Received event %d we didn't register for\n" + printk(KERN_INFO "%s: Received event 0x%X we didn't register for\n" KERN_INFO " Blame the I2O card manufacturer 8)\n", i2ob_dev[unit].i2odev->dev_name, evt); break; @@ -869,7 +873,7 @@ if(i2ob_backlog[c->unit] == NULL) i2ob_backlog_tail[c->unit] = NULL; - unit = MINOR(ireq->req->rq_dev); + unit = minor(ireq->req->rq_dev); i2ob_send(m, dev, ireq, i2ob[unit].start_sect, unit); } if(i2ob_backlog[c->unit]) @@ -905,7 +909,7 @@ if(req->rq_status == RQ_INACTIVE) return; - unit = MINOR(req->rq_dev); + unit = minor(req->rq_dev); dev = &i2ob_dev[(unit&0xF0)]; /* @@ -1038,7 +1042,7 @@ static int do_i2ob_revalidate(kdev_t dev, int maxu) { - int minor=MINOR(dev); + int minor=minor(dev); int i; minor&=0xF0; @@ -1053,7 +1057,7 @@ for( i = 15; i>=0 ; i--) { int m = minor+i; - invalidate_device(MKDEV(MAJOR_NR, m), 1); + invalidate_device(mk_kdev(MAJOR_NR, m), 1); i2ob_gendisk.part[m].start_sect = 0; i2ob_gendisk.part[m].nr_sects = 0; } @@ -1079,14 +1083,14 @@ if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!inode || !inode->i_rdev) + if (!inode || kdev_none(inode->i_rdev)) return -EINVAL; switch (cmd) { case HDIO_GETGEO: { struct hd_geometry g; - int u = MINOR(inode->i_rdev) & 0xF0; + int u = minor(inode->i_rdev) & 0xF0; i2o_block_biosparam(i2ob_sizes[u]<<1, &g.cylinders, &g.heads, &g.sectors); g.start = get_start_sect(inode->i_rdev); @@ -1121,7 +1125,7 @@ struct i2ob_device *dev; int minor; - minor = MINOR(inode->i_rdev); + minor = minor(inode->i_rdev); if (minor >= (MAX_I2OB<<4)) return -ENODEV; dev = &i2ob_dev[(minor&0xF0)]; @@ -1137,9 +1141,6 @@ if(!dev->i2odev) return 0; - /* Sync the device so we don't get errors */ - fsync_dev(inode->i_rdev); - if (dev->refcnt <= 0) printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt); dev->refcnt--; @@ -1193,7 +1194,7 @@ if (!inode) return -EINVAL; - minor = MINOR(inode->i_rdev); + minor = minor(inode->i_rdev); if (minor >= MAX_I2OB<<4) return -ENODEV; dev=&i2ob_dev[(minor&0xF0)]; @@ -1384,7 +1385,7 @@ */ dev->req_queue = &i2ob_queues[c->unit]->req_queue; - grok_partitions(MKDEV(MAJOR_NR, unit), (long)(size>>9)); + grok_partitions(mk_kdev(MAJOR_NR, unit), (long)(size>>9)); /* * Register for the events we're interested in and that the @@ -1404,19 +1405,16 @@ { int i; - i2ob_queues[unit] = (struct i2ob_iop_queue*) - kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC); + i2ob_queues[unit] = (struct i2ob_iop_queue*) kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC); if(!i2ob_queues[unit]) { - printk(KERN_WARNING - "Could not allocate request queue for I2O block device!\n"); + printk(KERN_WARNING "Could not allocate request queue for I2O block device!\n"); return -1; } for(i = 0; i< MAX_I2OB_DEPTH; i++) { - i2ob_queues[unit]->request_queue[i].next = - &i2ob_queues[unit]->request_queue[i+1]; + i2ob_queues[unit]->request_queue[i].next = &i2ob_queues[unit]->request_queue[i+1]; i2ob_queues[unit]->request_queue[i].num = i; } @@ -1460,34 +1458,34 @@ if(c==NULL) continue; - /* - * The device list connected to the I2O Controller is doubly linked - * Here we traverse the end of the list , and start claiming devices - * from that end. This assures that within an I2O controller atleast - * the newly created volumes get claimed after the older ones, thus - * mapping to same major/minor (and hence device file name) after - * every reboot. - * The exception being: - * 1. If there was a TID reuse. - * 2. There was more than one I2O controller. - */ - - if(!bios) - { - for (d=c->devices;d!=NULL;d=d->next) - if(d->next == NULL) - b = d; - } - else - b = c->devices; + /* + * The device list connected to the I2O Controller is doubly linked + * Here we traverse the end of the list , and start claiming devices + * from that end. This assures that within an I2O controller atleast + * the newly created volumes get claimed after the older ones, thus + * mapping to same major/minor (and hence device file name) after + * every reboot. + * The exception being: + * 1. If there was a TID reuse. + * 2. There was more than one I2O controller. + */ - while(b != NULL) - { - d=b; - if(bios) - b = b->next; + if(!bios) + { + for (d=c->devices;d!=NULL;d=d->next) + if(d->next == NULL) + b = d; + } else - b = b->prev; + b = c->devices; + + while(b != NULL) + { + d=b; + if(bios) + b = b->next; + else + b = b->prev; if(d->lct_data.class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE) continue; @@ -1704,7 +1702,7 @@ */ static int i2ob_media_change(kdev_t dev) { - int i=MINOR(dev); + int i=minor(dev); i>>=4; if(i2ob_media_change_flag[i]) { @@ -1883,7 +1881,7 @@ * Finally see what is actually plugged in to our controllers */ for (i = 0; i < MAX_I2OB; i++) - register_disk(&i2ob_gendisk, MKDEV(MAJOR_NR,i<<4), 1<<4, + register_disk(&i2ob_gendisk, mk_kdev(MAJOR_NR,i<<4), 1<<4, &i2ob_fops, 0); i2ob_probe(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/message/i2o/i2o_config.c linux-2.5/drivers/message/i2o/i2o_config.c --- linux-2.5.5/drivers/message/i2o/i2o_config.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/message/i2o/i2o_config.c Mon Feb 18 21:47:52 2002 @@ -25,7 +25,10 @@ * 2 of the License, or (at your option) any later version. */ +#include // Nuke me with the ifdef. +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #include #include @@ -47,7 +50,7 @@ static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED; struct wait_queue *i2o_wait_queue; -#define MODINC(x,y) (x = x++ % y) +#define MODINC(x,y) ((x) = ((x) + 1) % (y)) struct i2o_cfg_info { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/message/i2o/i2o_core.c linux-2.5/drivers/message/i2o/i2o_core.c --- linux-2.5.5/drivers/message/i2o/i2o_core.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/message/i2o/i2o_core.c Mon Feb 18 21:45:54 2002 @@ -22,9 +22,12 @@ * */ +#include + +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif -#include #include #include #include @@ -210,7 +213,7 @@ static DECLARE_MUTEX(evt_sem); static DECLARE_COMPLETION(evt_dead); -DECLARE_WAIT_QUEUE_HEAD(evt_wait); +static DECLARE_WAIT_QUEUE_HEAD(evt_wait); static struct notifier_block i2o_reboot_notifier = { @@ -1186,7 +1189,8 @@ { struct i2o_handler *i; /* Map the message from the page frame map to kernel virtual */ - m=(struct i2o_message *)(mv - (unsigned long)c->page_frame_map + (unsigned long)c->page_frame); + /* m=(struct i2o_message *)(mv - (unsigned long)c->page_frame_map + (unsigned long)c->page_frame); */ + m=(struct i2o_message *)bus_to_virt(mv); msg=(u32*)m; /* @@ -2560,6 +2564,7 @@ int i2o_post_wait_mem(struct i2o_controller *c, u32 *msg, int len, int timeout, void *mem1, void *mem2) { DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post); + DECLARE_WAITQUEUE(wait, current); int complete = 0; int status; unsigned long flags = 0; @@ -2600,12 +2605,19 @@ * complete will be zero. From the point post_this returns * the wait_data may have been deleted. */ + + add_wait_queue(&wq_i2o_post, &wait); + set_current_state(TASK_INTERRUPTIBLE); if ((status = i2o_post_this(c, msg, len))==0) { - sleep_on_timeout(&wq_i2o_post, HZ * timeout); + schedule_timeout(HZ * timeout); } else + { + remove_wait_queue(&wq_i2o_post, &wait); return -EIO; - + } + remove_wait_queue(&wq_i2o_post, &wait); + if(signal_pending(current)) status = -EINTR; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/message/i2o/i2o_lan.c linux-2.5/drivers/message/i2o/i2o_lan.c --- linux-2.5.5/drivers/message/i2o/i2o_lan.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/message/i2o/i2o_lan.c Mon Feb 18 21:50:50 2002 @@ -25,9 +25,12 @@ * TODO: tests for other LAN classes (Token Ring, Fibre Channel) */ +#include + +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif -#include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/message/i2o/i2o_scsi.c linux-2.5/drivers/message/i2o/i2o_scsi.c --- linux-2.5.5/drivers/message/i2o/i2o_scsi.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/message/i2o/i2o_scsi.c Mon Feb 18 21:52:06 2002 @@ -31,7 +31,10 @@ * Fix the resource management problems. */ +#include // nuke me later. +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #include #include @@ -191,7 +194,7 @@ { /* Create a scsi error for this */ current_command = (Scsi_Cmnd *)m[3]; - lock = ¤t_command->host->host_lock; + lock = current_command->host->host_lock; printk("Aborted %ld\n", current_command->serial_number); spin_lock_irq(lock); @@ -286,22 +289,17 @@ * It worked maybe ? */ current_command->result = DID_OK << 16 | ds; - lock = ¤t_command->host->host_lock; + lock = current_command->host->host_lock; spin_lock(lock); current_command->scsi_done(current_command); spin_unlock(lock); return; } -struct i2o_handler i2o_scsi_handler= -{ - i2o_scsi_reply, - NULL, - NULL, - NULL, - "I2O SCSI OSM", - 0, - I2O_CLASS_SCSI_PERIPHERAL +struct i2o_handler i2o_scsi_handler = { + reply: i2o_scsi_reply, + name: "I2O SCSI OSM", + class: I2O_CLASS_SCSI_PERIPHERAL, }; static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/devices/blkmtd.c linux-2.5/drivers/mtd/devices/blkmtd.c --- linux-2.5.5/drivers/mtd/devices/blkmtd.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/mtd/devices/blkmtd.c Tue Feb 26 20:52:44 2002 @@ -1,10 +1,11 @@ /* - * $Id: blkmtd.c,v 1.3 2001/10/02 15:33:20 dwmw2 Exp $ + * $Id: blkmtd.c,v 1.7 2001/11/10 17:06:30 spse Exp $ + * * blkmtd.c - use a block device as a fake MTD * * Author: Simon Evans * - * Copyright (C) 2001 Simon Evans + * Copyright (C) 2001 Simon Evans * * Licence: GPL * @@ -13,7 +14,7 @@ * cache to cache access. Writes update the page cache with the * new data but make a copy of the new page(s) and then a kernel * thread writes pages out to the device in the background. This - * ensures tht writes are order even if a page is updated twice. + * ensures that writes are order even if a page is updated twice. * Also, since pages in the page cache are never marked as dirty, * we dont have to worry about writepage() being called on some * random page which may not be in the write order. @@ -30,7 +31,7 @@ * small memory systems and too small on large memory systems. * * Page cache usage may still be a bit wrong. Check we are doing - * everything proberly. + * everything properly. * * Somehow allow writes to dirty the page cache so we dont use too * much memory making copies of outgoing pages. Need to handle case @@ -39,19 +40,14 @@ * * Reading should read multiple pages at once rather than using * readpage() for each one. This is easy and will be fixed asap. - * - * Dont run the write_thread if readonly. This is also easy and will - * be fixed asap. - * - * Even though the multiple erase regions are used if the default erase - * block size doesnt match the device properly, erases currently wont - * work on the last page if it is not a full page. */ + #include #include #include +#include #include #include #include @@ -59,19 +55,30 @@ #include #include +#ifdef CONFIG_MTD_DEBUG +#ifdef CONFIG_PROC_FS +# include +# define BLKMTD_PROC_DEBUG + static struct proc_dir_entry *blkmtd_proc; +#endif +#endif + + /* Default erase size in K, always make it a multiple of PAGE_SIZE */ #define CONFIG_MTD_BLKDEV_ERASESIZE 128 -#define VERSION "1.1" +#define VERSION "1.7" extern int *blk_size[]; /* Info for the block device */ typedef struct mtd_raw_dev_data_s { struct block_device *binding; - int sector_size, sector_bits, total_sectors; + int sector_size, sector_bits; + int partial_last_page; // 0 if device ends on page boundary, else page no of last page + int last_page_sectors; // Number of sectors in last page if partial_last_page != 0 size_t totalsize; int readonly; struct address_space as; - struct file *file; + struct mtd_info mtd_info; } mtd_raw_dev_data_t; /* Info for each queue item in the write queue */ @@ -84,24 +91,28 @@ } mtdblkdev_write_queue_t; +/* Our erase page - always remains locked. */ +static struct page *erase_page; + /* Static info about the MTD, used in cleanup_module */ -static struct mtd_info *mtd_info; +static mtd_raw_dev_data_t *mtd_rawdevice; /* Write queue fixed size */ #define WRITE_QUEUE_SZ 512 /* Storage for the write queue */ -static mtdblkdev_write_queue_t write_queue[WRITE_QUEUE_SZ]; +static mtdblkdev_write_queue_t *write_queue; +static int write_queue_sz = WRITE_QUEUE_SZ; static int volatile write_queue_head; static int volatile write_queue_tail; static int volatile write_queue_cnt; static spinlock_t mbd_writeq_lock = SPIN_LOCK_UNLOCKED; /* Tell the write thread to finish */ -static volatile int write_task_finish = 0; +static volatile int write_task_finish; /* ipc with the write thread */ -#if LINUX_VERSION_CODE > 0x020300 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) static DECLARE_MUTEX_LOCKED(thread_sem); static DECLARE_WAIT_QUEUE_HEAD(thr_wq); static DECLARE_WAIT_QUEUE_HEAD(mtbd_sync_wq); @@ -112,13 +123,14 @@ #endif - /* Module parameters passed by insmod/modprobe */ char *device; /* the block device to use */ int erasesz; /* optional default erase size */ int ro; /* optional read only flag */ int bs; /* optionally force the block size (avoid using) */ int count; /* optionally force the block count (avoid using) */ +int wqs; /* optionally set the write queue size */ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) MODULE_LICENSE("GPL"); @@ -134,10 +146,10 @@ MODULE_PARM_DESC(bs, "force the block size in bytes"); MODULE_PARM(count, "i"); MODULE_PARM_DESC(count, "force the block count"); +MODULE_PARM(wqs, "i"); #endif - /* Page cache stuff */ /* writepage() - should never be called - catch it anyway */ @@ -149,13 +161,13 @@ /* readpage() - reads one page from the block device */ -static int blkmtd_readpage(struct file *file, struct page *page) +static int blkmtd_readpage(mtd_raw_dev_data_t *rawdevice, struct page *page) { int err; int sectornr, sectors, i; struct kiobuf *iobuf; - mtd_raw_dev_data_t *rawdevice = (mtd_raw_dev_data_t *)file->private_data; kdev_t dev; + unsigned long *blocks; if(!rawdevice) { printk("blkmtd: readpage: PANIC file->private_data == NULL\n"); @@ -167,7 +179,7 @@ bdevname(dev), page, page->index); if(Page_Uptodate(page)) { - DEBUG(1, "blkmtd: readpage page %ld is already upto date\n", page->index); + DEBUG(2, "blkmtd: readpage page %ld is already upto date\n", page->index); UnlockPage(page); return 0; } @@ -183,8 +195,9 @@ mtdblkdev_write_queue_t *item = &write_queue[i]; if(page->index >= item->pagenr && page->index < item->pagenr+item->pagecnt) { /* yes it is */ - int index = item->pagenr - page->index; - DEBUG(1, "blkmtd: readpage: found page %ld in outgoing write queue\n", + int index = page->index - item->pagenr; + + DEBUG(2, "blkmtd: readpage: found page %ld in outgoing write queue\n", page->index); if(item->iserase) { memset(page_address(page), 0xff, PAGE_SIZE); @@ -198,7 +211,7 @@ return 0; } i++; - i %= WRITE_QUEUE_SZ; + i %= write_queue_sz; } } spin_unlock(&mbd_writeq_lock); @@ -207,8 +220,24 @@ DEBUG(3, "blkmtd: readpage: getting kiovec\n"); err = alloc_kiovec(1, &iobuf); if (err) { + printk("blkmtd: cant allocate kiobuf\n"); + SetPageError(page); return err; } + + /* Pre 2.4.4 doesnt have space for the block list in the kiobuf */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) + blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long)); + if(blocks == NULL) { + printk("blkmtd: cant allocate iobuf blocks\n"); + free_kiovec(1, &iobuf); + SetPageError(page); + return -ENOMEM; + } +#else + blocks = iobuf->blocks; +#endif + iobuf->offset = 0; iobuf->nr_pages = 1; iobuf->length = PAGE_SIZE; @@ -216,16 +245,34 @@ iobuf->maplist[0] = page; sectornr = page->index << (PAGE_SHIFT - rawdevice->sector_bits); sectors = 1 << (PAGE_SHIFT - rawdevice->sector_bits); + if(rawdevice->partial_last_page && page->index == rawdevice->partial_last_page) { + DEBUG(3, "blkmtd: handling partial last page\n"); + sectors = rawdevice->last_page_sectors; + } DEBUG(3, "blkmtd: readpage: sectornr = %d sectors = %d\n", sectornr, sectors); for(i = 0; i < sectors; i++) { - iobuf->blocks[i] = sectornr++; + blocks[i] = sectornr++; } + /* If only a partial page read in, clear the rest of the page */ + if(rawdevice->partial_last_page && page->index == rawdevice->partial_last_page) { + int offset = rawdevice->last_page_sectors << rawdevice->sector_bits; + int count = PAGE_SIZE-offset; + DEBUG(3, "blkmtd: clear last partial page: offset = %d count = %d\n", offset, count); + memset(page_address(page)+offset, 0, count); + sectors = rawdevice->last_page_sectors; + } + DEBUG(3, "bklmtd: readpage: starting brw_kiovec\n"); - err = brw_kiovec(READ, 1, &iobuf, dev, iobuf->blocks, rawdevice->sector_size); + err = brw_kiovec(READ, 1, &iobuf, dev, blocks, rawdevice->sector_size); DEBUG(3, "blkmtd: readpage: finished, err = %d\n", err); iobuf->locked = 0; free_kiovec(1, &iobuf); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) + kfree(blocks); +#endif + if(err != PAGE_SIZE) { printk("blkmtd: readpage: error reading page %ld\n", page->index); memset(page_address(page), 0, PAGE_SIZE); @@ -245,7 +292,7 @@ static struct address_space_operations blkmtd_aops = { writepage: blkmtd_writepage, - readpage: blkmtd_readpage, + readpage: NULL, }; @@ -255,6 +302,7 @@ int err; struct task_struct *tsk = current; struct kiobuf *iobuf; + unsigned long *blocks; DECLARE_WAITQUEUE(wait, tsk); DEBUG(1, "blkmtd: writetask: starting (pid = %d)\n", tsk->pid); @@ -266,8 +314,23 @@ recalc_sigpending(); spin_unlock_irq(&tsk->sigmask_lock); - if(alloc_kiovec(1, &iobuf)) + if(alloc_kiovec(1, &iobuf)) { + printk("blkmtd: write_queue_task cant allocate kiobuf\n"); return 0; + } + + /* Pre 2.4.4 doesnt have space for the block list in the kiobuf */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) + blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long)); + if(blocks == NULL) { + printk("blkmtd: write_queue_task cant allocate iobuf blocks\n"); + free_kiovec(1, &iobuf); + return 0; + } +#else + blocks = iobuf->blocks; +#endif + DEBUG(2, "blkmtd: writetask: entering main loop\n"); add_wait_queue(&thr_wq, &wait); @@ -278,30 +341,39 @@ /* If nothing in the queue, wake up anyone wanting to know when there is space in the queue then sleep for 2*HZ */ spin_unlock(&mbd_writeq_lock); - DEBUG(3, "blkmtd: writetask: queue empty\n"); + DEBUG(4, "blkmtd: writetask: queue empty\n"); if(waitqueue_active(&mtbd_sync_wq)) wake_up(&mtbd_sync_wq); interruptible_sleep_on_timeout(&thr_wq, 2*HZ); - DEBUG(3, "blkmtd: writetask: woken up\n"); + DEBUG(4, "blkmtd: writetask: woken up\n"); if(write_task_finish) break; } else { /* we have stuff to write */ mtdblkdev_write_queue_t *item = &write_queue[write_queue_tail]; struct page **pages = item->pages; - int pagecnt = item->pagecnt; - int pagenr = item->pagenr; + int i; + int sectornr = item->pagenr << (PAGE_SHIFT - item->rawdevice->sector_bits); + int sectorcnt = item->pagecnt << (PAGE_SHIFT - item->rawdevice->sector_bits); int max_sectors = KIO_MAX_SECTORS >> (item->rawdevice->sector_bits - 9); kdev_t dev = to_kdev_t(item->rawdevice->binding->bd_dev); - + + /* If we are writing to the last page on the device and it doesnt end + * on a page boundary, subtract the number of sectors that dont exist. + */ + if(item->rawdevice->partial_last_page && + (item->pagenr + item->pagecnt -1) == item->rawdevice->partial_last_page) { + sectorcnt -= (1 << (PAGE_SHIFT - item->rawdevice->sector_bits)); + sectorcnt += item->rawdevice->last_page_sectors; + } DEBUG(3, "blkmtd: writetask: got %d queue items\n", write_queue_cnt); set_current_state(TASK_RUNNING); spin_unlock(&mbd_writeq_lock); - DEBUG(2, "blkmtd: write_task: writing pagenr = %d pagecnt = %d", - item->pagenr, item->pagecnt); + DEBUG(2, "blkmtd: writetask: writing pagenr = %d pagecnt = %d sectornr = %d sectorcnt = %d\n", + item->pagenr, item->pagecnt, sectornr, sectorcnt); iobuf->offset = 0; iobuf->locked = 1; @@ -309,31 +381,33 @@ /* Loop through all the pages to be written in the queue item, remembering we can only write KIO_MAX_SECTORS at a time */ - while(pagecnt) { - int sectornr = pagenr << (PAGE_SHIFT - item->rawdevice->sector_bits); - int sectorcnt = pagecnt << (PAGE_SHIFT - item->rawdevice->sector_bits); + while(sectorcnt) { int cursectors = (sectorcnt < max_sectors) ? sectorcnt : max_sectors; int cpagecnt = (cursectors << item->rawdevice->sector_bits) + PAGE_SIZE-1; cpagecnt >>= PAGE_SHIFT; - for(i = 0; i < cpagecnt; i++) + for(i = 0; i < cpagecnt; i++) { + if(item->iserase) { + iobuf->maplist[i] = erase_page; + } else { iobuf->maplist[i] = *(pages++); + } + } for(i = 0; i < cursectors; i++) { - iobuf->blocks[i] = sectornr++; + blocks[i] = sectornr++; } iobuf->nr_pages = cpagecnt; iobuf->length = cursectors << item->rawdevice->sector_bits; DEBUG(3, "blkmtd: write_task: about to kiovec\n"); - err = brw_kiovec(WRITE, 1, &iobuf, dev, iobuf->blocks, item->rawdevice->sector_size); + err = brw_kiovec(WRITE, 1, &iobuf, dev, blocks, item->rawdevice->sector_size); DEBUG(3, "bklmtd: write_task: done, err = %d\n", err); if(err != (cursectors << item->rawdevice->sector_bits)) { /* if an error occured - set this to exit the loop */ - pagecnt = 0; + sectorcnt = 0; } else { - pagenr += cpagecnt; - pagecnt -= cpagecnt; + sectorcnt -= cursectors; } } @@ -343,12 +417,14 @@ spin_lock(&mbd_writeq_lock); write_queue_cnt--; write_queue_tail++; - write_queue_tail %= WRITE_QUEUE_SZ; - for(i = 0 ; i < item->pagecnt; i++) { - UnlockPage(item->pages[i]); - __free_pages(item->pages[i], 0); + write_queue_tail %= write_queue_sz; + if(!item->iserase) { + for(i = 0 ; i < item->pagecnt; i++) { + UnlockPage(item->pages[i]); + __free_pages(item->pages[i], 0); + } + kfree(item->pages); } - kfree(item->pages); item->pages = NULL; spin_unlock(&mbd_writeq_lock); /* Tell others there is some space in the write queue */ @@ -359,6 +435,11 @@ remove_wait_queue(&thr_wq, &wait); DEBUG(1, "blkmtd: writetask: exiting\n"); free_kiovec(1, &iobuf); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) + kfree(blocks); +#endif + /* Tell people we have exitd */ up(&thread_sem); return 0; @@ -370,43 +451,45 @@ int pagenr, int pagecnt, int iserase) { struct page *outpage; - struct page **new_pages; + struct page **new_pages = NULL; mtdblkdev_write_queue_t *item; int i; DECLARE_WAITQUEUE(wait, current); - DEBUG(2, "mtdblkdev: queue_page_write: adding pagenr = %d pagecnt = %d\n", pagenr, pagecnt); + DEBUG(2, "blkmtd: queue_page_write: adding pagenr = %d pagecnt = %d\n", pagenr, pagecnt); if(!pagecnt) return 0; - if(pages == NULL) + if(pages == NULL && !iserase) return -EINVAL; /* create a array for the list of pages */ - new_pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL); - if(new_pages == NULL) - return -ENOMEM; + if(!iserase) { + new_pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL); + if(new_pages == NULL) + return -ENOMEM; - /* make copies of the pages in the page cache */ - for(i = 0; i < pagecnt; i++) { - outpage = alloc_pages(GFP_KERNEL, 0); - if(!outpage) { - while(i--) { - UnlockPage(new_pages[i]); - __free_pages(new_pages[i], 0); + /* make copies of the pages in the page cache */ + for(i = 0; i < pagecnt; i++) { + outpage = alloc_pages(GFP_KERNEL, 0); + if(!outpage) { + while(i--) { + UnlockPage(new_pages[i]); + __free_pages(new_pages[i], 0); + } + kfree(new_pages); + return -ENOMEM; } - kfree(new_pages); - return -ENOMEM; + lock_page(outpage); + memcpy(page_address(outpage), page_address(pages[i]), PAGE_SIZE); + new_pages[i] = outpage; } - lock_page(outpage); - memcpy(page_address(outpage), page_address(pages[i]), PAGE_SIZE); - new_pages[i] = outpage; } /* wait until there is some space in the write queue */ test_lock: spin_lock(&mbd_writeq_lock); - if(write_queue_cnt == WRITE_QUEUE_SZ) { + if(write_queue_cnt == write_queue_sz) { spin_unlock(&mbd_writeq_lock); DEBUG(3, "blkmtd: queue_page: Queue full\n"); current->state = TASK_UNINTERRUPTIBLE; @@ -415,11 +498,11 @@ schedule(); current->state = TASK_RUNNING; remove_wait_queue(&mtbd_sync_wq, &wait); - DEBUG(3, "blkmtd: queue_page: Queue has %d items in it\n", write_queue_cnt); + DEBUG(3, "blkmtd: queue_page_write: Queue has %d items in it\n", write_queue_cnt); goto test_lock; } - DEBUG(3, "blkmtd: queue_write_page: qhead: %d qtail: %d qcnt: %d\n", + DEBUG(3, "blkmtd: queue_page_write: qhead: %d qtail: %d qcnt: %d\n", write_queue_head, write_queue_tail, write_queue_cnt); /* fix up the queue item */ @@ -431,9 +514,9 @@ item->iserase = iserase; write_queue_head++; - write_queue_head %= WRITE_QUEUE_SZ; + write_queue_head %= write_queue_sz; write_queue_cnt++; - DEBUG(3, "blkmtd: queue_write_page: qhead: %d qtail: %d qcnt: %d\n", + DEBUG(3, "blkmtd: queue_page_write: qhead: %d qtail: %d qcnt: %d\n", write_queue_head, write_queue_tail, write_queue_cnt); spin_unlock(&mbd_writeq_lock); DEBUG(2, "blkmtd: queue_page_write: finished\n"); @@ -445,6 +528,8 @@ static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr) { mtd_raw_dev_data_t *rawdevice = mtd->priv; + struct mtd_erase_region_info *einfo = mtd->eraseregions; + int numregions = mtd->numeraseregions; size_t from; u_long len; int err = 0; @@ -460,17 +545,23 @@ from = instr->addr; len = instr->len; - /* check page alignment of start and length */ - DEBUG(2, "blkmtd: erase: dev = `%s' from = %d len = %ld\n", + /* check erase region has valid start and length */ + DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%x len = 0x%lx\n", bdevname(rawdevice->binding->bd_dev), from, len); - if(from % PAGE_SIZE) { - printk("blkmtd: erase: addr not page aligned (addr = %d)\n", from); - instr->state = MTD_ERASE_FAILED; - err = -EIO; + while(numregions) { + DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n", + einfo->offset, einfo->erasesize, einfo->numblocks); + if(from >= einfo->offset && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) { + if(len == einfo->erasesize && ( (from - einfo->offset) % einfo->erasesize == 0)) + break; + } + numregions--; + einfo++; } - if(len % PAGE_SIZE) { - printk("blkmtd: erase: len not a whole number of pages (len = %ld)\n", len); + if(!numregions) { + /* Not a valid erase block */ + printk("blkmtd: erase: invalid erase request 0x%lX @ 0x%08X\n", len, from); instr->state = MTD_ERASE_FAILED; err = -EIO; } @@ -481,9 +572,14 @@ struct page *page, **pages; int i = 0; + /* Handle the last page of the device not being whole */ + if(len < PAGE_SIZE) + len = PAGE_SIZE; + pagenr = from >> PAGE_SHIFT; pagecnt = len >> PAGE_SHIFT; DEBUG(3, "blkmtd: erase: pagenr = %d pagecnt = %d\n", pagenr, pagecnt); + pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL); if(pages == NULL) { err = -ENOMEM; @@ -491,9 +587,10 @@ goto erase_out; } + while(pagecnt) { /* get the page via the page cache */ - DEBUG(3, "blkmtd: erase: doing grap_cache_page() for page %d\n", pagenr); + DEBUG(3, "blkmtd: erase: doing grab_cache_page() for page %d\n", pagenr); page = grab_cache_page(&rawdevice->as, pagenr); if(!page) { DEBUG(3, "blkmtd: erase: grab_cache_page() failed for page %d\n", pagenr); @@ -509,7 +606,7 @@ i++; } DEBUG(3, "blkmtd: erase: queuing page write\n"); - err = queue_page_write(rawdevice, pages, from >> PAGE_SHIFT, len >> PAGE_SHIFT, 1); + err = queue_page_write(rawdevice, NULL, from >> PAGE_SHIFT, len >> PAGE_SHIFT, 1); pagecnt = len >> PAGE_SHIFT; if(!err) { while(pagecnt--) { @@ -565,7 +662,7 @@ struct page *page; int cpylen; DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr); - page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice->file); + page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice); if(IS_ERR(page)) { return PTR_ERR(page); } @@ -681,7 +778,7 @@ struct page *page; DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %d offset = %d\n", pagenr, len1, offset); - page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice->file); + page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice); if(IS_ERR(page)) { kfree(pages); @@ -714,6 +811,7 @@ memcpy(page_address(page), buf, PAGE_SIZE); pages[pagecnt++] = page; UnlockPage(page); + SetPageUptodate(page); pagenr++; pagesc--; buf += PAGE_SIZE; @@ -726,7 +824,7 @@ /* do the third region */ struct page *page; DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %d\n", pagenr, len3); - page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice->file); + page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice); if(IS_ERR(page)) { err = PTR_ERR(page); goto write_err; @@ -764,6 +862,10 @@ static void blkmtd_sync(struct mtd_info *mtd) { DECLARE_WAITQUEUE(wait, current); + mtd_raw_dev_data_t *rawdevice = mtd->priv; + if(rawdevice->readonly) + return; + DEBUG(2, "blkmtd: sync: called\n"); stuff_inq: @@ -782,36 +884,144 @@ } spin_unlock(&mbd_writeq_lock); - DEBUG(2, "blkmtdL sync: finished\n"); + DEBUG(2, "blkmtd: sync: finished\n"); } + +#ifdef BLKMTD_PROC_DEBUG +/* procfs stuff */ +static int blkmtd_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int clean = 0, dirty = 0, locked = 0; + struct list_head *temp; + int i, len, pages = 0, cnt; + MOD_INC_USE_COUNT; + spin_lock(&mbd_writeq_lock); + cnt = write_queue_cnt; + i = write_queue_tail; + while(cnt) { + if(!write_queue[i].iserase) + pages += write_queue[i].pagecnt; + i++; + i %= write_queue_sz; + cnt--; + } + + /* Count the size of the page lists */ + list_for_each(temp, &mtd_rawdevice->as.clean_pages) { + clean++; + } + list_for_each(temp, &mtd_rawdevice->as.dirty_pages) { + dirty++; + } + list_for_each(temp, &mtd_rawdevice->as.locked_pages) { + locked++; + } + + len = sprintf(page, "Write queue head: %d\nWrite queue tail: %d\n" + "Write queue count: %d\nPages in queue: %d (%dK)\n" + "Clean Pages: %d\nDirty Pages: %d\nLocked Pages: %d\n" + "nrpages: %ld\n", + write_queue_head, write_queue_tail, write_queue_cnt, + pages, pages << (PAGE_SHIFT-10), clean, dirty, locked, + mtd_rawdevice->as.nrpages); + if(len <= count) + *eof = 1; + spin_unlock(&mbd_writeq_lock); + MOD_DEC_USE_COUNT; + return len; +} +#endif + + /* Cleanup and exit - sync the device and kill of the kernel thread */ static void __exit cleanup_blkmtd(void) { - if (mtd_info) { - mtd_raw_dev_data_t *rawdevice = mtd_info->priv; - // sync the device - if (rawdevice) { - blkmtd_sync(mtd_info); +#ifdef BLKMTD_PROC_DEBUG + if(blkmtd_proc) { + remove_proc_entry("blkmtd_debug", NULL); + } +#endif + + if (mtd_rawdevice) { + /* sync the device */ + if (!mtd_rawdevice->readonly) { + blkmtd_sync(&mtd_rawdevice->mtd_info); write_task_finish = 1; wake_up_interruptible(&thr_wq); down(&thread_sem); - if(rawdevice->binding != NULL) - blkdev_put(rawdevice->binding, BDEV_RAW); - filp_close(rawdevice->file, NULL); - kfree(mtd_info->priv); } - if(mtd_info->eraseregions) - kfree(mtd_info->eraseregions); - del_mtd_device(mtd_info); - kfree(mtd_info); - mtd_info = NULL; + del_mtd_device(&mtd_rawdevice->mtd_info); + if(mtd_rawdevice->binding != NULL) + blkdev_put(mtd_rawdevice->binding, BDEV_RAW); + + if(mtd_rawdevice->mtd_info.eraseregions) + kfree(mtd_rawdevice->mtd_info.eraseregions); + if(mtd_rawdevice->mtd_info.name) + kfree(mtd_rawdevice->mtd_info.name); + + kfree(mtd_rawdevice); + } + if(write_queue) + kfree(write_queue); + + if(erase_page) { + UnlockPage(erase_page); + __free_pages(erase_page, 0); } printk("blkmtd: unloaded for %s\n", device); } extern struct module __this_module; +#ifndef MODULE + +/* Handle kernel boot params */ + + +static int __init param_blkmtd_device(char *str) +{ + device = str; + return 1; +} + + +static int __init param_blkmtd_erasesz(char *str) +{ + erasesz = simple_strtol(str, NULL, 0); + return 1; +} + + +static int __init param_blkmtd_ro(char *str) +{ + ro = simple_strtol(str, NULL, 0); + return 1; +} + + +static int __init param_blkmtd_bs(char *str) +{ + bs = simple_strtol(str, NULL, 0); + return 1; +} + + +static int __init param_blkmtd_count(char *str) +{ + count = simple_strtol(str, NULL, 0); + return 1; +} + +__setup("blkmtd_device=", param_blkmtd_device); +__setup("blkmtd_erasesz=", param_blkmtd_erasesz); +__setup("blkmtd_ro=", param_blkmtd_ro); +__setup("blkmtd_bs=", param_blkmtd_bs); +__setup("blkmtd_count=", param_blkmtd_count); + +#endif + + /* for a given size and initial erase size, calculate the number and size of each erase region */ static int __init calc_erase_regions(struct mtd_erase_region_info *info, size_t erase_size, size_t total_size) @@ -840,12 +1050,16 @@ } +extern kdev_t name_to_kdev_t(char *line) __init; + /* Startup */ static int __init init_blkmtd(void) { +#ifdef MODULE struct file *file = NULL; struct inode *inode; - mtd_raw_dev_data_t *rawdevice = NULL; +#endif + int maj, min; int i, blocksize, blocksize_bits; loff_t size = 0; @@ -854,15 +1068,12 @@ kdev_t rdev; int err; int mode; - int totalsize = 0, total_sectors = 0; int regions; - mtd_info = NULL; - - // Check args + /* Check args */ if(device == 0) { printk("blkmtd: error, missing `device' name\n"); - return 1; + return -EINVAL; } if(ro) @@ -871,12 +1082,25 @@ if(erasesz) erase_size = erasesz; - DEBUG(1, "blkmtd: got device = `%s' erase size = %dK readonly = %s\n", device, erase_size, readonly ? "yes" : "no"); - // Get a handle on the device + if(wqs) { + if(wqs < 16) + wqs = 16; + if(wqs > 4*WRITE_QUEUE_SZ) + wqs = 4*WRITE_QUEUE_SZ; + write_queue_sz = wqs; + } + + DEBUG(1, "blkmtd: device = `%s' erase size = %dK readonly = %s queue size = %d\n", + device, erase_size, readonly ? "yes" : "no", write_queue_sz); + /* Get a handle on the device */ mode = (readonly) ? O_RDONLY : O_RDWR; + +#ifdef MODULE + file = filp_open(device, mode, 0); if(IS_ERR(file)) { - DEBUG(2, "blkmtd: open_namei returned %ld\n", PTR_ERR(file)); + printk("blkmtd: error, cant open device %s\n", device); + DEBUG(2, "blkmtd: filp_open returned %ld\n", PTR_ERR(file)); return 1; } @@ -889,11 +1113,19 @@ return 1; } rdev = inode->i_rdev; - //filp_close(file, NULL); - DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n", - MAJOR(rdev), MINOR(rdev)); - maj = MAJOR(rdev); - min = MINOR(rdev); + filp_close(file, NULL); +#else + rdev = name_to_kdev_t(device); +#endif + + maj = major(rdev); + min = minor(rdev); + DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n", maj, min); + + if(kdev_none(rdev)) { + printk("blkmtd: bad block device: `%s'\n", device); + return 1; + } if(maj == MTD_BLOCK_MAJOR) { printk("blkmtd: attempting to use an MTD device as a block device\n"); @@ -918,116 +1150,159 @@ size = ((loff_t) blk_size[maj][min] << BLOCK_SIZE_BITS) >> blocksize_bits; } } - total_sectors = size; size *= blocksize; - totalsize = size; DEBUG(1, "blkmtd: size = %ld\n", (long int)size); if(size == 0) { printk("blkmtd: cant determine size\n"); return 1; } - rawdevice = (mtd_raw_dev_data_t *)kmalloc(sizeof(mtd_raw_dev_data_t), GFP_KERNEL); - if(rawdevice == NULL) { + + mtd_rawdevice = (mtd_raw_dev_data_t *)kmalloc(sizeof(mtd_raw_dev_data_t), GFP_KERNEL); + if(mtd_rawdevice == NULL) { err = -ENOMEM; goto init_err; } - memset(rawdevice, 0, sizeof(mtd_raw_dev_data_t)); - // get the block device - rawdevice->binding = bdget(kdev_t_to_nr(MKDEV(maj, min))); - err = blkdev_get(rawdevice->binding, mode, 0, BDEV_RAW); + memset(mtd_rawdevice, 0, sizeof(mtd_raw_dev_data_t)); + /* get the block device */ + mtd_rawdevice->binding = bdget(kdev_t_to_nr(mk_kdev(maj, min))); + err = blkdev_get(mtd_rawdevice->binding, mode, 0, BDEV_RAW); if (err) { goto init_err; } - rawdevice->totalsize = totalsize; - rawdevice->total_sectors = total_sectors; - rawdevice->sector_size = blocksize; - rawdevice->sector_bits = blocksize_bits; - rawdevice->readonly = readonly; - - DEBUG(2, "sector_size = %d, sector_bits = %d\n", rawdevice->sector_size, rawdevice->sector_bits); - - mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL); - if (mtd_info == NULL) { - err = -ENOMEM; + mtd_rawdevice->totalsize = size; + mtd_rawdevice->sector_size = blocksize; + mtd_rawdevice->sector_bits = blocksize_bits; + mtd_rawdevice->readonly = readonly; + + /* See if device ends on page boundary */ + if(size % PAGE_SIZE) { + mtd_rawdevice->partial_last_page = size >> PAGE_SHIFT; + mtd_rawdevice->last_page_sectors = (size & (PAGE_SIZE-1)) >> blocksize_bits; + } + + DEBUG(2, "sector_size = %d, sector_bits = %d, partial_last_page = %d last_page_sectors = %d\n", + mtd_rawdevice->sector_size, mtd_rawdevice->sector_bits, + mtd_rawdevice->partial_last_page, mtd_rawdevice->last_page_sectors); + + /* Setup the MTD structure */ + /* make the name contain the block device in */ + mtd_rawdevice->mtd_info.name = kmalloc(9 + strlen(device), GFP_KERNEL); + if(mtd_rawdevice->mtd_info.name == NULL) goto init_err; - } - memset(mtd_info, 0, sizeof(*mtd_info)); - // Setup the MTD structure - mtd_info->name = "blkmtd block device"; + sprintf(mtd_rawdevice->mtd_info.name, "blkmtd: %s", device); if(readonly) { - mtd_info->type = MTD_ROM; - mtd_info->flags = MTD_CAP_ROM; - mtd_info->erasesize = erase_size << 10; + mtd_rawdevice->mtd_info.type = MTD_ROM; + mtd_rawdevice->mtd_info.flags = MTD_CAP_ROM; + mtd_rawdevice->mtd_info.erasesize = erase_size << 10; } else { - mtd_info->type = MTD_RAM; - mtd_info->flags = MTD_CAP_RAM; - mtd_info->erasesize = erase_size << 10; - } - mtd_info->size = size; - mtd_info->erase = blkmtd_erase; - mtd_info->read = blkmtd_read; - mtd_info->write = blkmtd_write; - mtd_info->sync = blkmtd_sync; - mtd_info->point = 0; - mtd_info->unpoint = 0; + mtd_rawdevice->mtd_info.type = MTD_RAM; + mtd_rawdevice->mtd_info.flags = MTD_CAP_RAM; + mtd_rawdevice->mtd_info.erasesize = erase_size << 10; + } + mtd_rawdevice->mtd_info.size = size; + mtd_rawdevice->mtd_info.erase = blkmtd_erase; + mtd_rawdevice->mtd_info.read = blkmtd_read; + mtd_rawdevice->mtd_info.write = blkmtd_write; + mtd_rawdevice->mtd_info.sync = blkmtd_sync; + mtd_rawdevice->mtd_info.point = 0; + mtd_rawdevice->mtd_info.unpoint = 0; - mtd_info->priv = rawdevice; + mtd_rawdevice->mtd_info.priv = mtd_rawdevice; regions = calc_erase_regions(NULL, erase_size << 10, size); DEBUG(1, "blkmtd: init: found %d erase regions\n", regions); - mtd_info->eraseregions = kmalloc(regions * sizeof(struct mtd_erase_region_info), GFP_KERNEL); - if(mtd_info->eraseregions == NULL) { + mtd_rawdevice->mtd_info.eraseregions = kmalloc(regions * sizeof(struct mtd_erase_region_info), GFP_KERNEL); + if(mtd_rawdevice->mtd_info.eraseregions == NULL) { + err = -ENOMEM; + goto init_err; } - mtd_info->numeraseregions = regions; - calc_erase_regions(mtd_info->eraseregions, erase_size << 10, size); + mtd_rawdevice->mtd_info.numeraseregions = regions; + calc_erase_regions(mtd_rawdevice->mtd_info.eraseregions, erase_size << 10, size); /* setup the page cache info */ - INIT_LIST_HEAD(&rawdevice->as.clean_pages); - INIT_LIST_HEAD(&rawdevice->as.dirty_pages); - INIT_LIST_HEAD(&rawdevice->as.locked_pages); - rawdevice->as.nrpages = 0; - rawdevice->as.a_ops = &blkmtd_aops; - rawdevice->as.host = inode; - rawdevice->as.i_mmap = NULL; - rawdevice->as.i_mmap_shared = NULL; - spin_lock_init(&rawdevice->as.i_shared_lock); - rawdevice->as.gfp_mask = GFP_KERNEL; - rawdevice->file = file; - - file->private_data = rawdevice; + + mtd_rawdevice->as.nrpages = 0; + INIT_LIST_HEAD(&mtd_rawdevice->as.clean_pages); + INIT_LIST_HEAD(&mtd_rawdevice->as.dirty_pages); + INIT_LIST_HEAD(&mtd_rawdevice->as.locked_pages); + mtd_rawdevice->as.host = NULL; + spin_lock_init(&(mtd_rawdevice->as.i_shared_lock)); + + mtd_rawdevice->as.a_ops = &blkmtd_aops; + INIT_LIST_HEAD(&mtd_rawdevice->as.i_mmap); + INIT_LIST_HEAD(&mtd_rawdevice->as.i_mmap_shared); + mtd_rawdevice->as.gfp_mask = GFP_KERNEL; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - mtd_info->module = THIS_MODULE; + mtd_rawdevice->mtd_info.module = THIS_MODULE; #endif - if (add_mtd_device(mtd_info)) { - err = -EIO; - goto init_err; - } - init_waitqueue_head(&thr_wq); - init_waitqueue_head(&mtbd_sync_wq); - DEBUG(3, "blkmtd: init: kernel task @ %p\n", write_queue_task); - DEBUG(2, "blkmtd: init: starting kernel task\n"); - kernel_thread(write_queue_task, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - DEBUG(2, "blkmtd: init: started\n"); - printk("blkmtd loaded: version = %s using %s erase_size = %dK %s\n", VERSION, device, erase_size, (readonly) ? "(read-only)" : ""); - return 0; + if (add_mtd_device(&mtd_rawdevice->mtd_info)) { + err = -EIO; + goto init_err; + } + if(!mtd_rawdevice->readonly) { + /* Allocate the write queue */ + write_queue = kmalloc(write_queue_sz * sizeof(mtdblkdev_write_queue_t), GFP_KERNEL); + if(!write_queue) { + err = -ENOMEM; + goto init_err; + } + /* Set up the erase page */ + erase_page = alloc_pages(GFP_KERNEL, 0); + if(erase_page == NULL) { + err = -ENOMEM; + goto init_err; + } + memset(page_address(erase_page), 0xff, PAGE_SIZE); + lock_page(erase_page); + + init_waitqueue_head(&thr_wq); + init_waitqueue_head(&mtbd_sync_wq); + DEBUG(3, "blkmtd: init: kernel task @ %p\n", write_queue_task); + DEBUG(2, "blkmtd: init: starting kernel task\n"); + kernel_thread(write_queue_task, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + DEBUG(2, "blkmtd: init: started\n"); + printk("blkmtd loaded: version = %s using %s erase_size = %dK %s\n", + VERSION, device, erase_size, (readonly) ? "(read-only)" : ""); + } + +#ifdef BLKMTD_PROC_DEBUG + /* create proc entry */ + DEBUG(2, "Creating /proc/blkmtd_debug\n"); + blkmtd_proc = create_proc_read_entry("blkmtd_debug", 0444, + NULL, blkmtd_proc_read, NULL); + if(blkmtd_proc == NULL) { + printk("Cant create /proc/blkmtd_debug\n"); + } else { + blkmtd_proc->owner = THIS_MODULE; + } +#endif + + /* Everything is ok if we got here */ + return 0; + init_err: - if(!rawdevice) { - if(rawdevice->binding) - blkdev_put(rawdevice->binding, BDEV_RAW); - kfree(rawdevice); - rawdevice = NULL; - } - if(mtd_info) { - if(mtd_info->eraseregions) - kfree(mtd_info->eraseregions); - kfree(mtd_info); - mtd_info = NULL; - } - return err; + if(mtd_rawdevice) { + if(mtd_rawdevice->mtd_info.eraseregions) + kfree(mtd_rawdevice->mtd_info.eraseregions); + if(mtd_rawdevice->mtd_info.name) + kfree(mtd_rawdevice->mtd_info.name); + if(mtd_rawdevice->binding) + blkdev_put(mtd_rawdevice->binding, BDEV_RAW); + kfree(mtd_rawdevice); + } + + if(write_queue) { + kfree(write_queue); + write_queue = NULL; + } + + if(erase_page) + __free_pages(erase_page, 0); + return err; } module_init(init_blkmtd); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/devices/pmc551.c linux-2.5/drivers/mtd/devices/pmc551.c --- linux-2.5.5/drivers/mtd/devices/pmc551.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/mtd/devices/pmc551.c Sun Mar 3 17:54:35 2002 @@ -715,7 +715,7 @@ } /* - * This is needed untill the driver is capable of reading the + * This is needed until the driver is capable of reading the * onboard I2C SROM to discover the "real" memory size. */ if(msize) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/ftl.c linux-2.5/drivers/mtd/ftl.c --- linux-2.5.5/drivers/mtd/ftl.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/mtd/ftl.c Fri Feb 8 02:38:25 2002 @@ -95,8 +95,6 @@ /* Funky stuff for setting up a block device */ #define MAJOR_NR FTL_MAJOR #define DEVICE_NAME "ftl" -#define DEVICE_REQUEST do_ftl_request -#define DEVICE_ON(device) #define DEVICE_OFF(device) #define DEVICE_NR(minor) ((minor)>>5) @@ -195,7 +193,7 @@ u_int cmd, u_long arg); static int ftl_open(struct inode *inode, struct file *file); static release_t ftl_close(struct inode *inode, struct file *file); -static int ftl_reread_partitions(int minor); +static int ftl_reread_partitions(kdev_t dev); static void ftl_erase_callback(struct erase_info *done); @@ -842,7 +840,7 @@ static int ftl_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); partition_t *partition; if (minor>>4 >= MAX_MTD_DEVICES) @@ -878,7 +876,7 @@ static release_t ftl_close(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); partition_t *part = myparts[minor >> 4]; int i; @@ -1114,7 +1112,7 @@ u_int cmd, u_long arg) { struct hd_geometry *geo = (struct hd_geometry *)arg; - int ret = 0, minor = MINOR(inode->i_rdev); + int ret = 0, minor = minor(inode->i_rdev); partition_t *part= myparts[minor >> 4]; u_long sect; @@ -1139,7 +1137,7 @@ ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg); break; case BLKRRPART: - ret = ftl_reread_partitions(minor); + ret = ftl_reread_partitions(inode->i_rdev); break; case BLKROSET: case BLKROGET: @@ -1161,7 +1159,7 @@ static int ftl_reread_partitions(kdev_t dev) { - int minor = MINOR(dev); + int minor = minor(dev); partition_t *part = myparts[minor >> 4]; int res; @@ -1197,7 +1195,7 @@ // sti(); INIT_REQUEST; - minor = MINOR(CURRENT->rq_dev); + minor = minor(CURRENT->rq_dev); part = myparts[minor >> 4]; if (part) { @@ -1369,7 +1367,7 @@ unregister_blkdev(FTL_MAJOR, "ftl"); blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR)); - bklk_clear(FTL_MAJOR); + blk_clear(FTL_MAJOR); del_gendisk(&ftl_gendisk); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/maps/Config.in linux-2.5/drivers/mtd/maps/Config.in --- linux-2.5.5/drivers/mtd/maps/Config.in Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/mtd/maps/Config.in Sun Mar 3 17:54:35 2002 @@ -37,6 +37,12 @@ fi if [ "$CONFIG_MIPS" = "y" ]; then + dep_tristate ' Pb1000 boot flash device' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000 + dep_tristate ' Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500 + if [ "$CONFIG_MTD_PB1500" = "y" -o "$CONFIG_MTD_PB1500" = "m" ]; then + bool ' Pb1500 boot flash device' CONFIG_MTD_PB1500_BOOT + bool ' Pb1500 user flash device (2nd 32MB bank)' CONFIG_MTD_PB1500_USER + fi dep_tristate ' Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board' CONFIG_MTD_CSTM_MIPS_IXX $CONFIG_MTD_CFI $CONFIG_MTD_JEDEC $CONFIG_MTD_PARTITIONS if [ "$CONFIG_MTD_CSTM_MIPS_IXX" = "y" -o "$CONFIG_MTD_CSTM_MIPS_IXX" = "m" ]; then hex ' Physical start address of flash mapping' CONFIG_MTD_CSTM_MIPS_IXX_START 0x8000000 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/maps/Makefile linux-2.5/drivers/mtd/maps/Makefile --- linux-2.5.5/drivers/mtd/maps/Makefile Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/mtd/maps/Makefile Sun Mar 3 17:54:35 2002 @@ -29,5 +29,7 @@ obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o obj-$(CONFIG_MTD_OCELOT) += ocelot.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o +obj-$(CONFIG_MTD_PB1000) += pb1xxx-flash.o +obj-$(CONFIG_MTD_PB1500) += pb1xxx-flash.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/maps/elan-104nc.c linux-2.5/drivers/mtd/maps/elan-104nc.c --- linux-2.5.5/drivers/mtd/maps/elan-104nc.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/mtd/maps/elan-104nc.c Sun Feb 17 23:08:54 2002 @@ -213,7 +213,7 @@ /* MTD device for all of the flash. */ static struct mtd_info *all_mtd; -static void __exit cleanup_elan_104nc(void) +static void cleanup_elan_104nc(void) { if( all_mtd ) { del_mtd_partitions( all_mtd ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/maps/pb1xxx-flash.c linux-2.5/drivers/mtd/maps/pb1xxx-flash.c --- linux-2.5.5/drivers/mtd/maps/pb1xxx-flash.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/mtd/maps/pb1xxx-flash.c Mon Mar 4 01:54:03 2002 @@ -0,0 +1,253 @@ +/* + * Flash memory access on Alchemy Pb1xxx boards + * + * (C) 2001 Pete Popov + * + * $Id: pb1xxx-flash.c,v 1.1 2002/02/27 17:23:28 marcelo Exp $ + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifdef DEBUG_RW +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#ifdef CONFIG_MIPS_PB1000 +#define WINDOW_ADDR 0x1F800000 +#define WINDOW_SIZE 0x800000 +#endif + +__u8 physmap_read8(struct map_info *map, unsigned long ofs) +{ + __u8 ret; + ret = __raw_readb(map->map_priv_1 + ofs); + DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); + return ret; +} + +__u16 physmap_read16(struct map_info *map, unsigned long ofs) +{ + __u16 ret; + ret = __raw_readw(map->map_priv_1 + ofs); + DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); + return ret; +} + +__u32 physmap_read32(struct map_info *map, unsigned long ofs) +{ + __u32 ret; + ret = __raw_readl(map->map_priv_1 + ofs); + DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); + return ret; +} + +void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to); + memcpy_fromio(to, map->map_priv_1 + from, len); +} + +void physmap_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +void physmap_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +void physmap_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from); + memcpy_toio(map->map_priv_1 + to, from, len); +} + + + +static struct map_info pb1xxx_map = { + name: "Pb1xxx flash", + read8: physmap_read8, + read16: physmap_read16, + read32: physmap_read32, + copy_from: physmap_copy_from, + write8: physmap_write8, + write16: physmap_write16, + write32: physmap_write32, + copy_to: physmap_copy_to, +}; + + +#ifdef CONFIG_MIPS_PB1000 + +static unsigned long flash_size = 0x00800000; +static unsigned char flash_buswidth = 4; +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "yamon env", + size: 0x00020000, + offset: 0, + mask_flags: MTD_WRITEABLE + },{ + name: "User FS", + size: 0x003e0000, + offset: 0x20000, + },{ + name: "boot code", + size: 0x100000, + offset: 0x400000, + mask_flags: MTD_WRITEABLE + },{ + name: "raw/kernel", + size: 0x300000, + offset: 0x500000 + } +}; + +#elif defined(CONFIG_MIPS_PB1500) + +static unsigned char flash_buswidth = 4; +#if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) +/* both 32MB banks will be used. Combine the first 32MB bank and the + * first 28MB of the second bank together into a single jffs/jffs2 + * partition. + */ +static unsigned long flash_size = 0x04000000; +#define WINDOW_ADDR 0x1C000000 +#define WINDOW_SIZE 0x4000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "User FS", + size: 0x3c00000, + offset: 0x0000000 + },{ + name: "yamon", + size: 0x0100000, + offset: 0x3c00000, + mask_flags: MTD_WRITEABLE + },{ + name: "raw kernel", + size: 0x02c0000, + offset: 0x3d00000 + } +}; +#elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER) +static unsigned long flash_size = 0x02000000; +#define WINDOW_ADDR 0x1E000000 +#define WINDOW_SIZE 0x2000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "User FS", + size: 0x1c00000, + offset: 0x0000000 + },{ + name: "yamon", + size: 0x0100000, + offset: 0x1c00000, + mask_flags: MTD_WRITEABLE + },{ + name: "raw kernel", + size: 0x02c0000, + offset: 0x1d00000 + } +}; +#elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) +static unsigned long flash_size = 0x02000000; +#define WINDOW_ADDR 0x1C000000 +#define WINDOW_SIZE 0x2000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + name: "User FS", + size: 0x1e00000, + offset: 0x0000000 + },{ + name: "raw kernel", + size: 0x0200000, + offset: 0x1e00000, + } +}; +#else +#error MTD_PB1500 define combo error /* should never happen */ +#endif +#else +#error Unsupported board +#endif + + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_partition *parsed_parts; +static struct mtd_info *mymtd; + +int __init pb1xxx_mtd_init(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + char *part_type; + + /* Default flash buswidth */ + pb1xxx_map.buswidth = flash_buswidth; + + /* + * Static partition definition selection + */ + part_type = "static"; + parts = pb1xxx_partitions; + nb_parts = NB_OF(pb1xxx_partitions); + pb1xxx_map.size = flash_size; + + /* + * Now let's probe for the actual flash. Do it here since + * specific machine settings might have been set above. + */ + printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n", + pb1xxx_map.buswidth*8); + pb1xxx_map.map_priv_1 = + (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + mymtd = do_map_probe("cfi_probe", &pb1xxx_map); + if (!mymtd) return -ENXIO; + mymtd->module = THIS_MODULE; + + add_mtd_partitions(mymtd, parts, nb_parts); + return 0; +} + +static void __exit pb1xxx_mtd_cleanup(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + if (parsed_parts) + kfree(parsed_parts); + } +} + +module_init(pb1xxx_mtd_init); +module_exit(pb1xxx_mtd_cleanup); + +MODULE_AUTHOR("Pete Popov"); +MODULE_DESCRIPTION("Pb1xxx CFI map driver"); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/maps/sbc_gxx.c linux-2.5/drivers/mtd/maps/sbc_gxx.c --- linux-2.5.5/drivers/mtd/maps/sbc_gxx.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/mtd/maps/sbc_gxx.c Sun Feb 17 23:08:54 2002 @@ -221,7 +221,7 @@ /* MTD device for all of the flash. */ static struct mtd_info *all_mtd; -static void __exit cleanup_sbc_gxx(void) +static void cleanup_sbc_gxx(void) { if( all_mtd ) { del_mtd_partitions( all_mtd ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/mtdblock.c linux-2.5/drivers/mtd/mtdblock.c --- linux-2.5.5/drivers/mtd/mtdblock.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/mtd/mtdblock.c Fri Mar 1 15:07:38 2002 @@ -16,11 +16,8 @@ #define MAJOR_NR MTD_BLOCK_MAJOR #define DEVICE_NAME "mtdblock" -#define DEVICE_REQUEST mtdblock_request #define DEVICE_NR(device) (device) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) -#define DEVICE_NO_RANDOM +#define LOCAL_END_REQUEST #include /* for old kernels... */ #ifndef QUEUE_EMPTY @@ -283,7 +280,7 @@ if (!inode) return -EINVAL; - dev = MINOR(inode->i_rdev); + dev = minor(inode->i_rdev); if (dev >= MAX_MTD_DEVICES) return -EINVAL; @@ -373,7 +370,7 @@ invalidate_device(inode->i_rdev, 1); - dev = MINOR(inode->i_rdev); + dev = minor(inode->i_rdev); mtdblk = mtdblks[dev]; down(&mtdblk->cache_sem); @@ -417,18 +414,20 @@ INIT_REQUEST; req = CURRENT; spin_unlock_irq(&QUEUE->queue_lock); - mtdblk = mtdblks[MINOR(req->rq_dev)]; + mtdblk = mtdblks[minor(req->rq_dev)]; res = 0; - if (MINOR(req->rq_dev) >= MAX_MTD_DEVICES) + if (minor(req->rq_dev) >= MAX_MTD_DEVICES) panic(__FUNCTION__": minor out of bound"); + if (req->flags & REQ_CMD) + goto end_req; + if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9)) goto end_req; // Handle the request - switch (req->cmd) - { + switch (rq_data_dir(CURRENT)) { int err; case READ: @@ -459,7 +458,11 @@ end_req: spin_lock_irq(&QUEUE->queue_lock); - end_request(res); + if (!end_that_request_first(req, res, req->hard_cur_sectors)) { + blkdev_dequeue_request(req); + end_that_request_last(req); + } + } } @@ -519,7 +522,7 @@ { struct mtdblk_dev *mtdblk; - mtdblk = mtdblks[MINOR(inode->i_rdev)]; + mtdblk = mtdblks[minor(inode->i_rdev)]; #ifdef PARANOIA if (!mtdblk) @@ -537,7 +540,7 @@ if(!capable(CAP_SYS_ADMIN)) return -EACCES; #endif - fsync_dev(inode->i_rdev); + fsync_bdev(inode->i_bdev); invalidate_buffers(inode->i_rdev); down(&mtdblk->cache_sem); write_cached_data(mtdblk); @@ -597,6 +600,8 @@ } #endif +static spinlock_t mtddev_lock = SPIN_LOCK_UNLOCKED; + int __init init_mtdblock(void) { int i; @@ -630,7 +635,7 @@ blksize_size[MAJOR_NR] = mtd_blksizes; blk_size[MAJOR_NR] = mtd_sizes; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request, &mtddev_lock); kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND); return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/mtdblock_ro.c linux-2.5/drivers/mtd/mtdblock_ro.c --- linux-2.5.5/drivers/mtd/mtdblock_ro.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/mtd/mtdblock_ro.c Fri Mar 1 15:07:38 2002 @@ -16,13 +16,10 @@ #include #include +#define LOCAL_END_REQUEST #define MAJOR_NR MTD_BLOCK_MAJOR #define DEVICE_NAME "mtdblock" -#define DEVICE_REQUEST mtdblock_request #define DEVICE_NR(device) (device) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) -#define DEVICE_NO_RANDOM #include #if LINUX_VERSION_CODE < 0x20300 @@ -52,7 +49,7 @@ if (inode == 0) return -EINVAL; - dev = MINOR(inode->i_rdev); + dev = minor(inode->i_rdev); mtd = get_mtd_device(NULL, dev); if (!mtd) @@ -81,7 +78,7 @@ invalidate_device(inode->i_rdev, 1); - dev = MINOR(inode->i_rdev); + dev = minor(inode->i_rdev); mtd = __get_mtd_device(NULL, dev); if (!mtd) { @@ -97,8 +94,15 @@ DEBUG(1, "ok\n"); release_return(0); -} +} +static inline void mtdblock_end_request(struct request *req, int uptodate) +{ + if (end_that_request_first(req, uptodate, req->hard_cur_sectors)) + return; + blkdev_dequeue_request(req); + end_that_request_last(req); +} static void mtdblock_request(RQFUNC_ARG) { @@ -113,19 +117,19 @@ INIT_REQUEST; current_request = CURRENT; - if (MINOR(current_request->rq_dev) >= MAX_MTD_DEVICES) + if (minor(current_request->rq_dev) >= MAX_MTD_DEVICES) { printk("mtd: Unsupported device!\n"); - end_request(0); + mtdblock_end_request(current_request, 0); continue; } // Grab our MTD structure - mtd = __get_mtd_device(NULL, MINOR(current_request->rq_dev)); + mtd = __get_mtd_device(NULL, minor(current_request->rq_dev)); if (!mtd) { printk("MTD device %d doesn't appear to exist any more\n", CURRENT_DEV); - end_request(0); + mtdblock_end_request(current_request, 0); } if (current_request->sector << 9 > mtd->size || @@ -133,7 +137,7 @@ { printk("mtd: Attempt to read past end of device!\n"); printk("size: %x, sector: %lx, nr_sectors %lx\n", mtd->size, current_request->sector, current_request->nr_sectors); - end_request(0); + mtdblock_end_request(current_request, 0); continue; } @@ -192,7 +196,7 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) spin_lock_irq(&io_request_lock); #endif - end_request(res); + mtdblock_end_request(current_request, res); } } @@ -203,7 +207,7 @@ { struct mtd_info *mtd; - mtd = __get_mtd_device(NULL, MINOR(inode->i_rdev)); + mtd = __get_mtd_device(NULL, minor(inode->i_rdev)); if (!mtd) return -EINVAL; @@ -217,7 +221,7 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) if(!capable(CAP_SYS_ADMIN)) return -EACCES; #endif - fsync_dev(inode->i_rdev); + fsync_bdev(inode->i_bdev); invalidate_buffers(inode->i_rdev); if (mtd->sync) mtd->sync(mtd); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/mtdchar.c linux-2.5/drivers/mtd/mtdchar.c --- linux-2.5.5/drivers/mtd/mtdchar.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/mtd/mtdchar.c Thu Feb 7 20:00:06 2002 @@ -64,7 +64,7 @@ static int mtd_open(struct inode *inode, struct file *file) { - int minor = MINOR(inode->i_rdev); + int minor = minor(inode->i_rdev); int devnum = minor >> 1; struct mtd_info *mtd; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/nand/nand_ecc.c linux-2.5/drivers/mtd/nand/nand_ecc.c --- linux-2.5.5/drivers/mtd/nand/nand_ecc.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/mtd/nand/nand_ecc.c Fri Feb 8 15:46:33 2002 @@ -207,3 +207,5 @@ EXPORT_SYMBOL(nand_calculate_ecc); EXPORT_SYMBOL(nand_correct_data); + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/nand/spia.c linux-2.5/drivers/mtd/nand/spia.c --- linux-2.5.5/drivers/mtd/nand/spia.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/mtd/nand/spia.c Sun Mar 3 17:54:35 2002 @@ -113,7 +113,7 @@ this->ALE = 0x02; this->NCE = 0x04; - /* Scan to find existance of the device */ + /* Scan to find existence of the device */ if (nand_scan (spia_mtd)) { kfree (spia_mtd); return -ENXIO; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/mtd/nftlcore.c linux-2.5/drivers/mtd/nftlcore.c --- linux-2.5.5/drivers/mtd/nftlcore.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/mtd/nftlcore.c Fri Mar 1 15:07:38 2002 @@ -40,7 +40,6 @@ /* NFTL block device stuff */ #define MAJOR_NR NFTL_MAJOR -#define DEVICE_REQUEST nftl_request #define DEVICE_OFF(device) @@ -156,7 +155,7 @@ #if LINUX_VERSION_CODE < 0x20328 resetup_one_dev(&nftl_gendisk, firstfree); #else - grok_partitions(MKDEV(MAJOR_NR,firstfree<nr_sects); #endif } @@ -779,7 +778,7 @@ struct NFTLrecord *nftl; int res; - nftl = NFTLs[MINOR(inode->i_rdev) >> NFTL_PARTN_BITS]; + nftl = NFTLs[minor(inode->i_rdev) >> NFTL_PARTN_BITS]; if (!nftl) return -EINVAL; @@ -795,7 +794,7 @@ } case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; - fsync_dev(inode->i_rdev); + fsync_bdev(inode->i_bdev); invalidate_buffers(inode->i_rdev); if (nftl->mtd->sync) nftl->mtd->sync(nftl->mtd); @@ -853,7 +852,7 @@ (req->cmd == READ) ? "Read " : "Write", req->sector, req->current_nr_sectors); - dev = MINOR(req->rq_dev); + dev = minor(req->rq_dev); block = req->sector; nsect = req->current_nr_sectors; buffer = req->buffer; @@ -875,7 +874,7 @@ if (block + nsect > part_table[dev].nr_sects) { /* access past the end of device */ printk("nftl%c%d: bad access: block = %d, count = %d\n", - (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect); + (minor(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect); up(&nftl->mutex); res = 0; /* fail */ goto repeat; @@ -933,7 +932,7 @@ static int nftl_open(struct inode *ip, struct file *fp) { - int nftlnum = MINOR(ip->i_rdev) >> NFTL_PARTN_BITS; + int nftlnum = minor(ip->i_rdev) >> NFTL_PARTN_BITS; struct NFTLrecord *thisNFTL; thisNFTL = NFTLs[nftlnum]; @@ -947,7 +946,7 @@ #endif if (!thisNFTL) { DEBUG(MTD_DEBUG_LEVEL2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n", - nftlnum, ip->i_rdev, ip, fp); + nftlnum, minor(ip->i_rdev), ip, fp); return -ENODEV; } @@ -967,7 +966,7 @@ { struct NFTLrecord *thisNFTL; - thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16]; + thisNFTL = NFTLs[minor(inode->i_rdev) / 16]; DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/3c505.c linux-2.5/drivers/net/3c505.c --- linux-2.5.5/drivers/net/3c505.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/net/3c505.c Mon Feb 18 23:03:02 2002 @@ -1350,87 +1350,6 @@ } } -/** - * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls - * @dev: network interface on which out-of-band action is to be performed - * @useraddr: userspace address to which data is to be read and returned - * - * Process the various commands of the SIOCETHTOOL interface. - */ - -static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) -{ - u32 ethcmd; - - /* dev_ioctl() in ../../net/core/dev.c has already checked - capable(CAP_NET_ADMIN), so don't bother with that here. */ - - if (get_user(ethcmd, (u32 *)useraddr)) - return -EFAULT; - - switch (ethcmd) { - - case ETHTOOL_GDRVINFO: { - struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; - strcpy (info.driver, DRV_NAME); - strcpy (info.version, DRV_VERSION); - sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr); - if (copy_to_user (useraddr, &info, sizeof (info))) - return -EFAULT; - return 0; - } - - /* get message-level */ - case ETHTOOL_GMSGLVL: { - struct ethtool_value edata = {ETHTOOL_GMSGLVL}; - edata.data = debug; - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } - /* set message-level */ - case ETHTOOL_SMSGLVL: { - struct ethtool_value edata; - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - debug = edata.data; - return 0; - } - - default: - break; - } - - return -EOPNOTSUPP; -} - -/** - * netdev_ioctl: Handle network interface ioctls - * @dev: network interface on which out-of-band action is to be performed - * @rq: user request data - * @cmd: command issued by user - * - * Process the various out-of-band ioctls passed to this driver. - */ - -static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) -{ - int rc = 0; - - switch (cmd) { - case SIOCETHTOOL: - rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); - break; - - default: - rc = -EOPNOTSUPP; - break; - } - - return rc; -} - - /****************************************************** * * initialise Etherlink Plus board diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/3c509.c linux-2.5/drivers/net/3c509.c --- linux-2.5.5/drivers/net/3c509.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/net/3c509.c Mon Mar 4 01:41:52 2002 @@ -45,11 +45,13 @@ - Reviewed against 1.18 from scyld.com v1.18a 17Nov2001 Jeff Garzik - ethtool support + v1.18b 1Mar2002 Zwane Mwaikambo + - Power Management support */ #define DRV_NAME "3c509" -#define DRV_VERSION "1.18a" -#define DRV_RELDATE "17Nov2001" +#define DRV_VERSION "1.18b" +#define DRV_RELDATE "1Mar2002" /* A few values that may be tweaked. */ @@ -82,8 +84,9 @@ #include #include #include +#include -static char versionA[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE "becker@scyld.com\n"; +static char versionA[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n"; static char versionB[] __initdata = "http://www.scyld.com/network/3c509.html\n"; #ifdef EL3_DEBUG @@ -116,7 +119,8 @@ FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11, SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11, SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11, - StatsDisable = 22<<11, StopCoax = 23<<11,}; + StatsDisable = 22<<11, StopCoax = 23<<11, PowerUp = 27<<11, + PowerDown = 28<<11, PowerAuto = 29<<11}; enum c509status { IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004, @@ -152,6 +156,9 @@ int head, size; struct sk_buff *queue[SKB_QUEUE_SIZE]; char mca_slot; +#ifdef CONFIG_PM + struct pm_dev *pmdev; +#endif }; static int id_port __initdata = 0x110; /* Start with 0x110 to avoid new sound cards.*/ static struct net_device *el3_root_dev; @@ -168,6 +175,13 @@ static void set_multicast_list(struct net_device *dev); static void el3_tx_timeout (struct net_device *dev); static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); +static void el3_down(struct net_device *dev); +static void el3_up(struct net_device *dev); +#ifdef CONFIG_PM +static int el3_suspend(struct pm_dev *pdev); +static int el3_resume(struct pm_dev *pdev); +static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data); +#endif #ifdef CONFIG_MCA struct el3_mca_adapters_struct { @@ -219,7 +233,7 @@ #endif /* __ISAPNP__ */ static int nopnp; -int __init el3_probe(struct net_device *dev) +int __init el3_probe(struct net_device *dev, int card_idx) { struct el3_private *lp; short lrs_state = 0xff, i; @@ -525,6 +539,16 @@ dev->watchdog_timeo = TX_TIMEOUT; dev->do_ioctl = netdev_ioctl; +#ifdef CONFIG_PM + /* register power management */ + lp->pmdev = pm_register(PM_ISA_DEV, card_idx, el3_pm_callback); + if (lp->pmdev) { + struct pm_dev *p; + p = lp->pmdev; + p->data = (struct net_device *)dev; + } +#endif + /* Fill in the generic fields of the device structure. */ ether_setup(dev); return 0; @@ -581,53 +605,7 @@ printk("%s: Opening, IRQ %d status@%x %4.4x.\n", dev->name, dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS)); - /* Activate board: this is probably unnecessary. */ - outw(0x0001, ioaddr + 4); - - /* Set the IRQ line. */ - outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ); - - /* Set the station address in window 2 each time opened. */ - EL3WINDOW(2); - - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); - - if (dev->if_port == 3) - /* Start the thinnet transceiver. We should really wait 50ms...*/ - outw(StartCoax, ioaddr + EL3_CMD); - else if (dev->if_port == 0) { - /* 10baseT interface, enabled link beat and jabber check. */ - EL3WINDOW(4); - outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA); - } - - /* Switch to the stats window, and clear all stats by reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - EL3WINDOW(6); - for (i = 0; i < 9; i++) - inb(ioaddr + i); - inw(ioaddr + 10); - inw(ioaddr + 12); - - /* Switch to register set 1 for normal use. */ - EL3WINDOW(1); - - /* Accept b-case and phys addr only. */ - outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - - netif_start_queue(dev); - - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ - /* Allow status bits to be seen. */ - outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); - /* Ack all pending events, and set active indicator mask. */ - outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, - ioaddr + EL3_CMD); - outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull, - ioaddr + EL3_CMD); + el3_up(dev); if (el3_debug > 3) printk("%s: Opened 3c509 IRQ %d status %4.4x.\n", @@ -986,23 +964,7 @@ if (el3_debug > 2) printk("%s: Shutting down ethercard.\n", dev->name); - netif_stop_queue(dev); - - /* Turn off statistics ASAP. We update lp->stats below. */ - outw(StatsDisable, ioaddr + EL3_CMD); - - /* Disable the receiver and transmitter. */ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); - - if (dev->if_port == 3) - /* Turn off thinnet power. Green! */ - outw(StopCoax, ioaddr + EL3_CMD); - else if (dev->if_port == 0) { - /* Disable link beat and jabber, if_port may change ere next open(). */ - EL3WINDOW(4); - outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA); - } + el3_down(dev); free_irq(dev->irq, dev); /* Switching back to window 0 disables the IRQ. */ @@ -1010,7 +972,6 @@ /* But we explicitly zero the IRQ line select anyway. */ outw(0x0f00, ioaddr + WN0_IRQ); - update_stats(dev); return 0; } @@ -1092,7 +1053,157 @@ return rc; } - + +static void el3_down(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + + netif_stop_queue(dev); + + /* Turn off statistics ASAP. We update lp->stats below. */ + outw(StatsDisable, ioaddr + EL3_CMD); + + /* Disable the receiver and transmitter. */ + outw(RxDisable, ioaddr + EL3_CMD); + outw(TxDisable, ioaddr + EL3_CMD); + + if (dev->if_port == 3) + /* Turn off thinnet power. Green! */ + outw(StopCoax, ioaddr + EL3_CMD); + else if (dev->if_port == 0) { + /* Disable link beat and jabber, if_port may change ere next open(). */ + EL3WINDOW(4); + outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA); + } + + outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); + + update_stats(dev); +} + +static void el3_up(struct net_device *dev) +{ + int i; + int ioaddr = dev->base_addr; + + /* Activating the board required and does no harm otherwise */ + outw(0x0001, ioaddr + 4); + + /* Set the IRQ line. */ + outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ); + + /* Set the station address in window 2 each time opened. */ + EL3WINDOW(2); + + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], ioaddr + i); + + if (dev->if_port == 3) + /* Start the thinnet transceiver. We should really wait 50ms...*/ + outw(StartCoax, ioaddr + EL3_CMD); + else if (dev->if_port == 0) { + /* 10baseT interface, enabled link beat and jabber check. */ + EL3WINDOW(4); + outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA); + } + + /* Switch to the stats window, and clear all stats by reading. */ + outw(StatsDisable, ioaddr + EL3_CMD); + EL3WINDOW(6); + for (i = 0; i < 9; i++) + inb(ioaddr + i); + inw(ioaddr + 10); + inw(ioaddr + 12); + + /* Switch to register set 1 for normal use. */ + EL3WINDOW(1); + + /* Accept b-case and phys addr only. */ + outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); + outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ + + outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ + outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ + /* Allow status bits to be seen. */ + outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); + /* Ack all pending events, and set active indicator mask. */ + outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, + ioaddr + EL3_CMD); + outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull, + ioaddr + EL3_CMD); + + netif_start_queue(dev); +} + +/* Power Management support functions */ +#ifdef CONFIG_PM + +static int el3_suspend(struct pm_dev *pdev) +{ + unsigned long flags; + struct net_device *dev; + struct el3_private *lp; + int ioaddr; + + if (!pdev && !pdev->data) + return -EINVAL; + + dev = (struct net_device *)pdev->data; + lp = (struct el3_private *)dev->priv; + ioaddr = dev->base_addr; + + spin_lock_irqsave(&lp->lock, flags); + + if (netif_running(dev)) + netif_device_detach(dev); + + el3_down(dev); + outw(PowerDown, ioaddr + EL3_CMD); + + spin_unlock_irqrestore(&lp->lock, flags); + return 0; +} + +static int el3_resume(struct pm_dev *pdev) +{ + unsigned long flags; + struct net_device *dev; + struct el3_private *lp; + int ioaddr; + + if (!pdev && !pdev->data) + return -EINVAL; + + dev = (struct net_device *)pdev->data; + lp = (struct el3_private *)dev->priv; + ioaddr = dev->base_addr; + + spin_lock_irqsave(&lp->lock, flags); + + outw(PowerUp, ioaddr + EL3_CMD); + el3_up(dev); + + if (netif_running(dev)) + netif_device_attach(dev); + + spin_unlock_irqrestore(&lp->lock, flags); + return 0; +} + +static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data) +{ + switch (rqst) { + case PM_SUSPEND: + return el3_suspend(pdev); + + case PM_RESUME: + return el3_resume(pdev); + } + return 0; +} + +#endif /* CONFIG_PM */ + #ifdef MODULE /* Parameters that may be passed into the module. */ static int debug = -1; @@ -1121,7 +1232,7 @@ el3_debug = debug; el3_root_dev = NULL; - while (el3_probe(0) == 0) { + while (el3_probe(0, el3_cards) == 0) { if (irq[el3_cards] > 1) el3_root_dev->irq = irq[el3_cards]; if (xcvr[el3_cards] >= 0) @@ -1143,7 +1254,12 @@ #ifdef CONFIG_MCA if(lp->mca_slot!=-1) mca_mark_as_unused(lp->mca_slot); -#endif +#endif + +#ifdef CONFIG_PM + if (lp->pmdev) + pm_unregister(lp->pmdev); +#endif next_dev = lp->next_dev; unregister_netdev(el3_root_dev); release_region(el3_root_dev->base_addr, EL3_IO_EXTENT); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/3c59x.c linux-2.5/drivers/net/3c59x.c --- linux-2.5.5/drivers/net/3c59x.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/net/3c59x.c Fri Jan 18 22:19:46 2002 @@ -2916,7 +2916,7 @@ static struct pci_driver vortex_driver = { name: "3c59x", probe: vortex_init_one, - remove: vortex_remove_one, + remove: __devexit_p(vortex_remove_one), id_table: vortex_pci_tbl, #ifdef CONFIG_PM suspend: vortex_suspend, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/8139cp.c linux-2.5/drivers/net/8139cp.c --- linux-2.5.5/drivers/net/8139cp.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/net/8139cp.c Fri Mar 1 15:07:38 2002 @@ -1,6 +1,6 @@ /* 8139cp.c: A Linux PCI Ethernet driver for the RealTek 8139C+ chips. */ /* - Copyright 2001 Jeff Garzik + Copyright 2001,2002 Jeff Garzik Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c] Copyright 2001 Manfred Spraul [natsemi.c] @@ -32,19 +32,20 @@ * Rx checksumming * Tx checksumming * ETHTOOL_GREGS, ETHTOOL_[GS]WOL, - * Jumbo frames / dev->change_mtu * Investigate using skb->priority with h/w VLAN priority * Investigate using High Priority Tx Queue with skb->priority * Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error * Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error - * Implement Tx software interrupt mitigation via - Tx descriptor bit + * Implement Tx software interrupt mitigation via + Tx descriptor bit + * Determine correct value for CP_{MIN,MAX}_MTU, instead of + using conservative guesses. */ #define DRV_NAME "8139cp" -#define DRV_VERSION "0.0.6cvs" -#define DRV_RELDATE "Nov 19, 2001" +#define DRV_VERSION "0.0.7" +#define DRV_RELDATE "Feb 27, 2002" #include @@ -55,7 +56,6 @@ #include #include #include -#include #include #include #include @@ -107,8 +107,11 @@ #define TX_EARLY_THRESH 256 /* Early Tx threshold, in bytes */ /* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (6*HZ) +#define TX_TIMEOUT (6*HZ) +/* hardware minimum and maximum for a single frame's data payload */ +#define CP_MIN_MTU 60 /* FIXME: this is a guess */ +#define CP_MAX_MTU 1500 /* FIXME: this is a guess */ enum { /* NIC register offsets */ @@ -321,6 +324,17 @@ }; MODULE_DEVICE_TABLE(pci, cp_pci_tbl); +static inline void cp_set_rxbufsize (struct cp_private *cp) +{ + unsigned int mtu = cp->dev->mtu; + + if (mtu > ETH_DATA_LEN) + /* MTU + ethernet header + FCS + optional VLAN tag */ + cp->rx_buf_sz = mtu + ETH_HLEN + 8; + else + cp->rx_buf_sz = PKT_BUF_SZ; +} + static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb) { skb->protocol = eth_type_trans (skb, cp->dev); @@ -705,9 +719,6 @@ return 0; } -/* Set or clear the multicast filter for this adaptor. - This routine is not state sensitive and need not be SMP locked. */ - static void __cp_set_rx_mode (struct net_device *dev) { struct cp_private *cp = dev->priv; @@ -812,6 +823,12 @@ printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name); } +static inline void cp_start_hw (struct cp_private *cp) +{ + cpw8(Cmd, RxOn | TxOn); + cpw16(CpCmd, PCIMulRW | CpRxOn | CpTxOn); +} + static void cp_init_hw (struct cp_private *cp) { struct net_device *dev = cp->dev; @@ -824,8 +841,7 @@ cpw32_f (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); cpw32_f (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); - cpw8(Cmd, RxOn | TxOn); - cpw16(CpCmd, PCIMulRW | CpRxOn | CpTxOn); + cp_start_hw(cp); cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */ __cp_set_rx_mode(dev); @@ -957,8 +973,6 @@ if (netif_msg_ifup(cp)) printk(KERN_DEBUG "%s: enabling interface\n", dev->name); - cp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); - rc = cp_alloc_rings(cp); if (rc) return rc; @@ -993,6 +1007,36 @@ return 0; } +static int cp_change_mtu(struct net_device *dev, int new_mtu) +{ + struct cp_private *cp = dev->priv; + int rc; + + /* check for invalid MTU, according to hardware limits */ + if (new_mtu < CP_MIN_MTU || new_mtu > CP_MAX_MTU) + return -EINVAL; + + /* if network interface not up, no need for complexity */ + if (!netif_running(dev)) { + cp_set_rxbufsize(cp); /* set new rx buf size */ + return 0; + } + + spin_lock_irq(&cp->lock); + + cp_stop_hw(cp); /* stop h/w and free rings */ + cp_clean_rings(cp); + + cp_set_rxbufsize(cp); /* set new rx buf size */ + + rc = cp_init_rings(cp); /* realloc and restart h/w */ + cp_start_hw(cp); + + spin_unlock_irq(&cp->lock); + + return rc; +} + static char mii_2_8139_map[8] = { BasicModeCtrl, BasicModeStatus, @@ -1231,6 +1275,7 @@ cp->mii_if.mdio_read = mdio_read; cp->mii_if.mdio_write = mdio_write; cp->mii_if.phy_id = CP_INTERNAL_PHY; + cp_set_rxbufsize(cp); rc = pci_enable_device(pdev); if (rc) @@ -1284,6 +1329,7 @@ dev->hard_start_xmit = cp_start_xmit; dev->get_stats = cp_get_stats; dev->do_ioctl = cp_ioctl; + dev->change_mtu = cp_change_mtu; #if 0 dev->tx_timeout = cp_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -1371,7 +1417,7 @@ name: DRV_NAME, id_table: cp_pci_tbl, probe: cp_init_one, - remove: cp_remove_one, + remove: __devexit_p(cp_remove_one), }; static int __init cp_init (void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/8139too.c linux-2.5/drivers/net/8139too.c --- linux-2.5.5/drivers/net/8139too.c Wed Feb 20 02:10:52 2002 +++ linux-2.5/drivers/net/8139too.c Thu Feb 14 02:57:58 2002 @@ -2499,7 +2499,7 @@ name: DRV_NAME, id_table: rtl8139_pci_tbl, probe: rtl8139_init_one, - remove: rtl8139_remove_one, + remove: __devexit_p(rtl8139_remove_one), #ifdef CONFIG_PM suspend: rtl8139_suspend, resume: rtl8139_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/Config.help linux-2.5/drivers/net/Config.help --- linux-2.5.5/drivers/net/Config.help Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/net/Config.help Tue Feb 26 21:24:48 2002 @@ -3,6 +3,10 @@ MIPS-32-based Baget embedded system. This chipset is better known via the NE2100 cards. +CONFIG_LASI_82596 + Say Y here to support the on-board Intel 82596 ethernet controller + built into Hewlett-Packard PA-RISC machines. + CONFIG_MIPS_JAZZ_SONIC This is the driver for the onboard card of MIPS Magnum 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM systems. @@ -214,6 +218,12 @@ pppd, along with binaries of a patched pppd package can be found at: . +CONFIG_PPPOATM + Support PPP (Point to Point Protocol) encapsulated in ATM frames. + This implementation does not yet comply with section 8 of RFC2364, + which can lead to bad results if the ATM peer loses state and + changes its encapsulation unilaterally. + CONFIG_NET_RADIO Support for wireless LANs and everything having to do with radio, but not with amateur radio or FM broadcasting. @@ -806,6 +816,42 @@ say M here and read . This is recommended. The module will be called dl2k.o. +CONFIG_E1000 + This driver supports Intel(R) PRO/1000 gigabit ethernet family of + adapters, which includes: + + Controller Adapter Name Board IDs + ---------- ------------ --------- + 82542 PRO/1000 Gigabit Server Adapter 700262-xxx, + 717037-xxx + 82543 PRO/1000 F Server Adapter 738640-xxx, + A38888-xxx, + A06512-xxx + 82543 PRO/1000 T Server Adapter A19845-xxx, + A33948-xxx + 82544 PRO/1000 XT Server Adapter A51580-xxx + 82544 PRO/1000 XF Server Adapter A50484-xxx + 82544 PRO/1000 T Desktop Adapter A62947-xxx + + For more information on how to identify your adapter, go to the + Adapter & Driver ID Guide at: + + + + For general information and support, go to the Intel support + website at: + + + + More specific information on configuring the driver is in + . + + This driver 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 e1000.o. If you want to compile it as a + module, say M here and read as well + as . + CONFIG_LANCE If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from @@ -817,6 +863,14 @@ say M here and read . This is recommended. The module will be called lance.o. +CONFIG_MIPS_AU1000_ENET + If you have an Alchemy Semi AU1000 ethernet controller + on an SGI MIPS system, say Y. Otherwise, say N. + +CONFIG_MIPS_AU1000_ENET + If you have an Alchemy Semi AU1000 ethernet controller + on an SGI MIPS system, say Y. Otherwise, say N. + CONFIG_SGI_IOC3_ETH If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from @@ -1290,6 +1344,42 @@ module, say M here and read as well as . +CONFIG_DE2104X + This driver is developed for the SMC EtherPower series Ethernet + cards and also works with cards based on the DECchip + 21040 (Tulip series) chips. Some LinkSys PCI cards are + of this type. (If your card is NOT SMC EtherPower 10/100 PCI + (smc9332dst), you can also try the driver for "Generic DECchip" + cards, above. However, most people with a network card of this type + will say Y here.) Do read the Ethernet-HOWTO, available from + . More specific + information is contained in + . + + This driver 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 tulip.o. If you want to compile it as a + module, say M here and read as well + as . + +CONFIG_DE2104X + This driver is developed for the SMC EtherPower series Ethernet + cards and also works with cards based on the DECchip + 21040 (Tulip series) chips. Some LinkSys PCI cards are + of this type. (If your card is NOT SMC EtherPower 10/100 PCI + (smc9332dst), you can also try the driver for "Generic DECchip" + cards, above. However, most people with a network card of this type + will say Y here.) Do read the Ethernet-HOWTO, available from + . More specific + information is contained in + . + + This driver 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 tulip.o. If you want to compile it as a + module, say M here and read as well + as . + CONFIG_TULIP This driver is developed for the SMC EtherPower series Ethernet cards and also works with cards based on the DECchip @@ -1308,6 +1398,34 @@ module, say M here and read as well as . +CONFIG_TULIP_MWI + This configures your Tulip card specifically for the card and + system cache line size type you are using. + + This is experimental code, not yet tested on many boards. + + If unsure, say N. + +CONFIG_TULIP_MMIO + Use PCI shared memory for the NIC registers, rather than going through + the Tulip's PIO (programmed I/O ports). Faster, but could produce + obscure bugs if your mainboard has memory controller timing issues. + If in doubt, say N. + +CONFIG_TULIP_MWI + This configures your Tulip card specifically for the card and + system cache line size type you are using. + + This is experimental code, not yet tested on many boards. + + If unsure, say N. + +CONFIG_TULIP_MMIO + Use PCI shared memory for the NIC registers, rather than going through + the Tulip's PIO (programmed I/O ports). Faster, but could produce + obscure bugs if your mainboard has memory controller timing issues. + If in doubt, say N. + CONFIG_DGRS This is support for the Digi International RightSwitch series of PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6 @@ -1338,6 +1456,16 @@ cards. Specifications and data at . +CONFIG_LP486E + Say Y here to support the 82596-based on-board Ethernet controller + for the Panther motherboard, which is one of the two shipped in the + Intel Professional Workstation. + +CONFIG_LP486E + Say Y here to support the 82596-based on-board Ethernet controller + for the Panther motherboard, which is one of the two shipped in the + Intel Professional Workstation. + CONFIG_ETH16I If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from @@ -1376,6 +1504,26 @@ The module will be called via-rhine.o. If you want to compile it as a module, say M here and read as well as . + +CONFIG_VIA_RHINE_MMIO + This instructs the driver to use PCI shared memory (MMIO) instead of + programmed I/O ports (PIO). Enabling this gives an improvement in + processing time in parts of the driver. + + It is not known if this works reliably on all "rhine" based cards, + but it has been tested successfully on some DFE-530TX adapters. + + If unsure, say N. + +CONFIG_VIA_RHINE_MMIO + This instructs the driver to use PCI shared memory (MMIO) instead of + programmed I/O ports (PIO). Enabling this gives an improvement in + processing time in parts of the driver. + + It is not known if this works reliably on all "rhine" based cards, + but it has been tested successfully on some DFE-530TX adapters. + + If unsure, say N. CONFIG_DM9102 This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/Config.in linux-2.5/drivers/net/Config.in --- linux-2.5.5/drivers/net/Config.in Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/net/Config.in Sun Mar 3 17:54:35 2002 @@ -37,7 +37,11 @@ bool ' Use AAUI port instead of TP by default' CONFIG_MACE_AAUI_PORT fi dep_tristate ' BMAC (G3 ethernet) support' CONFIG_BMAC $CONFIG_ALL_PPC - tristate ' National DP83902AV (Oak ethernet) support' CONFIG_OAKNET + if [ "$CONFIG_4xx" = "y" ]; then + if [ "$CONFIG_STB03xxx" = "y" -o "$CONFIG_403GCX" = "y" ]; then + tristate ' National DP83902AV (Oak ethernet) support' CONFIG_OAKNET + fi + fi fi if [ "$CONFIG_ZORRO" = "y" ]; then tristate ' Ariadne support' CONFIG_ARIADNE @@ -57,9 +61,15 @@ if [ "$CONFIG_MIPS_AU1000" = "y" ]; then bool ' MIPS AU1000 Ethernet support' CONFIG_MIPS_AU1000_ENET fi + if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then + tristate ' SB1250 Ethernet support' CONFIG_NET_SB1250_MAC + fi if [ "$CONFIG_SGI_IP27" = "y" ]; then bool ' SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH fi + if [ "$CONFIG_SGI_IP32" = "y" ]; then + tristate ' SGI O2 MACE Fast Ethernet support' CONFIG_SGI_O2MACE_ETH + fi if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then bool ' SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH fi @@ -157,6 +167,7 @@ dep_tristate ' CS89x0 support' CONFIG_CS89x0 $CONFIG_ISA dep_tristate ' Early DECchip Tulip (dc2104x) PCI support (EXPERIMENTAL)' CONFIG_DE2104X $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' DECchip Tulip (dc2114x) PCI support' CONFIG_TULIP $CONFIG_PCI + dep_tristate ' TOSHIBA TC35815 Ethernet support' CONFIG_TC35815 $CONFIG_PCI if [ "$CONFIG_TULIP" = "y" -o "$CONFIG_TULIP" = "m" ]; then dep_bool ' New bus configuration (EXPERIMENTAL)' CONFIG_TULIP_MWI $CONFIG_EXPERIMENTAL bool ' Use PCI shared mem for NIC registers' CONFIG_TULIP_MMIO @@ -211,10 +222,13 @@ fi if [ "$CONFIG_DECSTATION" = "y" ]; then bool ' DEC LANCE ethernet controller support' CONFIG_DECLANCE - fi + fi if [ "$CONFIG_BAGET_MIPS" = "y" ]; then tristate ' Baget AMD LANCE support' CONFIG_BAGETLANCE fi + if [ "$CONFIG_NEC_OSPREY" = "y" ]; then + bool ' Memory-mapped onboard NE2000-compatible ethernet' CONFIG_NE2000 + fi fi endmenu @@ -231,6 +245,7 @@ bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I fi dep_tristate 'D-Link DL2000-based Gigabit Ethernet support' CONFIG_DL2K $CONFIG_PCI +dep_tristate 'Intel(R) PRO/1000 Gigabit Ethernet support' CONFIG_E1000 $CONFIG_PCI dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS dep_tristate 'National Semiconduct DP83820 support' CONFIG_NS83820 $CONFIG_PCI dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/Makefile linux-2.5/drivers/net/Makefile --- linux-2.5.5/drivers/net/Makefile Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/Makefile Sun Mar 3 17:54:35 2002 @@ -25,6 +25,10 @@ obj-y += tulip/tulip.o endif +ifeq ($(CONFIG_E1000),y) + obj-y += e1000/e1000.o +endif + ifeq ($(CONFIG_ISDN_PPP),y) obj-$(CONFIG_ISDN) += slhc.o endif @@ -32,6 +36,7 @@ subdir-$(CONFIG_NET_PCMCIA) += pcmcia subdir-$(CONFIG_NET_WIRELESS) += wireless subdir-$(CONFIG_TULIP) += tulip +subdir-$(CONFIG_E1000) += e1000 subdir-$(CONFIG_IRDA) += irda subdir-$(CONFIG_TR) += tokenring subdir-$(CONFIG_WAN) += wan @@ -68,7 +73,7 @@ obj-$(CONFIG_EEPRO100) += eepro100.o obj-$(CONFIG_TLAN) += tlan.o obj-$(CONFIG_EPIC100) += epic100.o mii.o -obj-$(CONFIG_SIS900) += sis900.o +obj-$(CONFIG_SIS900) += sis900.o mii.o obj-$(CONFIG_DM9102) += dmfe.o obj-$(CONFIG_YELLOWFIN) += yellowfin.o obj-$(CONFIG_ACENIC) += acenic.o @@ -77,6 +82,7 @@ obj-$(CONFIG_NS83820) += ns83820.o obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_FEALNX) += fealnx.o mii.o +obj-$(CONFIG_TC35815) += tc35815.o ifeq ($(CONFIG_SK98LIN),y) obj-y += sk98lin/sk98lin.o @@ -128,6 +134,7 @@ obj-$(CONFIG_ES3210) += es3210.o 8390.o obj-$(CONFIG_LNE390) += lne390.o 8390.o obj-$(CONFIG_NE3210) += ne3210.o 8390.o +obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_PPP) += ppp_generic.o slhc.o obj-$(CONFIG_PPP_ASYNC) += ppp_async.o @@ -151,6 +158,7 @@ obj-$(CONFIG_SUN3LANCE) += sun3lance.o obj-$(CONFIG_DEFXX) += defxx.o obj-$(CONFIG_SGISEEQ) += sgiseeq.o +obj-$(CONFIG_SGI_O2MACE_ETH) += meth.o obj-$(CONFIG_AT1700) += at1700.o obj-$(CONFIG_FMV18X) += fmv18x.o obj-$(CONFIG_EL1) += 3c501.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/acenic.c linux-2.5/drivers/net/acenic.c --- linux-2.5.5/drivers/net/acenic.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/net/acenic.c Thu Feb 14 00:36:31 2002 @@ -166,12 +166,12 @@ #endif #ifndef SET_MODULE_OWNER -#define SET_MODULE_OWNER(dev) {do{} while(0);} +#define SET_MODULE_OWNER(dev) do { } while(0) #define ACE_MOD_INC_USE_COUNT MOD_INC_USE_COUNT #define ACE_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT #else -#define ACE_MOD_INC_USE_COUNT {do{} while(0);} -#define ACE_MOD_DEC_USE_COUNT {do{} while(0);} +#define ACE_MOD_INC_USE_COUNT do { } while(0) +#define ACE_MOD_DEC_USE_COUNT do { } while(0) #endif @@ -252,7 +252,7 @@ #define dev_kfree_skb_irq(a) dev_kfree_skb(a) #define netif_wake_queue(dev) clear_bit(0, &dev->tbusy) #define netif_stop_queue(dev) set_bit(0, &dev->tbusy) -#define late_stop_netif_stop_queue(dev) {do{} while(0);} +#define late_stop_netif_stop_queue(dev) do { } while(0) #define early_stop_netif_stop_queue(dev) test_and_set_bit(0,&dev->tbusy) #define early_stop_netif_wake_queue(dev) netif_wake_queue(dev) @@ -266,7 +266,7 @@ #define ace_mark_net_bh() mark_bh(NET_BH) #define netif_queue_stopped(dev) dev->tbusy #define netif_running(dev) dev->start -#define ace_if_down(dev) {do{dev->start = 0;} while(0);} +#define ace_if_down(dev) do { dev->start = 0; } while(0) #define tasklet_struct tq_struct static inline void tasklet_schedule(struct tasklet_struct *tasklet) @@ -284,13 +284,13 @@ tasklet->routine = (void (*)(void *))func; tasklet->data = (void *)data; } -#define tasklet_kill(tasklet) {do{} while(0);} +#define tasklet_kill(tasklet) do { } while(0) #else #define late_stop_netif_stop_queue(dev) netif_stop_queue(dev) #define early_stop_netif_stop_queue(dev) 0 -#define early_stop_netif_wake_queue(dev) {do{} while(0);} -#define ace_mark_net_bh() {do{} while(0);} -#define ace_if_down(dev) {do{} while(0);} +#define early_stop_netif_wake_queue(dev) do { } while(0) +#define ace_mark_net_bh() do { } while(0) +#define ace_if_down(dev) do { } while(0) #endif #if (LINUX_VERSION_CODE >= 0x02031b) @@ -306,7 +306,7 @@ #ifndef ARCH_HAS_PREFETCHW #ifndef prefetchw -#define prefetchw(x) {do{} while(0);} +#define prefetchw(x) do { } while(0) #endif #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/arcnet/arc-rawmode.c linux-2.5/drivers/net/arcnet/arc-rawmode.c --- linux-2.5.5/drivers/net/arcnet/arc-rawmode.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/net/arcnet/arc-rawmode.c Fri Feb 8 15:46:33 2002 @@ -83,6 +83,7 @@ arcnet_unregister_proto(&rawmode_proto); } +MODULE_LICENSE("GPL"); #endif /* MODULE */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/arcnet/arc-rimi.c linux-2.5/drivers/net/arcnet/arc-rimi.c --- linux-2.5.5/drivers/net/arcnet/arc-rimi.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/net/arcnet/arc-rimi.c Fri Feb 8 15:46:33 2002 @@ -297,6 +297,7 @@ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); MODULE_PARM(device, "s"); +MODULE_LICENSE("GPL"); int init_module(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/arcnet/arcnet.c linux-2.5/drivers/net/arcnet/arcnet.c --- linux-2.5.5/drivers/net/arcnet/arcnet.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/net/arcnet/arcnet.c Fri Feb 8 15:46:33 2002 @@ -163,6 +163,7 @@ static int debug = ARCNET_DEBUG; MODULE_PARM(debug, "i"); +MODULE_LICENSE("GPL"); int __init init_module(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/arcnet/com20020-isa.c linux-2.5/drivers/net/arcnet/com20020-isa.c --- linux-2.5.5/drivers/net/arcnet/com20020-isa.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/net/arcnet/com20020-isa.c Fri Feb 8 15:46:33 2002 @@ -133,6 +133,7 @@ MODULE_PARM(backplane, "i"); MODULE_PARM(clockp, "i"); MODULE_PARM(clockm, "i"); +MODULE_LICENSE("GPL"); static void com20020isa_open_close(struct net_device *dev, bool open) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/arcnet/com20020-pci.c linux-2.5/drivers/net/arcnet/com20020-pci.c --- linux-2.5.5/drivers/net/arcnet/com20020-pci.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/net/arcnet/com20020-pci.c Fri Feb 8 15:46:33 2002 @@ -57,6 +57,7 @@ MODULE_PARM(backplane, "i"); MODULE_PARM(clockp, "i"); MODULE_PARM(clockm, "i"); +MODULE_LICENSE("GPL"); static void com20020pci_open_close(struct net_device *dev, bool open) { @@ -160,7 +161,7 @@ name: "com20020", id_table: com20020pci_id_table, probe: com20020pci_probe, - remove: com20020pci_remove + remove: __devexit_p(com20020pci_remove), }; static int __init com20020pci_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/arcnet/com20020.c linux-2.5/drivers/net/arcnet/com20020.c --- linux-2.5.5/drivers/net/arcnet/com20020.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/net/arcnet/com20020.c Fri Feb 8 15:46:33 2002 @@ -356,6 +356,8 @@ EXPORT_SYMBOL(com20020_found); EXPORT_SYMBOL(com20020_remove); +MODULE_LICENSE("GPL"); + int init_module(void) { BUGLVL(D_NORMAL) printk(VERSION); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/arcnet/com90io.c linux-2.5/drivers/net/arcnet/com90io.c --- linux-2.5.5/drivers/net/arcnet/com90io.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/net/arcnet/com90io.c Fri Feb 8 15:46:33 2002 @@ -383,6 +383,7 @@ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); MODULE_PARM(device, "s"); +MODULE_LICENSE("GPL"); int init_module(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/arcnet/com90xx.c linux-2.5/drivers/net/arcnet/com90xx.c --- linux-2.5.5/drivers/net/arcnet/com90xx.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/net/arcnet/com90xx.c Fri Feb 8 15:46:33 2002 @@ -619,6 +619,7 @@ MODULE_PARM(irq, "i"); MODULE_PARM(shmem, "i"); MODULE_PARM(device, "s"); +MODULE_LICENSE("GPL"); int init_module(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/arcnet/rfc1051.c linux-2.5/drivers/net/arcnet/rfc1051.c --- linux-2.5.5/drivers/net/arcnet/rfc1051.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/net/arcnet/rfc1051.c Fri Feb 8 15:46:33 2002 @@ -68,6 +68,8 @@ #ifdef MODULE +MODULE_LICENSE("GPL"); + int __init init_module(void) { printk(VERSION); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/arcnet/rfc1201.c linux-2.5/drivers/net/arcnet/rfc1201.c --- linux-2.5.5/drivers/net/arcnet/rfc1201.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/net/arcnet/rfc1201.c Fri Feb 8 15:46:33 2002 @@ -70,6 +70,8 @@ #ifdef MODULE +MODULE_LICENSE("GPL"); + int __init init_module(void) { printk(VERSION); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/at1700.c linux-2.5/drivers/net/at1700.c --- linux-2.5.5/drivers/net/at1700.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/net/at1700.c Thu Feb 14 00:36:31 2002 @@ -465,7 +465,7 @@ #define EE_DATA_READ 0x80 /* EEPROM chip data out, in reg. 17. */ /* Delay between EEPROM clock transitions. */ -#define eeprom_delay() do {} while (0); +#define eeprom_delay() do { } while (0) /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD (5 << 6) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/atp.c linux-2.5/drivers/net/atp.c --- linux-2.5.5/drivers/net/atp.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/net/atp.c Sun Mar 3 17:54:35 2002 @@ -667,7 +667,7 @@ } num_tx_since_rx++; } else if (num_tx_since_rx > 8 - && jiffies > dev->last_rx + HZ) { + && time_after(jiffies, dev->last_rx + HZ)) { if (net_debug > 2) printk(KERN_DEBUG "%s: Missed packet? No Rx after %d Tx and " "%ld jiffies status %02x CMR1 %02x.\n", dev->name, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/au1000_eth.c linux-2.5/drivers/net/au1000_eth.c --- linux-2.5.5/drivers/net/au1000_eth.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/net/au1000_eth.c Sun Mar 3 17:54:35 2002 @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +66,7 @@ static void *dma_alloc(size_t, dma_addr_t *); static void dma_free(void *, size_t); static void hard_stop(struct net_device *); +static void enable_rx_tx(struct net_device *dev); static int __init au1000_probe1(struct net_device *, long, int, int); static int au1000_init(struct net_device *); static int au1000_open(struct net_device *); @@ -79,15 +81,17 @@ static inline void update_tx_stats(struct net_device *, u32, u32); static inline void update_rx_stats(struct net_device *, u32); static void au1000_timer(unsigned long); -static void cleanup_buffers(struct net_device *); static int au1000_ioctl(struct net_device *, struct ifreq *, int); static int mdio_read(struct net_device *, int, int); static void mdio_write(struct net_device *, int, int, u16); -static inline void sync(void); +static void dump_mii(struct net_device *dev, int phy_id); +// externs extern void ack_rise_edge_irq(unsigned int); - -static int next_dev; +extern int get_ethernet_addr(char *ethernet_addr); +extern inline void str2eaddr(unsigned char *ea, unsigned char *str); +extern inline unsigned char str2hexnum(unsigned char c); +extern char * __init prom_getcmdline(void); /* * Theory of operation @@ -106,24 +110,30 @@ /* - * Base address and interupt of the Au1000 ethernet macs + * Base address and interupt of the Au1xxx ethernet macs */ static struct { unsigned int port; int irq; } au1000_iflist[NUM_INTERFACES] = { - {AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, - {AU1000_ETH1_BASE, AU1000_ETH1_IRQ} -}; + {AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, + {AU1000_ETH1_BASE, AU1000_ETH1_IRQ} + }, + au1500_iflist[NUM_INTERFACES] = { + {AU1500_ETH0_BASE, AU1000_ETH0_IRQ}, + {AU1500_ETH1_BASE, AU1000_ETH1_IRQ} + }; static char version[] __devinitdata = - "au1000eth.c:0.1 ppopov@mvista.com\n"; + "au1000eth.c:1.0 ppopov@mvista.com\n"; -// FIX! Need real Ethernet addresses -static unsigned char au1000_mac_addr[2][6] __devinitdata = { - {0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00}, - {0x00, 0x50, 0xc2, 0x0c, 0x40, 0x00} +/* These addresses are only used if yamon doesn't tell us what + * the mac address is, and the mac address is not passed on the + * command line. + */ +static unsigned char au1000_mac_addr[6] __devinitdata = { + 0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00 }; #define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0)) @@ -133,11 +143,6 @@ #define cpu_to_dma32 cpu_to_be32 #define dma32_to_cpu be32_to_cpu -/* CPU pipeline flush */ -static inline void sync(void) -{ - asm volatile ("sync"); -} /* FIXME * All of the PHY code really should be detached from the MAC @@ -148,7 +153,8 @@ {"unknown", "10Base2", "10BaseT", "AUI", - "100BaseT", "100BaseTX", "100BaseFX"}; + "100BaseT", "100BaseTX", "100BaseFX" + }; int bcm_5201_init(struct net_device *dev, int phy_addr) { @@ -169,7 +175,8 @@ data = mdio_read(dev, phy_addr, MII_CONTROL); data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO; mdio_write(dev, phy_addr, MII_CONTROL, data); - //dump_mii(dev, phy_addr); + + if (au1000_debug > 4) dump_mii(dev, phy_addr); return 0; } @@ -229,10 +236,91 @@ else { *link = 0; *speed = 0; + dev->if_port = IF_PORT_UNKNOWN; + } + return 0; +} + +int lsi_80227_init(struct net_device *dev, int phy_addr) +{ + if (au1000_debug > 4) + printk("lsi_80227_init\n"); + + /* restart auto-negotiation */ + mdio_write(dev, phy_addr, 0, 0x3200); + + /* set up LEDs to correct display */ + mdio_write(dev, phy_addr, 17, 0xffc0); + + if (au1000_debug > 4) + dump_mii(dev, phy_addr); + return 0; +} + +int lsi_80227_reset(struct net_device *dev, int phy_addr) +{ + s16 mii_control, timeout; + + if (au1000_debug > 4) { + printk("lsi_80227_reset\n"); + dump_mii(dev, phy_addr); + } + + mii_control = mdio_read(dev, phy_addr, MII_CONTROL); + mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET); + mdelay(1); + for (timeout = 100; timeout > 0; --timeout) { + mii_control = mdio_read(dev, phy_addr, MII_CONTROL); + if ((mii_control & MII_CNTL_RESET) == 0) + break; + mdelay(1); + } + if (mii_control & MII_CNTL_RESET) { + printk(KERN_ERR "%s PHY reset timeout !\n", dev->name); + return -1; } return 0; } +int +lsi_80227_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed) +{ + u16 mii_data; + struct au1000_private *aup; + + if (!dev) { + printk(KERN_ERR "lsi_80227_status error: NULL dev\n"); + return -1; + } + aup = (struct au1000_private *) dev->priv; + + mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS); + if (mii_data & MII_STAT_LINK) { + *link = 1; + mii_data = mdio_read(dev, aup->phy_addr, MII_LSI_STAT); + if (mii_data & MII_LSI_STAT_SPD) { + if (mii_data & MII_LSI_STAT_FDX) { + *speed = IF_PORT_100BASEFX; + dev->if_port = IF_PORT_100BASEFX; + } + else { + *speed = IF_PORT_100BASETX; + dev->if_port = IF_PORT_100BASETX; + } + } + else { + *speed = IF_PORT_10BASET; + dev->if_port = IF_PORT_10BASET; + } + + } + else { + *link = 0; + *speed = 0; + dev->if_port = IF_PORT_UNKNOWN; + } + return 0; +} int am79c901_init(struct net_device *dev, int phy_addr) { @@ -264,6 +352,12 @@ am79c901_status, }; +struct phy_ops lsi_80227_ops = { + lsi_80227_init, + lsi_80227_reset, + lsi_80227_status, +}; + static struct mii_chip_info { const char * name; u16 phy_id0; @@ -272,6 +366,7 @@ } mii_chip_table[] = { {"Broadcom BCM5201 10/100 BaseT PHY", 0x0040, 0x6212, &bcm_5201_ops }, {"AMD 79C901 HomePNA PHY", 0x0000, 0x35c8, &am79c901_ops }, + {"LSI 80227 10/100 BaseT PHY", 0x0016, 0xf840, &lsi_80227_ops }, {0,}, }; @@ -284,7 +379,8 @@ while (aup->mac->mii_control & MAC_MII_BUSY) { mdelay(1); if (--timedout == 0) { - printk(KERN_ERR "%s: read_MII busy timeout!!\n", dev->name); + printk(KERN_ERR "%s: read_MII busy timeout!!\n", + dev->name); return -1; } } @@ -298,7 +394,8 @@ while (aup->mac->mii_control & MAC_MII_BUSY) { mdelay(1); if (--timedout == 0) { - printk(KERN_ERR "%s: mdio_read busy timeout!!\n", dev->name); + printk(KERN_ERR "%s: mdio_read busy timeout!!\n", + dev->name); return -1; } } @@ -314,7 +411,8 @@ while (aup->mac->mii_control & MAC_MII_BUSY) { mdelay(1); if (--timedout == 0) { - printk(KERN_ERR "%s: mdio_write busy timeout!!\n", dev->name); + printk(KERN_ERR "%s: mdio_write busy timeout!!\n", + dev->name); return; } } @@ -363,25 +461,34 @@ phy_id1 = mdio_read(dev, phy_addr, MII_PHY_ID1); /* search our mii table for the current mii */ - for (i = 0; mii_chip_table[i].phy_id1; i++) + for (i = 0; mii_chip_table[i].phy_id1; i++) { if (phy_id0 == mii_chip_table[i].phy_id0 && phy_id1 == mii_chip_table[i].phy_id1) { struct mii_phy * mii_phy; - printk(KERN_INFO "%s: %s found at phy address %d\n", - dev->name, mii_chip_table[i].name, phy_addr); - if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) { + printk(KERN_INFO "%s: %s at phy address %d\n", + dev->name, mii_chip_table[i].name, + phy_addr); + mii_phy = kmalloc(sizeof(struct mii_phy), + GFP_KERNEL); + if (mii_phy) { mii_phy->chip_info = mii_chip_table+i; mii_phy->phy_addr = phy_addr; - //mii_phy->status = mdio_read(dev, phy_addr, MII_STATUS); mii_phy->next = aup->mii; - aup->phy_ops = mii_chip_table[i].phy_ops; + aup->phy_ops = + mii_chip_table[i].phy_ops; aup->mii = mii_phy; + aup->phy_ops->phy_init(dev,phy_addr); + } else { + printk(KERN_ERR "%s: out of memory\n", + dev->name); + return -1; } /* the current mii is on our mii_info_table, try next address */ break; } + } } if (aup->mii == NULL) { @@ -391,7 +498,8 @@ /* use last PHY */ aup->phy_addr = aup->mii->phy_addr; - printk(KERN_INFO "%s: Using %s as default\n", dev->name, aup->mii->chip_info->name); + printk(KERN_INFO "%s: Using %s as default\n", + dev->name, aup->mii->chip_info->name); return 0; } @@ -438,7 +546,7 @@ if (ret != NULL) { memset(ret, 0, size); *dma_handle = virt_to_bus(ret); - ret = KSEG0ADDR(ret); + ret = (void *)KSEG0ADDR(ret); } return ret; } @@ -446,11 +554,22 @@ static void dma_free(void *vaddr, size_t size) { - vaddr = KSEG0ADDR(vaddr); + vaddr = (void *)KSEG0ADDR(vaddr); free_pages((unsigned long) vaddr, get_order(size)); } +static void enable_rx_tx(struct net_device *dev) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + + if (au1000_debug > 4) + printk(KERN_INFO "%s: enable_rx_tx\n", dev->name); + + aup->mac->control |= (MAC_RX_ENABLE | MAC_TX_ENABLE); + au_sync_delay(10); +} + static void hard_stop(struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; @@ -459,8 +578,7 @@ printk(KERN_INFO "%s: hard stop\n", dev->name); aup->mac->control &= ~(MAC_RX_ENABLE | MAC_TX_ENABLE); - sync(); - mdelay(10); + au_sync_delay(10); } @@ -469,39 +587,21 @@ u32 flags; struct au1000_private *aup = (struct au1000_private *) dev->priv; - if (au1000_debug > 4) - printk(KERN_INFO "%s: reset mac, aup %x\n", dev->name, (unsigned)aup); + if (au1000_debug > 4) + printk(KERN_INFO "%s: reset mac, aup %x\n", + dev->name, (unsigned)aup); spin_lock_irqsave(&aup->lock, flags); del_timer(&aup->timer); hard_stop(dev); - *aup->enable |= MAC_DMA_RESET; - sync(); - mdelay(10); + *aup->enable = MAC_EN_CLOCK_ENABLE; + au_sync_delay(2); + *aup->enable = 0; + au_sync_delay(2); aup->tx_full = 0; spin_unlock_irqrestore(&aup->lock, flags); } -static void cleanup_buffers(struct net_device *dev) -{ - int i; - struct au1000_private *aup = (struct au1000_private *) dev->priv; - - for (i=0; irx_db_inuse[i]) { - ReleaseDB(aup, aup->rx_db_inuse[i]); - aup->rx_db_inuse[i] = 0; - } - } - - for (i=0; itx_db_inuse[i]) { - ReleaseDB(aup, aup->tx_db_inuse[i]); - aup->tx_db_inuse[i] = 0; - } - } -} - /* * Setup the receive and transmit "rings". These pointers are the addresses @@ -514,44 +614,40 @@ int i; for (i=0; irx_dma_ring[i] = (volatile rx_dma_t *) ioremap_nocache((unsigned long) - (rx_base + sizeof(rx_dma_t)*i), sizeof(rx_dma_t)); + aup->rx_dma_ring[i] = + (volatile rx_dma_t *) (rx_base + sizeof(rx_dma_t)*i); } for (i=0; itx_dma_ring[i] = (volatile tx_dma_t *)ioremap_nocache((unsigned long) - (tx_base + sizeof(tx_dma_t)*i), sizeof(tx_dma_t)); + aup->tx_dma_ring[i] = + (volatile tx_dma_t *) (tx_base + sizeof(tx_dma_t)*i); } } -/* - * Probe for a AU1000 ethernet controller. - */ -int __init au1000_probe(struct net_device *dev) +static int __init au1000_init_module(void) { - int base_addr = au1000_iflist[next_dev].port; - int irq = au1000_iflist[next_dev].irq; - -#ifndef CONFIG_MIPS_AU1000_ENET - return -ENODEV; -#endif - - if (au1000_debug > 4) - printk(KERN_INFO "%s: au1000_probe base_addr %x\n", - dev->name, base_addr); + int i; + int prid; + int base_addr, irq; - if (next_dev >= NUM_INTERFACES) { - return -ENODEV; - } - if (au1000_probe1(dev, base_addr, irq, next_dev) == 0) { - next_dev++; - return 0; + prid = read_32bit_cp0_register(CP0_PRID); + for (i=0; iname, ioaddr, irq); - + printk("%s: Au1xxx ethernet found at 0x%lx, irq %d\n", + dev->name, ioaddr, irq); /* Initialize our private structure */ if (dev->priv == NULL) { - aup = (struct au1000_private *) kmalloc(sizeof(*aup), GFP_KERNEL); + aup = (struct au1000_private *) + kmalloc(sizeof(*aup), GFP_KERNEL); if (aup == NULL) { retval = -ENOMEM; goto free_region; @@ -598,52 +691,75 @@ /* Allocate the data buffers */ - aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr); + aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE * + (NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr); if (!aup->vaddr) { retval = -ENOMEM; goto free_region; } /* aup->mac is the base address of the MAC's registers */ - aup->mac = (volatile mac_reg_t *)ioremap_nocache((unsigned long)ioaddr, sizeof(*aup->mac)); + aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr); /* Setup some variables for quick register address access */ - if (ioaddr == AU1000_ETH0_BASE) { - aup->enable = (volatile u32 *) - ioremap_nocache((unsigned long)MAC0_ENABLE, sizeof(*aup->enable)); - memcpy(dev->dev_addr, au1000_mac_addr[0], sizeof(dev->dev_addr)); + switch (ioaddr) { + case AU1000_ETH0_BASE: + case AU1500_ETH0_BASE: + /* check env variables first */ + if (!get_ethernet_addr(ethaddr)) { + memcpy(au1000_mac_addr, ethaddr, sizeof(dev->dev_addr)); + } else { + /* Check command line */ + argptr = prom_getcmdline(); + if ((pmac = strstr(argptr, "ethaddr=")) == NULL) { + printk(KERN_INFO "%s: No mac address found\n", + dev->name); + /* use the hard coded mac addresses */ + } else { + str2eaddr(ethaddr, pmac + strlen("ethaddr=")); + memcpy(au1000_mac_addr, ethaddr, + sizeof(dev->dev_addr)); + } + } + if (ioaddr == AU1000_ETH0_BASE) + aup->enable = (volatile u32 *) + ((unsigned long)AU1000_MAC0_ENABLE); + else + aup->enable = (volatile u32 *) + ((unsigned long)AU1500_MAC0_ENABLE); + memcpy(dev->dev_addr, au1000_mac_addr, sizeof(dev->dev_addr)); setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR); - } - else if (ioaddr == AU1000_ETH1_BASE) { - aup->enable = (volatile u32 *) - ioremap_nocache((unsigned long)MAC1_ENABLE, sizeof(*aup->enable)); - memcpy(dev->dev_addr, au1000_mac_addr[1], sizeof(dev->dev_addr)); + break; + case AU1000_ETH1_BASE: + case AU1500_ETH1_BASE: + if (ioaddr == AU1000_ETH1_BASE) + aup->enable = (volatile u32 *) + ((unsigned long)AU1000_MAC1_ENABLE); + else + aup->enable = (volatile u32 *) + ((unsigned long)AU1500_MAC1_ENABLE); + memcpy(dev->dev_addr, au1000_mac_addr, sizeof(dev->dev_addr)); + dev->dev_addr[4] += 0x10; setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR); - } - else { /* should never happen */ - printk (KERN_ERR "au1000 eth: bad ioaddr %x\n", (unsigned)ioaddr); - retval = -ENODEV; - goto free_region; + break; + default: + printk(KERN_ERR "%s: bad ioaddr\n", dev->name); + break; + } aup->phy_addr = PHY_ADDRESS; + /* bring the device out of reset, otherwise probing the mii * will hang */ - *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 | - MAC_EN_CLOCK_ENABLE | MAC_EN_TOSS; - sync(); - mdelay(2); + *aup->enable = MAC_EN_CLOCK_ENABLE; + au_sync_delay(2); + *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | + MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE; + au_sync_delay(2); + if (mii_probe(dev) != 0) { goto free_region; } - aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed); - if (!link) { - printk(KERN_INFO "%s: link down resetting...\n", dev->name); - aup->phy_ops->phy_reset(dev, aup->phy_addr); - aup->phy_ops->phy_init(dev, aup->phy_addr); - } - else { - printk(KERN_INFO "%s: link up (%s)\n", dev->name, phy_link[speed]); - } pDBfree = NULL; /* setup the data buffer descriptors and attach a buffer to each one */ @@ -689,18 +805,18 @@ ether_setup(dev); /* - * The boot code uses the ethernet controller, so reset it to start fresh. - * au1000_init() expects that the device is in reset state. + * The boot code uses the ethernet controller, so reset it to start + * fresh. au1000_init() expects that the device is in reset state. */ reset_mac(dev); - return 0; free_region: release_region(ioaddr, MAC_IOSIZE); unregister_netdev(dev); - if (aup->vaddr) - dma_free((void *)aup->vaddr, MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS)); + if (aup->vaddr) + dma_free((void *)aup->vaddr, + MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS)); if (dev->priv != NULL) kfree(dev->priv); kfree(dev); @@ -724,18 +840,19 @@ struct au1000_private *aup = (struct au1000_private *) dev->priv; u32 flags; int i; - u32 value, control; + u32 control; + u16 link, speed; - if (au1000_debug > 4) printk("%s: au1000_init", dev->name); + if (au1000_debug > 4) printk("%s: au1000_init\n", dev->name); spin_lock_irqsave(&aup->lock, flags); /* bring the device out of reset */ - value = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 | - MAC_EN_CLOCK_ENABLE | MAC_EN_TOSS; - *aup->enable = value; - sync(); - mdelay(200); + *aup->enable = MAC_EN_CLOCK_ENABLE; + au_sync_delay(2); + *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | + MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE; + au_sync_delay(20); aup->mac->control = 0; aup->tx_head = (aup->tx_dma_ring[0]->buff_stat & 0xC) >> 2; @@ -749,13 +866,18 @@ for (i=0; irx_dma_ring[i]->buff_stat |= RX_DMA_ENABLE; } + au_sync(); - sync(); + aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed); control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE; #ifndef CONFIG_CPU_LITTLE_ENDIAN control |= MAC_BIG_ENDIAN; #endif + if (link && (dev->if_port == IF_PORT_100BASEFX)) { + control |= MAC_FULL_DUPLEX; + } aup->mac->control = control; + au_sync(); spin_unlock_irqrestore(&aup->lock, flags); return 0; @@ -765,23 +887,22 @@ { struct net_device *dev = (struct net_device *)data; struct au1000_private *aup = (struct au1000_private *) dev->priv; - u16 mii_data, link, speed; + unsigned char if_port; + u16 link, speed; if (!dev) { /* fatal error, don't restart the timer */ printk(KERN_ERR "au1000_timer error: NULL dev\n"); return; } - if (!(dev->flags & IFF_UP)) { - goto set_timer; - } + if_port = dev->if_port; if (aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed) == 0) { if (link) { if (!(dev->flags & IFF_RUNNING)) { netif_carrier_on(dev); dev->flags |= IFF_RUNNING; - printk(KERN_DEBUG "%s: link up\n", dev->name); + printk(KERN_INFO "%s: link up\n", dev->name); } } else { @@ -789,12 +910,27 @@ netif_carrier_off(dev); dev->flags &= ~IFF_RUNNING; dev->if_port = 0; - printk(KERN_DEBUG "%s: link down\n", dev->name); + printk(KERN_INFO "%s: link down\n", dev->name); } } } -set_timer: + if (link && (dev->if_port != if_port) && + (dev->if_port != IF_PORT_UNKNOWN)) { + hard_stop(dev); + if (dev->if_port == IF_PORT_100BASEFX) { + printk(KERN_INFO "%s: going to full duplex\n", + dev->name); + aup->mac->control |= MAC_FULL_DUPLEX; + au_sync_delay(1); + } + else { + aup->mac->control &= ~MAC_FULL_DUPLEX; + au_sync_delay(1); + } + enable_rx_tx(dev); + } + aup->timer.expires = RUN_AT((1*HZ)); aup->timer.data = (unsigned long)dev; aup->timer.function = &au1000_timer; /* timer handler */ @@ -820,8 +956,10 @@ } netif_start_queue(dev); - if ((retval = request_irq(dev->irq, &au1000_interrupt, 0, dev->name, dev))) { - printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); + if ((retval = request_irq(dev->irq, &au1000_interrupt, 0, + dev->name, dev))) { + printk(KERN_ERR "%s: unable to get IRQ %d\n", + dev->name, dev->irq); MOD_DEC_USE_COUNT; return retval; } @@ -861,8 +999,13 @@ return 0; } +static void __exit au1000_cleanup_module(void) +{ +} -static inline void update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) + +static inline void +update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) { struct au1000_private *aup = (struct au1000_private *) dev->priv; struct net_device_stats *ps = &aup->stats; @@ -871,10 +1014,20 @@ ps->tx_bytes += pkt_len; if (status & TX_FRAME_ABORTED) { - ps->tx_errors++; - ps->tx_aborted_errors++; - if (status & (TX_NO_CARRIER | TX_LOSS_CARRIER)) - ps->tx_carrier_errors++; + if (dev->if_port == IF_PORT_100BASEFX) { + if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) { + /* any other tx errors are only valid + * in half duplex mode */ + ps->tx_errors++; + ps->tx_aborted_errors++; + } + } + else { + ps->tx_errors++; + ps->tx_aborted_errors++; + if (status & (TX_NO_CARRIER | TX_LOSS_CARRIER)) + ps->tx_carrier_errors++; + } } } @@ -895,7 +1048,7 @@ update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff); ptxd->buff_stat &= ~TX_T_DONE; ptxd->len = 0; - sync(); + au_sync(); aup->tx_tail = (aup->tx_tail + 1) & (NUM_TX_DMA - 1); ptxd = aup->tx_dma_ring[aup->tx_tail]; @@ -914,26 +1067,22 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; - //unsigned long flags; volatile tx_dma_t *ptxd; u32 buff_stat; db_dest_t *pDB; int i; if (au1000_debug > 4) - printk("%s: tx: aup %x len=%d, data=%p, head %d\n", - dev->name, (unsigned)aup, skb->len, skb->data, aup->tx_head); + printk("%s: tx: aup %x len=%d, data=%p, head %d\n", + dev->name, (unsigned)aup, skb->len, + skb->data, aup->tx_head); - /* Prevent interrupts from changing the Tx ring */ - //spin_lock_irqsave(&aup->lock, flags); - ptxd = aup->tx_dma_ring[aup->tx_head]; buff_stat = ptxd->buff_stat; if (buff_stat & TX_DMA_ENABLE) { /* We've wrapped around and the transmitter is still busy */ netif_stop_queue(dev); aup->tx_full = 1; - //spin_unlock_irqrestore(&aup->lock, flags); return 1; } else if (buff_stat & TX_T_DONE) { @@ -958,11 +1107,10 @@ ptxd->len = skb->len; ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE; - sync(); + au_sync(); dev_kfree_skb(skb); aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1); dev->trans_start = jiffies; - //spin_unlock_irqrestore(&aup->lock, flags); return 0; } @@ -1027,7 +1175,7 @@ skb_reserve(skb, 2); /* 16 byte IP header align */ eth_copy_and_sum(skb, (unsigned char *)pDB->vaddr, status & RX_FRAME_LEN_MASK, 0); - skb_put(skb, status & RX_FRAME_LEN_MASK); /* Make room */ + skb_put(skb, status & RX_FRAME_LEN_MASK); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); /* pass the packet to upper layers */ } @@ -1057,7 +1205,7 @@ } prxd->buff_stat = (u32)(pDB->dma_addr | RX_DMA_ENABLE); aup->rx_head = (aup->rx_head + 1) & (NUM_RX_DMA - 1); - sync(); + au_sync(); /* next descriptor */ prxd = aup->rx_dma_ring[aup->rx_head]; @@ -1079,8 +1227,8 @@ printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name); return; } - au1000_rx(dev); au1000_tx_ack(dev); + au1000_rx(dev); } @@ -1099,9 +1247,8 @@ { struct au1000_private *aup = (struct au1000_private *) dev->priv; - /* fixme */ if (au1000_debug > 4) - printk("%s: set_multicast: flags=%x\n", dev->name, dev->flags); + printk("%s: set_rx_mode: flags=%x\n", dev->name, dev->flags); if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ aup->mac->control |= MAC_PROMISCUOUS; @@ -1123,6 +1270,7 @@ } aup->mac->multi_hash_high = mc_filter[1]; aup->mac->multi_hash_low = mc_filter[0]; + aup->mac->control &= ~MAC_PROMISCUOUS; aup->mac->control |= MAC_HASH_MODE; } } @@ -1130,24 +1278,23 @@ static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - //struct au1000_private *aup = (struct au1000_private *) dev->priv; u16 *data = (u16 *)&rq->ifr_data; /* fixme */ switch(cmd) { - case SIOCGMIIPHY: /* Get the address of the PHY in use. */ + case SIOCGMIIPHY: /* Get the address of the PHY in use. */ data[0] = PHY_ADDRESS; - case SIOCGMIIREG: /* Read the specified MII register. */ + case SIOCGMIIREG: /* Read the specified MII register. */ //data[3] = mdio_read(ioaddr, data[0], data[1]); return 0; - case SIOCSMIIREG: /* Write the specified MII register */ + case SIOCSMIIREG: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) return -EPERM; //mdio_write(ioaddr, data[0], data[1], data[2]); return 0; - default: + default: return -EOPNOTSUPP; } } @@ -1165,7 +1312,8 @@ switch(map->port){ case IF_PORT_UNKNOWN: /* use auto here */ - printk("auto\\n"); + printk(KERN_INFO "%s: config phy for aneg\n", + dev->name); dev->if_port = map->port; /* Link Down: the timer will bring it up */ netif_carrier_off(dev); @@ -1175,13 +1323,15 @@ control &= ~(MII_CNTL_FDX | MII_CNTL_F100); /* enable auto negotiation and reset the negotiation */ - mdio_write(dev, aup->phy_addr, - MII_CONTROL, control | MII_CNTL_AUTO | MII_CNTL_RST_AUTO); + mdio_write(dev, aup->phy_addr, MII_CONTROL, + control | MII_CNTL_AUTO | + MII_CNTL_RST_AUTO); break; case IF_PORT_10BASET: /* 10BaseT */ - printk("10baseT\n"); + printk(KERN_INFO "%s: config phy for 10BaseT\n", + dev->name); dev->if_port = map->port; /* Link Down: the timer will bring it up */ @@ -1189,8 +1339,8 @@ /* set Speed to 10Mbps, Half Duplex */ control = mdio_read(dev, aup->phy_addr, MII_CONTROL); - printk("read control %x\n", control); - control &= ~(MII_CNTL_F100 | MII_CNTL_AUTO | MII_CNTL_FDX); + control &= ~(MII_CNTL_F100 | MII_CNTL_AUTO | + MII_CNTL_FDX); /* disable auto negotiation and force 10M/HD mode*/ mdio_write(dev, aup->phy_addr, MII_CONTROL, control); @@ -1198,7 +1348,8 @@ case IF_PORT_100BASET: /* 100BaseT */ case IF_PORT_100BASETX: /* 100BaseTx */ - printk("100 base T/TX\n"); + printk(KERN_INFO "%s: config phy for 100BaseTX\n", + dev->name); dev->if_port = map->port; /* Link Down: the timer will bring it up */ @@ -1214,7 +1365,8 @@ break; case IF_PORT_100BASEFX: /* 100BaseFx */ - printk("100 Base FX\n"); + printk(KERN_INFO "%s: config phy for 100BaseFX\n", + dev->name); dev->if_port = map->port; /* Link Down: the timer will bring it up */ @@ -1230,12 +1382,14 @@ case IF_PORT_10BASE2: /* 10Base2 */ case IF_PORT_AUI: /* AUI */ /* These Modes are not supported (are they?)*/ - printk(KERN_INFO "Not supported"); + printk(KERN_ERR "%s: 10Base2/AUI not supported", + dev->name); return -EOPNOTSUPP; break; default: - printk("Invalid"); + printk(KERN_ERR "%s: Invalid media selected", + dev->name); return -EINVAL; } return 0; @@ -1253,3 +1407,6 @@ } return 0; } + +module_init(au1000_init_module); +module_exit(au1000_cleanup_module); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/au1000_eth.h linux-2.5/drivers/net/au1000_eth.h --- linux-2.5.5/drivers/net/au1000_eth.h Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/net/au1000_eth.h Sun Mar 3 17:54:35 2002 @@ -39,7 +39,7 @@ #define ETH_TX_TIMEOUT HZ/4 #define MAC_MIN_PKT_SIZE 64 -#ifdef CONFIG_MIPS_PB1000 +#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1500) #define PHY_ADDRESS 0 #define PHY_CONTROL_DEFAULT 0x3000 #define PHY_CONTROL_REG_ADDR 0 @@ -60,7 +60,9 @@ #define MII_ANLPAR 0x0005 #define MII_AEXP 0x0006 #define MII_ANEXT 0x0007 -#define MII_AUX_CNTRL 0x18 +#define MII_LSI_CONFIG 0x0011 +#define MII_LSI_STAT 0x0012 +#define MII_AUX_CNTRL 0x0018 /* mii registers specific to AMD 79C901 */ #define MII_STATUS_SUMMARY = 0x0018 @@ -123,6 +125,11 @@ #define MII_STSSUM_DPLX 0x0004 #define MII_STSSUM_AUTO 0x0002 #define MII_STSSUM_SPD 0x0001 + +/* lsi status register */ + +#define MII_LSI_STAT_FDX 0x0008 +#define MII_LSI_STAT_SPD 0x0010 /* Auxilliary Control/Status Register */ #define MII_AUX_FDX 0x0001 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/de2104x.c linux-2.5/drivers/net/de2104x.c --- linux-2.5.5/drivers/net/de2104x.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/de2104x.c Sun Mar 3 20:03:52 2002 @@ -2136,7 +2136,7 @@ return rc; } -static void __exit de_remove_one (struct pci_dev *pdev) +static void __devexit de_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct de_private *de = dev->priv; @@ -2216,7 +2216,7 @@ name: DRV_NAME, id_table: de_pci_tbl, probe: de_init_one, - remove: de_remove_one, + remove: __devexit_p(de_remove_one), #ifdef CONFIG_PM suspend: de_suspend, resume: de_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/defxx.c linux-2.5/drivers/net/defxx.c --- linux-2.5.5/drivers/net/defxx.c Wed Feb 20 02:10:52 2002 +++ linux-2.5/drivers/net/defxx.c Mon Feb 18 22:59:43 2002 @@ -199,7 +199,10 @@ * Feb 2001 davej PCI enable cleanups. */ +#include // Kill me later. +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif /* Include files */ @@ -3362,7 +3365,7 @@ static struct pci_driver dfx_driver = { name: "defxx", probe: dfx_init_one, - remove: dfx_remove_one, + remove: __devexit_p(dfx_remove_one), id_table: dfx_pci_tbl, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/dl2k.c linux-2.5/drivers/net/dl2k.c --- linux-2.5.5/drivers/net/dl2k.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/net/dl2k.c Tue Feb 26 21:24:48 2002 @@ -1682,7 +1682,7 @@ name:"dl2k", id_table:rio_pci_tbl, probe:rio_probe1, - remove:rio_remove1, + remove: __devexit_p(rio_remove1), }; static int __init diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/dmfe.c linux-2.5/drivers/net/dmfe.c --- linux-2.5.5/drivers/net/dmfe.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/net/dmfe.c Wed Jan 23 01:11:51 2002 @@ -461,7 +461,7 @@ } -static void __exit dmfe_remove_one (struct pci_dev *pdev) +static void __devexit dmfe_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct dmfe_board_info *db = dev->priv; @@ -1986,7 +1986,7 @@ name: "dmfe", id_table: dmfe_pci_tbl, probe: dmfe_init_one, - remove: dmfe_remove_one, + remove: __devexit_p(dmfe_remove_one), }; MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/e1000/LICENSE linux-2.5/drivers/net/e1000/LICENSE --- linux-2.5.5/drivers/net/e1000/LICENSE Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/e1000/LICENSE Tue Feb 26 21:24:49 2002 @@ -0,0 +1,69 @@ +This software program is available to you under a choice of one of two +licenses. You may choose to be licensed under either the GNU General Public +License (GPL) Version 2, June 1991, available at +http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the +text of which follows: + +Recipient has requested a license and Intel Corporation ("Intel") is willing +to grant a license for the software entitled Linux Base Driver for the +Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided +by Intel Corporation. The following definitions apply to this license: + +"Licensed Patents" means patent claims licensable by Intel Corporation which +are necessarily infringed by the use of sale of the Software alone or when +combined with the operating system referred to below. + +"Recipient" means the party to whom Intel delivers this Software. + +"Licensee" means Recipient and those third parties that receive a license to +any operating system available under the GNU Public License version 2.0 or +later. + +Copyright (c) 1999 - 2002 Intel Corporation. +All rights reserved. + +The license is provided to Recipient and Recipient's Licensees under the +following terms. + +Redistribution and use in source and binary forms of the Software, with or +without modification, are permitted provided that the following conditions +are met: + +Redistributions of source code of the Software may retain the above +copyright notice, this list of conditions and the following disclaimer. + +Redistributions in binary form of the Software may reproduce the above +copyright notice, this list of conditions and the following disclaimer in +the documentation and/or materials provided with the distribution. + +Neither the name of Intel Corporation nor the names of its contributors +shall be used to endorse or promote products derived from this Software +without specific prior written permission. + +Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, +royalty-free patent license under Licensed Patents to make, use, sell, offer +to sell, import and otherwise transfer the Software, if any, in source code +and object code form. This license shall include changes to the Software +that are error corrections or other minor changes to the Software that do +not add functionality or features when the Software is incorporated in any +version of an operating system that has been distributed under the GNU +General Public License 2.0 or later. This patent license shall apply to the +combination of the Software and any operating system licensed under the GNU +Public License version 2.0 or later if, at the time Intel provides the +Software to Recipient, such addition of the Software to the then publicly +available versions of such operating systems available under the GNU Public +License version 2.0 or later (whether in gold, beta or alpha form) causes +such combination to be covered by the Licensed Patents. The patent license +shall not apply to any other combinations which include the Software. NO +hardware per se is licensed hereunder. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/e1000/Makefile linux-2.5/drivers/net/e1000/Makefile --- linux-2.5.5/drivers/net/e1000/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/e1000/Makefile Tue Feb 26 21:24:49 2002 @@ -0,0 +1,16 @@ +# +# Makefile for the Intel(R) PRO/1000 ethernet driver +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +O_TARGET := e1000.o + +obj-y := e1000_main.o e1000_mac.o e1000_phy.o \ + e1000_ethtool.o e1000_param.o e1000_proc.o +obj-m := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/e1000/e1000.h linux-2.5/drivers/net/e1000/e1000.h --- linux-2.5.5/drivers/net/e1000/e1000.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/e1000/e1000.h Fri Mar 1 15:07:38 2002 @@ -0,0 +1,230 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +/* Linux PRO/1000 Ethernet Driver main header file */ + +#ifndef _E1000_H_ +#define _E1000_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct e1000_adapter; + +#include "e1000_mac.h" +#include "e1000_phy.h" + +#define BAR_0 0 + +#if DBG +#define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args) +#else +#define E1000_DBG(args...) +#endif + +#define E1000_ERR(args...) printk(KERN_ERR "e1000: " args) + +#ifdef CONFIG_PPC +#define E1000_MAX_INTR 1 +#else +#define E1000_MAX_INTR 10 +#endif + +/* Supported Rx Buffer Sizes */ +#define E1000_RXBUFFER_2048 2048 +#define E1000_RXBUFFER_4096 4096 +#define E1000_RXBUFFER_8192 8192 +#define E1000_RXBUFFER_16384 16384 + +/* How many Tx Descriptors do we need to call netif_wake_queue ? */ +#define E1000_TX_QUEUE_WAKE 16 + +#define E1000_JUMBO_PBA 0x00000028 +#define E1000_DEFAULT_PBA 0x00000030 + +/* only works for sizes that are powers of 2 */ +#define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1))) + +/* wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer */ +struct e1000_buffer { + struct sk_buff *skb; + uint64_t dma; + unsigned long length; +}; + +struct e1000_desc_ring { + /* pointer to the descriptor ring memory */ + void *desc; + /* physical address of the descriptor ring */ + dma_addr_t dma; + /* length of descriptor ring in bytes */ + unsigned int size; + /* number of descriptors in the ring */ + unsigned int count; + /* (atomic) number of desc with no buffer */ + atomic_t unused; + /* number of desc with no buffer */ + unsigned int unused_count; + /* next descriptor to associate a buffer with */ + unsigned int next_to_use; + /* next descriptor to check for DD status bit */ + unsigned int next_to_clean; + /* array of buffer information structs */ + struct e1000_buffer *buffer_info; +}; + +#define E1000_RX_DESC(ring, i) \ + (&(((struct e1000_rx_desc *)((ring).desc))[i])) + +#define E1000_TX_DESC(ring, i) \ + (&(((struct e1000_tx_desc *)((ring).desc))[i])) + +#define E1000_CONTEXT_DESC(ring, i) \ + (&(((struct e1000_context_desc *)((ring).desc))[i])) + +/* board specific private data structure */ + +struct e1000_adapter { + struct timer_list watchdog_timer; + struct timer_list phy_info_timer; +#ifdef CONFIG_PROC_FS + struct list_head proc_list_head; +#endif + char *id_string; + uint32_t bd_number; + uint32_t rx_buffer_len; + uint32_t part_num; + uint32_t wol; + uint16_t link_speed; + uint16_t link_duplex; + spinlock_t stats_lock; + atomic_t irq_sem; + boolean_t rx_csum; + + /* TX */ + struct e1000_desc_ring tx_ring; + unsigned long trans_finish; + uint32_t tx_int_delay; + uint32_t txd_cmd; + + /* RX */ + struct e1000_desc_ring rx_ring; + uint64_t hw_csum_err; + uint64_t hw_csum_good; + uint32_t rx_int_delay; + + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + + /* structs defined in e1000_mac.h or e1000_phy.h */ + struct e1000_shared_adapter shared; + struct e1000_shared_stats stats; + struct e1000_phy_info phy_info; + struct e1000_phy_stats phy_stats; +}; + +#endif /* _E1000_H_ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/e1000/e1000_ethtool.c linux-2.5/drivers/net/e1000/e1000_ethtool.c --- linux-2.5.5/drivers/net/e1000/e1000_ethtool.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/e1000/e1000_ethtool.c Tue Feb 26 21:24:49 2002 @@ -0,0 +1,377 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* ethtool support for e1000 */ + +#include "e1000.h" + +#include +#include + +extern char e1000_driver_name[]; +extern char e1000_driver_version[]; + +extern int e1000_up(struct e1000_adapter *adapter); +extern void e1000_down(struct e1000_adapter *adapter); +extern void e1000_enable_WOL(struct e1000_adapter *adapter); + +static void +e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + + if(shared->media_type == e1000_media_type_copper) { + + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full| + SUPPORTED_Autoneg | + SUPPORTED_TP); + + ecmd->advertising = ADVERTISED_TP; + + if(shared->autoneg == 1) { + ecmd->advertising |= ADVERTISED_Autoneg; + + /* the e1000 autoneg seems to match ethtool nicely */ + + ecmd->advertising |= shared->autoneg_advertised; + } + + ecmd->port = PORT_TP; + ecmd->phy_address = shared->phy_addr; + + if(shared->mac_type == e1000_82543) + ecmd->transceiver = XCVR_EXTERNAL; + else + ecmd->transceiver = XCVR_INTERNAL; + + } else { + ecmd->supported = (SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg); + + ecmd->advertising = (SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg); + + ecmd->port = PORT_FIBRE; + + ecmd->transceiver = XCVR_EXTERNAL; + } + + if(netif_carrier_ok(adapter->netdev)) { + + e1000_get_speed_and_duplex(shared, &adapter->link_speed, + &adapter->link_duplex); + ecmd->speed = adapter->link_speed; + + /* unfortunatly FULL_DUPLEX != DUPLEX_FULL + * and HALF_DUPLEX != DUPLEX_HALF */ + + if(adapter->link_duplex == FULL_DUPLEX) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + ecmd->autoneg = (shared->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); + + return; +} + +static int +e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + + if(ecmd->autoneg == AUTONEG_ENABLE) { + shared->autoneg = 1; + shared->autoneg_advertised = (ecmd->advertising & 0x002F); + } else { + shared->autoneg = 0; + switch(ecmd->speed + ecmd->duplex) { + case SPEED_10 + DUPLEX_HALF: + shared->forced_speed_duplex = e1000_10_half; + break; + case SPEED_10 + DUPLEX_FULL: + shared->forced_speed_duplex = e1000_10_full; + break; + case SPEED_100 + DUPLEX_HALF: + shared->forced_speed_duplex = e1000_100_half; + break; + case SPEED_100 + DUPLEX_FULL: + shared->forced_speed_duplex = e1000_100_full; + break; + case SPEED_1000 + DUPLEX_FULL: + shared->autoneg = 1; + shared->autoneg_advertised = ADVERTISE_1000_FULL; + break; + case SPEED_1000 + DUPLEX_HALF: /* not supported */ + default: + return -EINVAL; + } + } + + /* reset the link */ + + e1000_down(adapter); + e1000_up(adapter); + + return 0; +} + +static inline int +e1000_eeprom_size(struct e1000_shared_adapter *shared) +{ + return 128; +} + +static void +e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter, + struct ethtool_drvinfo *drvinfo) +{ + strncpy(drvinfo->driver, e1000_driver_name, 32); + strncpy(drvinfo->version, e1000_driver_version, 32); + strncpy(drvinfo->fw_version, "", 32); + strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32); + drvinfo->eedump_len = e1000_eeprom_size(&adapter->shared); + return; +} + +static void +e1000_ethtool_geeprom(struct e1000_adapter *adapter, + struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + int i, max_len; + + eeprom->magic = shared->vendor_id | (shared->device_id << 16); + + max_len = e1000_eeprom_size(shared); + + if ((eeprom->offset + eeprom->len) > max_len) + eeprom->len = (max_len - eeprom->offset); + + for(i = 0; i < max_len; i++) + eeprom_buff[i] = e1000_read_eeprom(&adapter->shared, i); + + return; +} + +static void +e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + + if(shared->mac_type < e1000_82544) { + wol->supported = 0; + wol->wolopts = 0; + return; + } + + wol->supported = WAKE_PHY | WAKE_UCAST | + WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC; + + wol->wolopts = 0; + if(adapter->wol & E1000_WUFC_LNKC) + wol->wolopts |= WAKE_PHY; + if(adapter->wol & E1000_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if(adapter->wol & E1000_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if(adapter->wol & E1000_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if(adapter->wol & E1000_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; + + return; +} + +static int +e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + + if(shared->mac_type < e1000_82544) + return wol->wolopts == 0 ? 0 : -EOPNOTSUPP; + + adapter->wol = 0; + + if(wol->wolopts & WAKE_PHY) + adapter->wol |= E1000_WUFC_LNKC; + if(wol->wolopts & WAKE_UCAST) + adapter->wol |= E1000_WUFC_EX; + if(wol->wolopts & WAKE_MCAST) + adapter->wol |= E1000_WUFC_MC; + if(wol->wolopts & WAKE_BCAST) + adapter->wol |= E1000_WUFC_BC; + if(wol->wolopts & WAKE_MAGIC) + adapter->wol |= E1000_WUFC_MAG; + + e1000_enable_WOL(adapter); + return 0; +} + +int +e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr) +{ + struct e1000_adapter *adapter = netdev->priv; + void *addr = ifr->ifr_data; + uint32_t cmd; + + if(get_user(cmd, (uint32_t *) addr)) + return -EFAULT; + + switch(cmd) { + case ETHTOOL_GSET: { + struct ethtool_cmd ecmd = {ETHTOOL_GSET}; + e1000_ethtool_gset(adapter, &ecmd); + if(copy_to_user(addr, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + } + case ETHTOOL_SSET: { + struct ethtool_cmd ecmd; + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if(copy_from_user(&ecmd, addr, sizeof(ecmd))) + return -EFAULT; + return e1000_ethtool_sset(adapter, &ecmd); + } + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo drvinfo = {ETHTOOL_GDRVINFO}; + e1000_ethtool_gdrvinfo(adapter, &drvinfo); + if(copy_to_user(addr, &drvinfo, sizeof(drvinfo))) + return -EFAULT; + return 0; + } + case ETHTOOL_NWAY_RST: { + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + e1000_down(adapter); + e1000_up(adapter); + return 0; + } + case ETHTOOL_GLINK: { + struct ethtool_value link = {ETHTOOL_GLINK}; + link.data = netif_carrier_ok(netdev); + if(copy_to_user(addr, &link, sizeof(link))) + return -EFAULT; + return 0; + } + case ETHTOOL_GWOL: { + struct ethtool_wolinfo wol = {ETHTOOL_GWOL}; + e1000_ethtool_gwol(adapter, &wol); + if(copy_to_user(addr, &wol, sizeof(wol)) != 0) + return -EFAULT; + return 0; + } + case ETHTOOL_SWOL: { + struct ethtool_wolinfo wol; + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if(copy_from_user(&wol, addr, sizeof(wol)) != 0) + return -EFAULT; + return e1000_ethtool_swol(adapter, &wol); + } + case ETHTOOL_GEEPROM: { + struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM}; + uint16_t eeprom_buff[256]; + + if(copy_from_user(&eeprom, addr, sizeof(eeprom))) + return -EFAULT; + + e1000_ethtool_geeprom(adapter, &eeprom, eeprom_buff); + + if(copy_to_user(addr, &eeprom, sizeof(eeprom))) + return -EFAULT; + + addr += offsetof(struct ethtool_eeprom, data); + + if(copy_to_user(addr, eeprom_buff + eeprom.offset, eeprom.len)) + return -EFAULT; + return 0; + } + default: + return -EOPNOTSUPP; + } +} + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/e1000/e1000_mac.c linux-2.5/drivers/net/e1000/e1000_mac.c --- linux-2.5.5/drivers/net/e1000/e1000_mac.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/e1000/e1000_mac.c Tue Feb 26 21:24:49 2002 @@ -0,0 +1,1821 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* e1000_mac.c + * Shared functions for accessing and configuring the MAC + */ + +#include "e1000_mac.h" +#include "e1000_phy.h" + +/****************************************************************************** + * Raises the EEPROM's clock input. + * + * shared - Struct containing variables accessed by shared code + * eecd_reg - EECD's current value + *****************************************************************************/ +static void +e1000_raise_clock(struct e1000_shared_adapter *shared, + uint32_t *eecd_reg) +{ + /* Raise the clock input to the EEPROM (by setting the SK bit), and then + * wait 50 microseconds. + */ + *eecd_reg = *eecd_reg | E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, *eecd_reg); + usec_delay(50); + return; +} + +/****************************************************************************** + * Lowers the EEPROM's clock input. + * + * shared - Struct containing variables accessed by shared code + * eecd_reg - EECD's current value + *****************************************************************************/ +static void +e1000_lower_clock(struct e1000_shared_adapter *shared, + uint32_t *eecd_reg) +{ + /* Lower the clock input to the EEPROM (by clearing the SK bit), and then + * wait 50 microseconds. + */ + *eecd_reg = *eecd_reg & ~E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, *eecd_reg); + usec_delay(50); + return; +} + +/****************************************************************************** + * Shift data bits out to the EEPROM. + * + * shared - Struct containing variables accessed by shared code + * data - data to send to the EEPROM + * count - number of bits to shift out + *****************************************************************************/ +static void +e1000_shift_out_bits(struct e1000_shared_adapter *shared, + uint16_t data, + uint16_t count) +{ + uint32_t eecd_reg; + uint32_t mask; + + /* We need to shift "count" bits out to the EEPROM. So, value in the + * "data" parameter will be shifted out to the EEPROM one bit at a time. + * In order to do this, "data" must be broken down into bits. + */ + mask = 0x01 << (count - 1); + eecd_reg = E1000_READ_REG(shared, EECD); + eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI); + do { + /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1", + * and then raising and then lowering the clock (the SK bit controls + * the clock input to the EEPROM). A "0" is shifted out to the EEPROM + * by setting "DI" to "0" and then raising and then lowering the clock. + */ + eecd_reg &= ~E1000_EECD_DI; + + if(data & mask) + eecd_reg |= E1000_EECD_DI; + + E1000_WRITE_REG(shared, EECD, eecd_reg); + + usec_delay(50); + + e1000_raise_clock(shared, &eecd_reg); + e1000_lower_clock(shared, &eecd_reg); + + mask = mask >> 1; + + } while(mask); + + /* We leave the "DI" bit set to "0" when we leave this routine. */ + eecd_reg &= ~E1000_EECD_DI; + E1000_WRITE_REG(shared, EECD, eecd_reg); + return; +} + +/****************************************************************************** + * Shift data bits in from the EEPROM + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +static uint16_t +e1000_shift_in_bits(struct e1000_shared_adapter *shared) +{ + uint32_t eecd_reg; + uint32_t i; + uint16_t data; + + /* In order to read a register from the EEPROM, we need to shift 16 bits + * in from the EEPROM. Bits are "shifted in" by raising the clock input to + * the EEPROM (setting the SK bit), and then reading the value of the "DO" + * bit. During this "shifting in" process the "DI" bit should always be + * clear.. + */ + + eecd_reg = E1000_READ_REG(shared, EECD); + + eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI); + data = 0; + + for(i = 0; i < 16; i++) { + data = data << 1; + e1000_raise_clock(shared, &eecd_reg); + + eecd_reg = E1000_READ_REG(shared, EECD); + + eecd_reg &= ~(E1000_EECD_DI); + if(eecd_reg & E1000_EECD_DO) + data |= 1; + + e1000_lower_clock(shared, &eecd_reg); + } + + return data; +} + +/****************************************************************************** + * Prepares EEPROM for access + * + * shared - Struct containing variables accessed by shared code + * + * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This + * function should be called before issuing a command to the EEPROM. + *****************************************************************************/ +static void +e1000_setup_eeprom(struct e1000_shared_adapter *shared) +{ + uint32_t eecd_reg; + + eecd_reg = E1000_READ_REG(shared, EECD); + + /* Clear SK and DI */ + eecd_reg &= ~(E1000_EECD_SK | E1000_EECD_DI); + E1000_WRITE_REG(shared, EECD, eecd_reg); + + /* Set CS */ + eecd_reg |= E1000_EECD_CS; + E1000_WRITE_REG(shared, EECD, eecd_reg); + return; +} + +/****************************************************************************** + * Returns EEPROM to a "standby" state + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +static void +e1000_standby_eeprom(struct e1000_shared_adapter *shared) +{ + uint32_t eecd_reg; + + eecd_reg = E1000_READ_REG(shared, EECD); + + /* Deselct EEPROM */ + eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_SK); + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + + /* Clock high */ + eecd_reg |= E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + + /* Select EEPROM */ + eecd_reg |= E1000_EECD_CS; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + + /* Clock low */ + eecd_reg &= ~E1000_EECD_SK; + E1000_WRITE_REG(shared, EECD, eecd_reg); + usec_delay(50); + return; +} + + +/****************************************************************************** + * Forces the MAC's flow control settings. + * + * shared - Struct containing variables accessed by shared code + * + * Sets the TFCE and RFCE bits in the device control register to reflect + * the adapter settings. TFCE and RFCE need to be explicitly set by + * software when a Copper PHY is used because autonegotiation is managed + * by the PHY rather than the MAC. Software must also configure these + * bits when link is forced on a fiber connection. + *****************************************************************************/ +static void +e1000_force_mac_fc(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + + DEBUGFUNC("e1000_force_mac_fc"); + + /* Get the current configuration of the Device Control Register */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Because we didn't get link via the internal auto-negotiation + * mechanism (we either forced link or we got link via PHY + * auto-neg), we have to manually enable/disable transmit an + * receive flow control. + * + * The "Case" statement below enables/disable flow control + * according to the "shared->fc" parameter. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause + * frames but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * frames but we do not receive pause frames). + * 3: Both Rx and TX flow control (symmetric) is enabled. + * other: No other values should be possible at this point. + */ + + switch (shared->fc) { + case e1000_fc_none: + ctrl_reg &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); + break; + case e1000_fc_rx_pause: + ctrl_reg &= (~E1000_CTRL_TFCE); + ctrl_reg |= E1000_CTRL_RFCE; + break; + case e1000_fc_tx_pause: + ctrl_reg &= (~E1000_CTRL_RFCE); + ctrl_reg |= E1000_CTRL_TFCE; + break; + case e1000_fc_full: + ctrl_reg |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + /* Disable TX Flow Control for 82542 (rev 2.0) */ + if(shared->mac_type == e1000_82542_rev2_0) + ctrl_reg &= (~E1000_CTRL_TFCE); + + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + return; +} + +/****************************************************************************** + * Reset the transmit and receive units; mask and clear all interrupts. + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_adapter_stop(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint32_t ctrl_ext_reg; + uint32_t icr_reg; + uint16_t pci_cmd_word; + + DEBUGFUNC("e1000_shared_adapter_stop"); + + /* If we are stopped or resetting exit gracefully and wait to be + * started again before accessing the hardware. + */ + if(shared->adapter_stopped) { + DEBUGOUT("Exiting because the adapter is already stopped!!!\n"); + return; + } + + /* Set the Adapter Stopped flag so other driver functions stop + * touching the Hardware. + */ + shared->adapter_stopped = TRUE; + + /* For 82542 (rev 2.0), disable MWI before issuing a device reset */ + if(shared->mac_type == e1000_82542_rev2_0) { + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); + + pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE; + + e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word); + } + } + + /* Clear interrupt mask to stop board from generating interrupts */ + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(shared, IMC, 0xffffffff); + + /* Disable the Transmit and Receive units. Then delay to allow + * any pending transactions to complete before we hit the MAC with + * the global reset. + */ + E1000_WRITE_REG(shared, RCTL, 0); + E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP); + + /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */ + shared->tbi_compatibility_on = FALSE; + + msec_delay(10); + + /* Issue a global reset to the MAC. This will reset the chip's + * transmit, receive, DMA, and link units. It will not effect + * the current PCI configuration. The global reset bit is self- + * clearing, and should clear within a microsecond. + */ + DEBUGOUT("Issuing a global reset to MAC\n"); + ctrl_reg = E1000_READ_REG(shared, CTRL); + E1000_WRITE_REG(shared, CTRL, (ctrl_reg | E1000_CTRL_RST)); + + /* Delay a few ms just to allow the reset to complete */ + msec_delay(10); + +#if DBG + /* Make sure the self-clearing global reset bit did self clear */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + ASSERT(!(ctrl_reg & E1000_CTRL_RST)); +#endif + + /* Force a reload from the EEPROM */ + ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); + ctrl_ext_reg |= E1000_CTRL_EXT_EE_RST; + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + msec_delay(2); + + /* Clear interrupt mask to stop board from generating interrupts */ + DEBUGOUT("Masking off all interrupts\n"); + E1000_WRITE_REG(shared, IMC, 0xffffffff); + + /* Clear any pending interrupt events. */ + icr_reg = E1000_READ_REG(shared, ICR); + + /* If MWI was previously enabled, reenable it. */ + if(shared->mac_type == e1000_82542_rev2_0) { + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + e1000_write_pci_cfg(shared, + PCI_COMMAND_REGISTER, &shared->pci_cmd_word); + } + } + return; +} + +/****************************************************************************** + * Performs basic configuration of the adapter. + * + * shared - Struct containing variables accessed by shared code + * + * Assumes that the controller has previously been reset and is in a + * post-reset uninitialized state. Initializes the receive address registers, + * multicast table, and VLAN filter table. Calls routines to setup link + * configuration and flow control settings. Clears all on-chip counters. Leaves + * the transmit and receive units disabled and uninitialized. + *****************************************************************************/ +boolean_t +e1000_init_hw(struct e1000_shared_adapter *shared) +{ + uint32_t status_reg; + uint32_t i; + uint16_t pci_cmd_word; + boolean_t status; + + DEBUGFUNC("e1000_init_hw"); + + /* Set the Media Type and exit with error if it is not valid. */ + if(shared->mac_type != e1000_82543) { + /* tbi_compatibility is only valid on 82543 */ + shared->tbi_compatibility_en = FALSE; + } + + if(shared->mac_type >= e1000_82543) { + status_reg = E1000_READ_REG(shared, STATUS); + if(status_reg & E1000_STATUS_TBIMODE) { + shared->media_type = e1000_media_type_fiber; + /* tbi_compatibility not valid on fiber */ + shared->tbi_compatibility_en = FALSE; + } else { + shared->media_type = e1000_media_type_copper; + } + } else { + /* This is an 82542 (fiber only) */ + shared->media_type = e1000_media_type_fiber; + } + + /* Disabling VLAN filtering. */ + DEBUGOUT("Initializing the IEEE VLAN\n"); + E1000_WRITE_REG(shared, VET, 0); + + e1000_clear_vfta(shared); + + /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */ + if(shared->mac_type == e1000_82542_rev2_0) { + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); + pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE; + e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word); + } + E1000_WRITE_REG(shared, RCTL, E1000_RCTL_RST); + + msec_delay(5); + } + + /* Setup the receive address. This involves initializing all of the Receive + * Address Registers (RARs 0 - 15). + */ + e1000_init_rx_addrs(shared); + + /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */ + if(shared->mac_type == e1000_82542_rev2_0) { + E1000_WRITE_REG(shared, RCTL, 0); + + msec_delay(1); + + if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) { + e1000_write_pci_cfg(shared, + PCI_COMMAND_REGISTER, &shared->pci_cmd_word); + } + } + + /* Zero out the Multicast HASH table */ + DEBUGOUT("Zeroing the MTA\n"); + for(i = 0; i < E1000_MC_TBL_SIZE; i++) + E1000_WRITE_REG_ARRAY(shared, MTA, i, 0); + + /* Call a subroutine to configure the link and setup flow control. */ + status = e1000_setup_fc_and_link(shared); + + /* Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + e1000_clear_hw_cntrs(shared); + + return (status); +} + +/****************************************************************************** + * Initializes receive address filters. + * + * shared - Struct containing variables accessed by shared code + * + * Places the MAC address in receive address register 0 and clears the rest + * of the receive addresss registers. Clears the multicast table. Assumes + * the receiver is in reset when the routine is called. + *****************************************************************************/ +void +e1000_init_rx_addrs(struct e1000_shared_adapter *shared) +{ + uint32_t i; + uint32_t addr_low; + uint32_t addr_high; + + DEBUGFUNC("e1000_init_rx_addrs"); + + /* Setup the receive address. */ + DEBUGOUT("Programming MAC Address into RAR[0]\n"); + addr_low = (shared->mac_addr[0] | + (shared->mac_addr[1] << 8) | + (shared->mac_addr[2] << 16) | (shared->mac_addr[3] << 24)); + + addr_high = (shared->mac_addr[4] | + (shared->mac_addr[5] << 8) | E1000_RAH_AV); + + E1000_WRITE_REG_ARRAY(shared, RA, 0, addr_low); + E1000_WRITE_REG_ARRAY(shared, RA, 1, addr_high); + + /* Zero out the other 15 receive addresses. */ + DEBUGOUT("Clearing RAR[1-15]\n"); + for(i = 1; i < E1000_RAR_ENTRIES; i++) { + E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0); + E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0); + } + + return; +} + +/****************************************************************************** + * Updates the MAC's list of multicast addresses. + * + * shared - Struct containing variables accessed by shared code + * mc_addr_list - the list of new multicast addresses + * mc_addr_count - number of addresses + * pad - number of bytes between addresses in the list + * + * The given list replaces any existing list. Clears the last 15 receive + * address registers and the multicast table. Uses receive address registers + * for the first 15 multicast addresses, and hashes the rest into the + * multicast table. + *****************************************************************************/ +void +e1000_mc_addr_list_update(struct e1000_shared_adapter *shared, + uint8_t *mc_addr_list, + uint32_t mc_addr_count, + uint32_t pad) +{ + uint32_t hash_value; + uint32_t i; + uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */ + + DEBUGFUNC("e1000_mc_addr_list_update"); + + /* Set the new number of MC addresses that we are being requested to use. */ + shared->num_mc_addrs = mc_addr_count; + + /* Clear RAR[1-15] */ + DEBUGOUT(" Clearing RAR[1-15]\n"); + for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) { + E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0); + E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0); + } + + /* Clear the MTA */ + DEBUGOUT(" Clearing MTA\n"); + for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) { + E1000_WRITE_REG_ARRAY(shared, MTA, i, 0); + } + + /* Add the new addresses */ + for(i = 0; i < mc_addr_count; i++) { + DEBUGOUT(" Adding the multicast addresses:\n"); + DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i, + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4], + mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]); + + hash_value = e1000_hash_mc_addr(shared, + mc_addr_list + + (i * (ETH_LENGTH_OF_ADDRESS + pad))); + + DEBUGOUT1(" Hash value = 0x%03X\n", hash_value); + + /* Place this multicast address in the RAR if there is room, * + * else put it in the MTA + */ + if(rar_used_count < E1000_RAR_ENTRIES) { + e1000_rar_set(shared, + mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)), + rar_used_count); + rar_used_count++; + } else { + e1000_mta_set(shared, hash_value); + } + } + + DEBUGOUT("MC Update Complete\n"); + return; +} + +/****************************************************************************** + * Hashes an address to determine its location in the multicast table + * + * shared - Struct containing variables accessed by shared code + * mc_addr - the multicast address to hash + *****************************************************************************/ +uint32_t +e1000_hash_mc_addr(struct e1000_shared_adapter *shared, + uint8_t *mc_addr) +{ + uint32_t hash_value = 0; + + /* The portion of the address that is used for the hash table is + * determined by the mc_filter_type setting. + */ + switch (shared->mc_filter_type) { + /* [0] [1] [2] [3] [4] [5] + * 01 AA 00 12 34 56 + * LSB MSB - According to H/W docs */ + case 0: + /* [47:36] i.e. 0x563 for above example address */ + hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4)); + break; + case 1: /* [46:35] i.e. 0xAC6 for above example address */ + hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5)); + break; + case 2: /* [45:34] i.e. 0x5D8 for above example address */ + hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6)); + break; + case 3: /* [43:32] i.e. 0x634 for above example address */ + hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8)); + break; + } + + hash_value &= 0xFFF; + return (hash_value); +} + +/****************************************************************************** + * Sets the bit in the multicast table corresponding to the hash value. + * + * shared - Struct containing variables accessed by shared code + * hash_value - Multicast address hash value + *****************************************************************************/ +void +e1000_mta_set(struct e1000_shared_adapter *shared, + uint32_t hash_value) +{ + uint32_t hash_bit, hash_reg; + uint32_t mta_reg; + uint32_t temp; + + /* The MTA is a register array of 128 32-bit registers. + * It is treated like an array of 4096 bits. We want to set + * bit BitArray[hash_value]. So we figure out what register + * the bit is in, read it, OR in the new bit, then write + * back the new value. The register is determined by the + * upper 7 bits of the hash value and the bit within that + * register are determined by the lower 5 bits of the value. + */ + hash_reg = (hash_value >> 5) & 0x7F; + hash_bit = hash_value & 0x1F; + + mta_reg = E1000_READ_REG_ARRAY(shared, MTA, hash_reg); + + mta_reg |= (1 << hash_bit); + + /* If we are on an 82544 and we are trying to write an odd offset + * in the MTA, save off the previous entry before writing and + * restore the old value after writing. + */ + if((shared->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) { + temp = E1000_READ_REG_ARRAY(shared, MTA, (hash_reg - 1)); + E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg); + E1000_WRITE_REG_ARRAY(shared, MTA, (hash_reg - 1), temp); + } else { + E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg); + } + return; +} + +/****************************************************************************** + * Puts an ethernet address into a receive address register. + * + * shared - Struct containing variables accessed by shared code + * addr - Address to put into receive address register + * index - Receive address register to write + *****************************************************************************/ +void +e1000_rar_set(struct e1000_shared_adapter *shared, + uint8_t *addr, + uint32_t index) +{ + uint32_t rar_low, rar_high; + + /* HW expects these in little endian so we reverse the byte order + * from network order (big endian) to little endian + */ + rar_low = ((uint32_t) addr[0] | + ((uint32_t) addr[1] << 8) | + ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24)); + + rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV); + + E1000_WRITE_REG_ARRAY(shared, RA, (index << 1), rar_low); + E1000_WRITE_REG_ARRAY(shared, RA, ((index << 1) + 1), rar_high); + return; +} + +/****************************************************************************** + * Writes a value to the specified offset in the VLAN filter table. + * + * shared - Struct containing variables accessed by shared code + * offset - Offset in VLAN filer table to write + * value - Value to write into VLAN filter table + *****************************************************************************/ +void +e1000_write_vfta(struct e1000_shared_adapter *shared, + uint32_t offset, + uint32_t value) +{ + uint32_t temp; + + if((shared->mac_type == e1000_82544) && ((offset & 0x1) == 1)) { + temp = E1000_READ_REG_ARRAY(shared, VFTA, (offset - 1)); + E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value); + E1000_WRITE_REG_ARRAY(shared, VFTA, (offset - 1), temp); + } else { + E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value); + } + return; +} + +/****************************************************************************** + * Clears the VLAN filer table + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_clear_vfta(struct e1000_shared_adapter *shared) +{ + uint32_t offset; + + for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) + E1000_WRITE_REG_ARRAY(shared, VFTA, offset, 0); + return; +} + +/****************************************************************************** + * Configures flow control and link settings. + * + * shared - Struct containing variables accessed by shared code + * + * Determines which flow control settings to use. Calls the apropriate media- + * specific link configuration function. Configures the flow control settings. + * Assuming the adapter has a valid link partner, a valid link should be + * established. Assumes the hardware has previously been reset and the + * transmitter and receiver are not enabled. + *****************************************************************************/ +boolean_t +e1000_setup_fc_and_link(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint32_t eecd_reg; + uint32_t ctrl_ext_reg; + boolean_t status = TRUE; + + DEBUGFUNC("e1000_setup_fc_and_link"); + + /* Read the SWDPIO bits and the ILOS bit out of word 0x0A in the + * EEPROM. Store these bits in a variable that we will later write + * to the Device Control Register (CTRL). + */ + eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL1_REG); + + ctrl_reg = + (((eecd_reg & EEPROM_WORD0A_SWDPIO) << SWDPIO_SHIFT) | + ((eecd_reg & EEPROM_WORD0A_ILOS) << ILOS_SHIFT)); + + /* Set the PCI priority bit correctly in the CTRL register. This + * determines if the adapter gives priority to receives, or if it + * gives equal priority to transmits and receives. + */ + if(shared->dma_fairness) + ctrl_reg |= E1000_CTRL_PRIOR; + + /* Read and store word 0x0F of the EEPROM. This word contains bits + * that determine the hardware's default PAUSE (flow control) mode, + * a bit that determines whether the HW defaults to enabling or + * disabling auto-negotiation, and the direction of the + * SW defined pins. If there is no SW over-ride of the flow + * control setting, then the variable shared->fc will + * be initialized based on a value in the EEPROM. + */ + eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL2_REG); + + if(shared->fc > e1000_fc_full) { + if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == 0) + shared->fc = e1000_fc_none; + else if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR) + shared->fc = e1000_fc_tx_pause; + else + shared->fc = e1000_fc_full; + } + + /* We want to save off the original Flow Control configuration just + * in case we get disconnected and then reconnected into a different + * hub or switch with different Flow Control capabilities. + */ + shared->original_fc = shared->fc; + + if(shared->mac_type == e1000_82542_rev2_0) + shared->fc &= (~e1000_fc_tx_pause); + + if((shared->mac_type < e1000_82543) && (shared->report_tx_early == 1)) + shared->fc &= (~e1000_fc_rx_pause); + + DEBUGOUT1("After fix-ups FlowControl is now = %x\n", shared->fc); + + /* Take the 4 bits from EEPROM word 0x0F that determine the initial + * polarity value for the SW controlled pins, and setup the + * Extended Device Control reg with that info. + * This is needed because one of the SW controlled pins is used for + * signal detection. So this should be done before e1000_setup_pcs_link() + * or e1000_phy_setup() is called. + */ + if(shared->mac_type == e1000_82543) { + ctrl_ext_reg = ((eecd_reg & EEPROM_WORD0F_SWPDIO_EXT) + << SWDPIO__EXT_SHIFT); + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + } + + /* Call the necessary subroutine to configure the link. */ + if(shared->media_type == e1000_media_type_fiber) + status = e1000_setup_pcs_link(shared, ctrl_reg); + else + status = e1000_phy_setup(shared, ctrl_reg); + + /* Initialize the flow control address, type, and PAUSE timer + * registers to their default values. This is done even if flow + * control is disabled, because it does not hurt anything to + * initialize these registers. + */ + DEBUGOUT("Initializing the Flow Control address, type and timer regs\n"); + + E1000_WRITE_REG(shared, FCAL, FLOW_CONTROL_ADDRESS_LOW); + E1000_WRITE_REG(shared, FCAH, FLOW_CONTROL_ADDRESS_HIGH); + E1000_WRITE_REG(shared, FCT, FLOW_CONTROL_TYPE); + E1000_WRITE_REG(shared, FCTTV, shared->fc_pause_time); + + /* Set the flow control receive threshold registers. Normally, + * these registers will be set to a default threshold that may be + * adjusted later by the driver's runtime code. However, if the + * ability to transmit pause frames in not enabled, then these + * registers will be set to 0. + */ + if(!(shared->fc & e1000_fc_tx_pause)) { + E1000_WRITE_REG(shared, FCRTL, 0); + E1000_WRITE_REG(shared, FCRTH, 0); + } else { + /* We need to set up the Receive Threshold high and low water marks + * as well as (optionally) enabling the transmission of XON frames. + */ + if(shared->fc_send_xon) { + E1000_WRITE_REG(shared, FCRTL, + (shared->fc_low_water | E1000_FCRTL_XONE)); + E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water); + } else { + E1000_WRITE_REG(shared, FCRTL, shared->fc_low_water); + E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water); + } + } + return (status); +} + +/****************************************************************************** + * Sets up link for a fiber based adapter + * + * shared - Struct containing variables accessed by shared code + * ctrl_reg - Current value of the device control register + * + * Manipulates Physical Coding Sublayer functions in order to configure + * link. Assumes the hardware has been previously reset and the transmitter + * and receiver are not enabled. + *****************************************************************************/ +boolean_t +e1000_setup_pcs_link(struct e1000_shared_adapter *shared, + uint32_t ctrl_reg) +{ + uint32_t status_reg; + uint32_t tctl_reg; + uint32_t txcw_reg = 0; + uint32_t i; + + DEBUGFUNC("e1000_setup_pcs_link"); + + /* Setup the collsion distance. Since this is configuring the + * TBI it is assumed that we are in Full Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + i = E1000_FDX_COLLISION_DISTANCE; + i <<= E1000_COLD_SHIFT; + tctl_reg |= i; + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + /* Check for a software override of the flow control settings, and + * setup the device accordingly. If auto-negotiation is enabled, + * then software will have to set the "PAUSE" bits to the correct + * value in the Tranmsit Config Word Register (TXCW) and re-start + * auto-negotiation. However, if auto-negotiation is disabled, + * then software will have to manually configure the two flow + * control enable bits in the CTRL register. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (shared->fc) { + case e1000_fc_none: /* 0 */ + /* Flow control (RX & TX) is completely disabled by a + * software over-ride. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD); + break; + case e1000_fc_rx_pause: /* 1 */ + /* RX Flow control is enabled, and TX Flow control is + * disabled, by a software over-ride. + */ + /* Since there really isn't a way to advertise that we are + * capable of RX Pause ONLY, we will advertise that we + * support both symmetric and asymmetric RX PAUSE. Later + * we will disable the adapter's ability to send PAUSE + * frames. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + case e1000_fc_tx_pause: /* 2 */ + /* TX Flow control is enabled, and RX Flow control is + * disabled, by a software over-ride. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); + break; + case e1000_fc_full: /* 3 */ + /* Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); + break; + default: + /* We should never get here. The value should be 0-3. */ + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + /* Since auto-negotiation is enabled, take the link out of reset. + * (the link will be in reset, because we previously reset the + * chip). This will restart auto-negotiation. If auto-neogtiation + * is successful then the link-up status bit will be set and the + * flow control enable bits (RFCE and TFCE) will be set according + * to their negotiated value. + */ + DEBUGOUT("Auto-negotiation enabled\n"); + + E1000_WRITE_REG(shared, TXCW, txcw_reg); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + shared->txcw_reg = txcw_reg; + msec_delay(1); + + /* If we have a signal then poll for a "Link-Up" indication in the + * Device Status Register. Time-out if a link isn't seen in 500 + * milliseconds seconds (Auto-negotiation should complete in less + * than 500 milliseconds even if the other end is doing it in SW). + */ + if(!(E1000_READ_REG(shared, CTRL) & E1000_CTRL_SWDPIN1)) { + + DEBUGOUT("Looking for Link\n"); + for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) { + msec_delay(10); + status_reg = E1000_READ_REG(shared, STATUS); + if(status_reg & E1000_STATUS_LU) + break; + } + + if(i == (LINK_UP_TIMEOUT / 10)) { + /* AutoNeg failed to achieve a link, so we'll call the + * "CheckForLink" routine. This routine will force the link + * up if we have "signal-detect". This will allow us to + * communicate with non-autonegotiating link partners. + */ + DEBUGOUT("Never got a valid link from auto-neg!!!\n"); + + shared->autoneg_failed = 1; + e1000_check_for_link(shared); + shared->autoneg_failed = 0; + } else { + shared->autoneg_failed = 0; + DEBUGOUT("Valid Link Found\n"); + } + } else { + DEBUGOUT("No Signal Detected\n"); + } + + return (TRUE); +} + +/****************************************************************************** + * Configures flow control settings after link is established + * + * shared - Struct containing variables accessed by shared code + * + * Should be called immediately after a valid link has been established. + * Forces MAC flow control settings if link was forced. When in MII/GMII mode + * and autonegotiation is enabled, the MAC flow control settings will be set + * based on the flow control negotiated by the PHY. In TBI mode, the TFCE + * and RFCE bits will be automaticaly set to the negotiated flow control mode. + *****************************************************************************/ +void +e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared) +{ + uint16_t mii_status_reg; + uint16_t mii_nway_adv_reg; + uint16_t mii_nway_lp_ability_reg; + uint16_t speed; + uint16_t duplex; + + DEBUGFUNC("e1000_config_fc_after_link_up"); + + /* Check for the case where we have fiber media and auto-neg failed + * so we had to force link. In this case, we need to force the + * configuration of the MAC to match the "fc" parameter. + */ + if(((shared->media_type == e1000_media_type_fiber) + && (shared->autoneg_failed)) + || ((shared->media_type == e1000_media_type_copper) + && (!shared->autoneg))) { + e1000_force_mac_fc(shared); + } + + /* Check for the case where we have copper media and auto-neg is + * enabled. In this case, we need to check and see if Auto-Neg + * has completed, and if so, how the PHY and link partner has + * flow control configured. + */ + if((shared->media_type == e1000_media_type_copper) && shared->autoneg) { + /* Read the MII Status Register and check to see if AutoNeg + * has completed. We read this twice because this reg has + * some "sticky" (latched) bits. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) { + /* The AutoNeg process has completed, so we now need to + * read both the Auto Negotiation Advertisement Register + * (Address 4) and the Auto_Negotiation Base Page Ability + * Register (Address 5) to determine how flow control was + * negotiated. + */ + mii_nway_adv_reg = e1000_read_phy_reg(shared, + PHY_AUTONEG_ADV); + mii_nway_lp_ability_reg = e1000_read_phy_reg(shared, + PHY_LP_ABILITY); + + /* Two bits in the Auto Negotiation Advertisement Register + * (Address 4) and two bits in the Auto Negotiation Base + * Page Ability Register (Address 5) determine flow control + * for both the PHY and the link partner. The following + * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, + * 1999, describes these PAUSE resolution bits and how flow + * control is determined based upon these settings. + * NOTE: DC = Don't Care + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution + *-------|---------|-------|---------|-------------------- + * 0 | 0 | DC | DC | e1000_fc_none + * 0 | 1 | 0 | DC | e1000_fc_none + * 0 | 1 | 1 | 0 | e1000_fc_none + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * 1 | 0 | 0 | DC | e1000_fc_none + * 1 | DC | 1 | DC | e1000_fc_full + * 1 | 1 | 0 | 0 | e1000_fc_none + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * + */ + /* Are both PAUSE bits set to 1? If so, this implies + * Symmetric Flow Control is enabled at both ends. The + * ASM_DIR bits are irrelevant per the spec. + * + * For Symmetric Flow Control: + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | DC | 1 | DC | e1000_fc_full + * + */ + if((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { + /* Now we need to check if the user selected RX ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if(shared->original_fc == e1000_fc_full) { + shared->fc = e1000_fc_full; + DEBUGOUT("Flow Control = FULL.\r\n"); + } else { + shared->fc = e1000_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + } + } + /* For receiving PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * + */ + else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + shared->fc = e1000_fc_tx_pause; + DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n"); + } + /* For transmitting PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * + */ + else if((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + shared->fc = e1000_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + } + /* Per the IEEE spec, at this point flow control should be + * disabled. However, we want to consider that we could + * be connected to a legacy switch that doesn't advertise + * desired flow control, but can be forced on the link + * partner. So if we advertised no flow control, that is + * what we will resolve to. If we advertised some kind of + * receive capability (Rx Pause Only or Full Flow Control) + * and the link partner advertised none, we will configure + * ourselves to enable Rx Flow Control only. We can do + * this safely for two reasons: If the link partner really + * didn't want flow control enabled, and we enable Rx, no + * harm done since we won't be receiving any PAUSE frames + * anyway. If the intent on the link partner was to have + * flow control enabled, then by us enabling RX only, we + * can at least receive pause frames and process them. + * This is a good idea because in most cases, since we are + * predominantly a server NIC, more times than not we will + * be asked to delay transmission of packets than asking + * our link partner to pause transmission of frames. + */ + else if(shared->original_fc == e1000_fc_none || + shared->original_fc == e1000_fc_tx_pause) { + shared->fc = e1000_fc_none; + DEBUGOUT("Flow Control = NONE.\r\n"); + } else { + shared->fc = e1000_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); + } + + /* Now we need to do one last check... If we auto- + * negotiated to HALF DUPLEX, flow control should not be + * enabled per IEEE 802.3 spec. + */ + e1000_get_speed_and_duplex(shared, &speed, &duplex); + + if(duplex == HALF_DUPLEX) + shared->fc = e1000_fc_none; + + /* Now we call a subroutine to actually force the MAC + * controller to use the correct flow control settings. + */ + e1000_force_mac_fc(shared); + } else { + DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n"); + } + } + return; +} + +/****************************************************************************** + * Checks to see if the link status of the hardware has changed. + * + * shared - Struct containing variables accessed by shared code + * + * Called by any function that needs to check the link status of the adapter. + *****************************************************************************/ +void +e1000_check_for_link(struct e1000_shared_adapter *shared) +{ + uint32_t rxcw_reg; + uint32_t ctrl_reg; + uint32_t status_reg; + uint32_t rctl_reg; + uint16_t phy_data; + uint16_t lp_capability; + + DEBUGFUNC("e1000_check_for_link"); + + ctrl_reg = E1000_READ_REG(shared, CTRL); + status_reg = E1000_READ_REG(shared, STATUS); + rxcw_reg = E1000_READ_REG(shared, RXCW); + + /* If we have a copper PHY then we only want to go out to the PHY + * registers to see if Auto-Neg has completed and/or if our link + * status has changed. The get_link_status flag will be set if we + * receive a Link Status Change interrupt or we have Rx Sequence + * Errors. + */ + if(shared->media_type == e1000_media_type_copper + && shared->get_link_status) { + /* First we want to see if the MII Status Register reports + * link. If so, then we want to get the current speed/duplex + * of the PHY. + * Read the register twice since the link bit is sticky. + */ + phy_data = e1000_read_phy_reg(shared, PHY_STATUS); + phy_data = e1000_read_phy_reg(shared, PHY_STATUS); + + if(phy_data & MII_SR_LINK_STATUS) { + shared->get_link_status = FALSE; + } else { + DEBUGOUT("**** CFL - No link detected. ****\r\n"); + return; + } + + /* If we are forcing speed/duplex, then we simply return since + * we have already determined whether we have link or not. + */ + if(!shared->autoneg) { + return; + } + + switch (shared->phy_id) { + case M88E1000_12_PHY_ID: + case M88E1000_14_PHY_ID: + case M88E1000_I_PHY_ID: + /* We have a M88E1000 PHY and Auto-Neg is enabled. If we + * have Si on board that is 82544 or newer, Auto + * Speed Detection takes care of MAC speed/duplex + * configuration. So we only need to configure Collision + * Distance in the MAC. Otherwise, we need to force + * speed/duplex on the MAC to the current PHY speed/duplex + * settings. + */ + if(shared->mac_type >= e1000_82544) { + DEBUGOUT("CFL - Auto-Neg complete."); + DEBUGOUT("Configuring Collision Distance."); + e1000_config_collision_dist(shared); + } else { + /* Read the Phy Specific Status register to get the + * resolved speed/duplex settings. Then call + * e1000_config_mac_to_phy which will retrieve + * PHY register information and configure the MAC to + * equal the negotiated speed/duplex. + */ + phy_data = e1000_read_phy_reg(shared, + M88E1000_PHY_SPEC_STATUS); + + DEBUGOUT1("CFL - Auto-Neg complete. phy_data = %x\r\n", + phy_data); + e1000_config_mac_to_phy(shared, phy_data); + } + + /* Configure Flow Control now that Auto-Neg has completed. + * We need to first restore the users desired Flow + * Control setting since we may have had to re-autoneg + * with a different link partner. + */ + e1000_config_fc_after_link_up(shared); + break; + + default: + DEBUGOUT("CFL - Invalid PHY detected.\r\n"); + + } /* end switch statement */ + + /* At this point we know that we are on copper, link is up, + * and we are auto-neg'd. These are pre-conditions for checking + * the link parter capabilities register. We use the link partner + * capabilities to determine if TBI Compatibility needs to be turned on + * or turned off. If the link partner advertises any speed in addition + * to Gigabit, then we assume that they are GMII-based and TBI + * compatibility is not needed. + * If no other speeds are advertised, then we assume the link partner + * is TBI-based and we turn on TBI Compatibility. + */ + if(shared->tbi_compatibility_en) { + lp_capability = e1000_read_phy_reg(shared, PHY_LP_ABILITY); + if(lp_capability & (NWAY_LPAR_10T_HD_CAPS | + NWAY_LPAR_10T_FD_CAPS | + NWAY_LPAR_100TX_HD_CAPS | + NWAY_LPAR_100TX_FD_CAPS | + NWAY_LPAR_100T4_CAPS)) { + /* If our link partner advertises below Gig, then they do not + * need the special Tbi Compatibility mode. + */ + if(shared->tbi_compatibility_on) { + /* If we previously were in the mode, turn it off, now. */ + rctl_reg = E1000_READ_REG(shared, RCTL); + rctl_reg &= ~E1000_RCTL_SBP; + E1000_WRITE_REG(shared, RCTL, rctl_reg); + shared->tbi_compatibility_on = FALSE; + } + } else { + /* If the mode is was previously off, turn it on. + * For compatibility with a suspected Tbi link partners, + * we will store bad packets. + * (Certain frames have an additional byte on the end and will + * look like CRC errors to to the hardware). + */ + if(!shared->tbi_compatibility_on) { + shared->tbi_compatibility_on = TRUE; + rctl_reg = E1000_READ_REG(shared, RCTL); + rctl_reg |= E1000_RCTL_SBP; + E1000_WRITE_REG(shared, RCTL, rctl_reg); + } + } + } + } /* end if e1000_media_type_copper statement */ + /* If we don't have link (auto-negotiation failed or link partner + * cannot auto-negotiate) and the cable is plugged in since we don't + * have Loss-Of-Signal (we HAVE a signal) and our link partner is + * not trying to AutoNeg with us (we are receiving idles/data + * then we need to force our link to connect to a non + * auto-negotiating link partner. We also need to give + * auto-negotiation time to complete in case the cable was just + * plugged in. The autoneg_failed flag does this. + */ + else if((shared->media_type == e1000_media_type_fiber) && /* Fiber PHY */ + (!(status_reg & E1000_STATUS_LU)) && /* no link and */ + (!(ctrl_reg & E1000_CTRL_SWDPIN1)) && /* we have signal */ + (!(rxcw_reg & E1000_RXCW_C))) { /* and rxing idle/data */ + if(shared->autoneg_failed == 0) { /* given AutoNeg time */ + shared->autoneg_failed = 1; + return; + } + + DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n"); + + /* Disable auto-negotiation in the TXCW register */ + E1000_WRITE_REG(shared, TXCW, (shared->txcw_reg & ~E1000_TXCW_ANE)); + + /* Force link-up and also force full-duplex. */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + ctrl_reg |= (E1000_CTRL_SLU | E1000_CTRL_FD); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + /* Configure Flow Control after forcing link up. */ + e1000_config_fc_after_link_up(shared); + + } else if((shared->media_type == e1000_media_type_fiber) && /* Fiber */ + (ctrl_reg & E1000_CTRL_SLU) && /* we have forced link */ + (rxcw_reg & E1000_RXCW_C)) { /* and Rxing /C/ ordered sets */ + /* If we are forcing link and we are receiving /C/ ordered sets, + * then re-enable auto-negotiation in the RXCW register and + * disable forced link in the Device Control register in an attempt + * to AutoNeg with our link partner. + */ + DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n"); + + /* Enable auto-negotiation in the TXCW register and stop + * forcing link. + */ + E1000_WRITE_REG(shared, TXCW, shared->txcw_reg); + + E1000_WRITE_REG(shared, CTRL, (ctrl_reg & ~E1000_CTRL_SLU)); + } + + return; +} + +/****************************************************************************** + * Clears all hardware statistics counters. + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared) +{ + volatile uint32_t temp_reg; + + DEBUGFUNC("e1000_clear_hw_cntrs"); + + /* if we are stopped or resetting exit gracefully */ + if(shared->adapter_stopped) { + DEBUGOUT("Exiting because the adapter is stopped!!!\n"); + return; + } + + temp_reg = E1000_READ_REG(shared, CRCERRS); + temp_reg = E1000_READ_REG(shared, SYMERRS); + temp_reg = E1000_READ_REG(shared, MPC); + temp_reg = E1000_READ_REG(shared, SCC); + temp_reg = E1000_READ_REG(shared, ECOL); + temp_reg = E1000_READ_REG(shared, MCC); + temp_reg = E1000_READ_REG(shared, LATECOL); + temp_reg = E1000_READ_REG(shared, COLC); + temp_reg = E1000_READ_REG(shared, DC); + temp_reg = E1000_READ_REG(shared, SEC); + temp_reg = E1000_READ_REG(shared, RLEC); + temp_reg = E1000_READ_REG(shared, XONRXC); + temp_reg = E1000_READ_REG(shared, XONTXC); + temp_reg = E1000_READ_REG(shared, XOFFRXC); + temp_reg = E1000_READ_REG(shared, XOFFTXC); + temp_reg = E1000_READ_REG(shared, FCRUC); + temp_reg = E1000_READ_REG(shared, PRC64); + temp_reg = E1000_READ_REG(shared, PRC127); + temp_reg = E1000_READ_REG(shared, PRC255); + temp_reg = E1000_READ_REG(shared, PRC511); + temp_reg = E1000_READ_REG(shared, PRC1023); + temp_reg = E1000_READ_REG(shared, PRC1522); + temp_reg = E1000_READ_REG(shared, GPRC); + temp_reg = E1000_READ_REG(shared, BPRC); + temp_reg = E1000_READ_REG(shared, MPRC); + temp_reg = E1000_READ_REG(shared, GPTC); + temp_reg = E1000_READ_REG(shared, GORCL); + temp_reg = E1000_READ_REG(shared, GORCH); + temp_reg = E1000_READ_REG(shared, GOTCL); + temp_reg = E1000_READ_REG(shared, GOTCH); + temp_reg = E1000_READ_REG(shared, RNBC); + temp_reg = E1000_READ_REG(shared, RUC); + temp_reg = E1000_READ_REG(shared, RFC); + temp_reg = E1000_READ_REG(shared, ROC); + temp_reg = E1000_READ_REG(shared, RJC); + temp_reg = E1000_READ_REG(shared, TORL); + temp_reg = E1000_READ_REG(shared, TORH); + temp_reg = E1000_READ_REG(shared, TOTL); + temp_reg = E1000_READ_REG(shared, TOTH); + temp_reg = E1000_READ_REG(shared, TPR); + temp_reg = E1000_READ_REG(shared, TPT); + temp_reg = E1000_READ_REG(shared, PTC64); + temp_reg = E1000_READ_REG(shared, PTC127); + temp_reg = E1000_READ_REG(shared, PTC255); + temp_reg = E1000_READ_REG(shared, PTC511); + temp_reg = E1000_READ_REG(shared, PTC1023); + temp_reg = E1000_READ_REG(shared, PTC1522); + temp_reg = E1000_READ_REG(shared, MPTC); + temp_reg = E1000_READ_REG(shared, BPTC); + + if(shared->mac_type < e1000_82543) + return; + + temp_reg = E1000_READ_REG(shared, ALGNERRC); + temp_reg = E1000_READ_REG(shared, RXERRC); + temp_reg = E1000_READ_REG(shared, TNCRS); + temp_reg = E1000_READ_REG(shared, CEXTERR); + temp_reg = E1000_READ_REG(shared, TSCTC); + temp_reg = E1000_READ_REG(shared, TSCTFC); + return; +} + +/****************************************************************************** + * Detects the current speed and duplex settings of the hardware. + * + * shared - Struct containing variables accessed by shared code + * speed - Speed of the connection + * duplex - Duplex setting of the connection + *****************************************************************************/ +void +e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared, + uint16_t *speed, + uint16_t *duplex) +{ + uint32_t status_reg; +#if DBG + uint16_t phy_data; +#endif + + DEBUGFUNC("e1000_get_speed_and_duplex"); + + /* If the adapter is stopped we don't have a speed or duplex */ + if(shared->adapter_stopped) { + *speed = 0; + *duplex = 0; + return; + } + + if(shared->mac_type >= e1000_82543) { + status_reg = E1000_READ_REG(shared, STATUS); + if(status_reg & E1000_STATUS_SPEED_1000) { + *speed = SPEED_1000; + DEBUGOUT("1000 Mbs, "); + } else if(status_reg & E1000_STATUS_SPEED_100) { + *speed = SPEED_100; + DEBUGOUT("100 Mbs, "); + } else { + *speed = SPEED_10; + DEBUGOUT("10 Mbs, "); + } + + if(status_reg & E1000_STATUS_FD) { + *duplex = FULL_DUPLEX; + DEBUGOUT("Full Duplex\r\n"); + } else { + *duplex = HALF_DUPLEX; + DEBUGOUT(" Half Duplex\r\n"); + } + } else { + DEBUGOUT("1000 Mbs, Full Duplex\r\n"); + *speed = SPEED_1000; + *duplex = FULL_DUPLEX; + } + +#if DBG + if(shared->phy_id == M88E1000_12_PHY_ID || + shared->phy_id == M88E1000_14_PHY_ID || + shared->phy_id == M88E1000_I_PHY_ID) { + /* read the phy specific status register */ + phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", phy_data); + phy_data = e1000_read_phy_reg(shared, PHY_STATUS); + DEBUGOUT1("Phy MII Status Reg contents = %x\n", phy_data); + DEBUGOUT1("Device Status Reg contents = %x\n", + E1000_READ_REG(shared, STATUS)); + } +#endif + return; +} + +/****************************************************************************** + * Reads a 16 bit word from the EEPROM. + * + * shared - Struct containing variables accessed by shared code + * offset - offset of 16 bit word in the EEPROM to read + *****************************************************************************/ +uint16_t +e1000_read_eeprom(struct e1000_shared_adapter *shared, + uint16_t offset) +{ + uint16_t data; + + /* Prepare the EEPROM for reading */ + e1000_setup_eeprom(shared); + + /* Send the READ command (opcode + addr) */ + e1000_shift_out_bits(shared, EEPROM_READ_OPCODE, 3); + e1000_shift_out_bits(shared, offset, 6); + + /* Read the data */ + data = e1000_shift_in_bits(shared); + + /* End this read operation */ + e1000_standby_eeprom(shared); + + return (data); +} + +/****************************************************************************** + * Verifies that the EEPROM has a valid checksum + * + * shared - Struct containing variables accessed by shared code + * + * Reads the first 64 16 bit words of the EEPROM and sums the values read. + * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is + * valid. + *****************************************************************************/ +boolean_t +e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared) +{ + uint16_t checksum = 0; + uint16_t i; + + for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) + checksum += e1000_read_eeprom(shared, i); + + if(checksum == (uint16_t) EEPROM_SUM) + return (TRUE); + else + return (FALSE); +} +/****************************************************************************** + * Reads the adapter's part number from the EEPROM + * + * shared - Struct containing variables accessed by shared code + * part_num - Adapter's part number + *****************************************************************************/ +boolean_t +e1000_read_part_num(struct e1000_shared_adapter *shared, + uint32_t *part_num) +{ + uint16_t eeprom_word; + + DEBUGFUNC("e1000_read_part_num"); + + /* Don't read the EEPROM if we are stopped */ + if(shared->adapter_stopped) { + *part_num = 0; + return (FALSE); + } + + /* Get word 0 from EEPROM */ + eeprom_word = e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1)); + + DEBUGOUT("Read first part number word\n"); + + /* Save word 0 in upper half is PartNumber */ + *part_num = (uint32_t) eeprom_word; + *part_num = *part_num << 16; + + /* Get word 1 from EEPROM */ + eeprom_word = + e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1 + 1)); + + DEBUGOUT("Read second part number word\n"); + + /* Save word 1 in lower half of PartNumber */ + *part_num |= eeprom_word; + + /* read a valid part number */ + return (TRUE); +} + +void +e1000_read_mac_addr(struct e1000_shared_adapter * shared) +{ + uint16_t temp, x; + + for(x = 0; x < NODE_ADDRESS_SIZE; x += 2) { + temp = e1000_read_eeprom(shared, (uint16_t) + (EEPROM_NODE_ADDRESS_BYTE_0 + (x/2))); + shared->perm_mac_addr[x] = (uint8_t) (temp & 0x00FF); + shared->perm_mac_addr[x+1] = (uint8_t) (temp >> 8); + } + + for(x = 0; x < NODE_ADDRESS_SIZE; x++) + shared->mac_addr[x] = shared->perm_mac_addr[x]; +} + +/****************************************************************************** + * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT + * + * shared - Struct containing variables accessed by shared code + * frame_len - The length of the frame in question + * mac_addr - The Ethernet destination address of the frame in question + *****************************************************************************/ +uint32_t +e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared, + struct e1000_shared_stats *stats, + uint32_t frame_len, + uint8_t *mac_addr) +{ + uint64_t carry_bit; + + /* First adjust the frame length. */ + frame_len--; + /* We need to adjust the statistics counters, since the hardware + * counters overcount this packet as a CRC error and undercount + * the packet as a good packet + */ + /* This packet should not be counted as a CRC error. */ + stats->crcerrs--; + /* This packet does count as a Good Packet Received. */ + stats->gprc++; + + /* Adjust the Good Octets received counters */ + carry_bit = 0x80000000 & stats->gorcl; + stats->gorcl += frame_len; + /* If the high bit of Gorcl (the low 32 bits of the Good Octets + * Received Count) was one before the addition, + * AND it is zero after, then we lost the carry out, + * need to add one to Gorch (Good Octets Received Count High). + * This could be simplified if all environments supported + * 64-bit integers. + */ + if(carry_bit && ((stats->gorcl & 0x80000000) == 0)) + stats->gorch++; + /* Is this a broadcast or multicast? Check broadcast first, + * since the test for a multicast frame will test positive on + * a broadcast frame. + */ + if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff)) + /* Broadcast packet */ + stats->bprc++; + else if(*mac_addr & 0x01) + /* Multicast packet */ + stats->mprc++; + + if(frame_len == shared->max_frame_size) { + /* In this case, the hardware has overcounted the number of + * oversize frames. + */ + if(stats->roc > 0) + stats->roc--; + } + + /* Adjust the bin counters when the extra byte put the frame in the + * wrong bin. Remember that the frame_len was adjusted above. + */ + if(frame_len == 64) { + stats->prc64++; + stats->prc127--; + } else if(frame_len == 127) { + stats->prc127++; + stats->prc255--; + } else if(frame_len == 255) { + stats->prc255++; + stats->prc511--; + } else if(frame_len == 511) { + stats->prc511++; + stats->prc1023--; + } else if(frame_len == 1023) { + stats->prc1023++; + stats->prc1522--; + } else if(frame_len == 1522) { + stats->prc1522++; + } + return frame_len; +} + +/****************************************************************************** + * Gets the current PCI bus type, speed, and width of the hardware + * + * shared - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_get_bus_info(struct e1000_shared_adapter *shared) +{ + uint32_t status_reg; + + if(shared->mac_type < e1000_82543) { + shared->bus_type = e1000_bus_type_unknown; + shared->bus_speed = e1000_bus_speed_unknown; + shared->bus_width = e1000_bus_width_unknown; + return; + } + + status_reg = E1000_READ_REG(shared, STATUS); + + shared->bus_type = (status_reg & E1000_STATUS_PCIX_MODE) ? + e1000_bus_type_pcix : e1000_bus_type_pci; + + if(shared->bus_type == e1000_bus_type_pci) { + shared->bus_speed = (status_reg & E1000_STATUS_PCI66) ? + e1000_bus_speed_66 : e1000_bus_speed_33; + } else { + switch (status_reg & E1000_STATUS_PCIX_SPEED) { + case E1000_STATUS_PCIX_SPEED_66: + shared->bus_speed = e1000_bus_speed_66; + break; + case E1000_STATUS_PCIX_SPEED_100: + shared->bus_speed = e1000_bus_speed_100; + break; + case E1000_STATUS_PCIX_SPEED_133: + shared->bus_speed = e1000_bus_speed_133; + break; + default: + shared->bus_speed = e1000_bus_speed_reserved; + break; + } + } + + shared->bus_width = (status_reg & E1000_STATUS_BUS64) ? + e1000_bus_width_64 : e1000_bus_width_32; + + return; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/e1000/e1000_mac.h linux-2.5/drivers/net/e1000/e1000_mac.h --- linux-2.5.5/drivers/net/e1000/e1000_mac.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/e1000/e1000_mac.h Tue Feb 26 21:24:49 2002 @@ -0,0 +1,1383 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* e1000_mac.h + * Structures, enums, and macros for the MAC + */ + +#ifndef _E1000_MAC_H_ +#define _E1000_MAC_H_ + +#include "e1000_osdep.h" + +/* Forward declarations of structures used by the shared code */ +struct e1000_shared_adapter; +struct e1000_shared_stats; + +/* Enumerated types specific to the e1000 hardware */ +/* Media Access Controlers */ +typedef enum { + e1000_82542_rev2_0 = 0, + e1000_82542_rev2_1, + e1000_82543, + e1000_82544, + e1000_num_macs +} e1000_mac_type; + +/* Media Types */ +typedef enum { + e1000_media_type_copper = 0, + e1000_media_type_fiber = 1, + e1000_num_media_types +} e1000_media_type; + +typedef enum { + e1000_10_half = 0, + e1000_10_full = 1, + e1000_100_half = 2, + e1000_100_full = 3 +} e1000_speed_duplex_type; + +/* Flow Control Settings */ +typedef enum { + e1000_fc_none = 0, + e1000_fc_rx_pause = 1, + e1000_fc_tx_pause = 2, + e1000_fc_full = 3, + e1000_fc_default = 0xFF +} e1000_fc_type; + +/* PCI bus types */ +typedef enum { + e1000_bus_type_unknown = 0, + e1000_bus_type_pci, + e1000_bus_type_pcix +} e1000_bus_type; + +/* PCI bus speeds */ +typedef enum { + e1000_bus_speed_unknown = 0, + e1000_bus_speed_33, + e1000_bus_speed_66, + e1000_bus_speed_100, + e1000_bus_speed_133, + e1000_bus_speed_reserved +} e1000_bus_speed; + +/* PCI bus widths */ +typedef enum { + e1000_bus_width_unknown = 0, + e1000_bus_width_32, + e1000_bus_width_64 +} e1000_bus_width; + + + +/* Function prototypes */ +/* Setup */ +void e1000_adapter_stop(struct e1000_shared_adapter *shared); +boolean_t e1000_init_hw(struct e1000_shared_adapter *shared); +void e1000_init_rx_addrs(struct e1000_shared_adapter *shared); + +/* Filters (multicast, vlan, receive) */ +void e1000_mc_addr_list_update(struct e1000_shared_adapter *shared, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad); +uint32_t e1000_hash_mc_addr(struct e1000_shared_adapter *shared, uint8_t * mc_addr); +void e1000_mta_set(struct e1000_shared_adapter *shared, uint32_t hash_value); +void e1000_rar_set(struct e1000_shared_adapter *shared, uint8_t * mc_addr, uint32_t rar_index); +void e1000_write_vfta(struct e1000_shared_adapter *shared, uint32_t offset, uint32_t value); +void e1000_clear_vfta(struct e1000_shared_adapter *shared); + +/* Link layer setup functions */ +boolean_t e1000_setup_fc_and_link(struct e1000_shared_adapter *shared); +boolean_t e1000_setup_pcs_link(struct e1000_shared_adapter *shared, uint32_t dev_ctrl_reg); +void e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared); +void e1000_check_for_link(struct e1000_shared_adapter *shared); +void e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared, uint16_t * speed, uint16_t * duplex); + +/* EEPROM Functions */ +uint16_t e1000_read_eeprom(struct e1000_shared_adapter *shared, uint16_t reg); +boolean_t e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared); + +/* Everything else */ +void e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared); +boolean_t e1000_read_part_num(struct e1000_shared_adapter *shared, uint32_t * part_num); +void e1000_read_mac_addr(struct e1000_shared_adapter * shared); +void e1000_get_bus_info(struct e1000_shared_adapter *shared); +uint32_t e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared, struct e1000_shared_stats *stats, uint32_t frame_len, uint8_t * mac_addr); +void e1000_write_pci_cfg(struct e1000_shared_adapter *shared, uint32_t reg, uint16_t * value); + +/* PCI Device IDs */ +#define E1000_DEV_ID_82542 0x1000 +#define E1000_DEV_ID_82543GC_FIBER 0x1001 +#define E1000_DEV_ID_82543GC_COPPER 0x1004 +#define E1000_DEV_ID_82544EI_COPPER 0x1008 +#define E1000_DEV_ID_82544EI_FIBER 0x1009 +#define E1000_DEV_ID_82544GC_COPPER 0x100C +#define E1000_DEV_ID_82544GC_LOM 0x100D +#define NUM_DEV_IDS 7 + +#define NODE_ADDRESS_SIZE 6 +#define ETH_LENGTH_OF_ADDRESS 6 + +/* MAC decode size is 128K - This is the size of BAR0 */ +#define MAC_DECODE_SIZE (128 * 1024) + +#define E1000_82542_2_0_REV_ID 2 +#define E1000_82542_2_1_REV_ID 3 + +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + +/* The sizes (in bytes) of a ethernet packet */ +#define ENET_HEADER_SIZE 14 +#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 /* Without FCS */ +#define MINIMUM_ETHERNET_PACKET_SIZE 60 /* Without FCS */ +#define CRC_LENGTH 4 +#define MAX_JUMBO_FRAME_SIZE 0x3F00 + + +/* 802.1q VLAN Packet Sizes */ +#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMAed) */ + +/* Ethertype field values */ +#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */ +#define ETHERNET_IP_TYPE 0x0800 /* IP packets */ +#define ETHERNET_ARP_TYPE 0x0806 /* Address Resolution Protocol (ARP) */ + +/* Packet Header defines */ +#define IP_PROTOCOL_TCP 6 +#define IP_PROTOCOL_UDP 0x11 + +/* This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: + * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) + * o RXSEQ = Receive Sequence Error + */ +#define POLL_IMS_ENABLE_MASK ( \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ) + +/* This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: + * o RXT0 = Receiver Timer Interrupt (ring 0) + * o TXDW = Transmit Descriptor Written Back + * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) + * o RXSEQ = Receive Sequence Error + * o LSC = Link Status Change + */ +#define IMS_ENABLE_MASK ( \ + E1000_IMS_RXT0 | \ + E1000_IMS_TXDW | \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ | \ + E1000_IMS_LSC) + +/* The number of high/low register pairs in the RAR. The RAR (Receive Address + * Registers) holds the directed and multicast addresses that we monitor. We + * reserve one of these spots for our directed address, allowing us room for + * E1000_RAR_ENTRIES - 1 multicast addresses. + */ +#define E1000_RAR_ENTRIES 16 + +#define MIN_NUMBER_OF_DESCRIPTORS 8 +#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8 + +/* Receive Descriptor */ +struct e1000_rx_desc { + uint64_t buffer_addr; /* Address of the descriptor's data buffer */ + uint16_t length; /* Length of data DMAed into data buffer */ + uint16_t csum; /* Packet checksum */ + uint8_t status; /* Descriptor status */ + uint8_t errors; /* Descriptor Errors */ + uint16_t special; +}; + +/* Receive Decriptor bit definitions */ +#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ +#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ +#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ +#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ +#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */ +#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ +#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ +#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ +#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ +#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ +#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */ +#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ +#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ +#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ +#define E1000_RXD_SPC_PRI_SHIFT 0x000D /* Priority is in upper 3 of 16 */ +#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ +#define E1000_RXD_SPC_CFI_SHIFT 0x000C /* CFI is bit 12 */ + +/* mask to determine if packets should be dropped due to frame errors */ +#define E1000_RXD_ERR_FRAME_ERR_MASK ( \ + E1000_RXD_ERR_CE | \ + E1000_RXD_ERR_SE | \ + E1000_RXD_ERR_SEQ | \ + E1000_RXD_ERR_CXE | \ + E1000_RXD_ERR_RXE) + +/* Transmit Descriptor */ +struct e1000_tx_desc { + uint64_t buffer_addr; /* Address of the descriptor's data buffer */ + union { + uint32_t data; + struct { + uint16_t length; /* Data buffer length */ + uint8_t cso; /* Checksum offset */ + uint8_t cmd; /* Descriptor control */ + } flags; + } lower; + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t css; /* Checksum start */ + uint16_t special; + } fields; + } upper; +}; + +/* Transmit Descriptor bit definitions */ +#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ +#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */ +#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ +#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ +#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ +#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ +#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ +#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ +#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ +#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ +#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ +#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ +#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ +#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ +#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ + +/* Offload Context Descriptor */ +struct e1000_context_desc { + union { + uint32_t ip_config; + struct { + uint8_t ipcss; /* IP checksum start */ + uint8_t ipcso; /* IP checksum offset */ + uint16_t ipcse; /* IP checksum end */ + } ip_fields; + } lower_setup; + union { + uint32_t tcp_config; + struct { + uint8_t tucss; /* TCP checksum start */ + uint8_t tucso; /* TCP checksum offset */ + uint16_t tucse; /* TCP checksum end */ + } tcp_fields; + } upper_setup; + uint32_t cmd_and_length; /* */ + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t hdr_len; /* Header length */ + uint16_t mss; /* Maximum segment size */ + } fields; + } tcp_seg_setup; +}; + +/* Offload data descriptor */ +struct e1000_data_desc { + uint64_t buffer_addr; /* Address of the descriptor's buffer address */ + union { + uint32_t data; + struct { + uint16_t length; /* Data buffer length */ + uint8_t typ_len_ext; /* */ + uint8_t cmd; /* */ + } flags; + } lower; + union { + uint32_t data; + struct { + uint8_t status; /* Descriptor status */ + uint8_t popts; /* Packet Options */ + uint16_t special; /* */ + } fields; + } upper; +}; + +/* Filters */ +#define E1000_NUM_UNICAST 16 /* Unicast filter entries */ +#define E1000_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */ +#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ + + +/* Receive Address Register */ +struct e1000_rar { + volatile uint32_t low; /* receive address low */ + volatile uint32_t high; /* receive address high */ +}; + +/* The number of entries in the Multicast Table Array (MTA). */ +#define E1000_NUM_MTA_REGISTERS 128 + +/* IPv4 Address Table Entry */ +struct e1000_ipv4_at_entry { + volatile uint32_t ipv4_addr; /* IP Address (RW) */ + volatile uint32_t reserved; +}; + +/* Four wakeup IP addresses are supported */ +#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4 +#define E1000_IP4AT_SIZE E1000_WAKEUP_IP_ADDRESS_COUNT_MAX +#define E1000_IP6AT_SIZE 1 + +/* IPv6 Address Table Entry */ +struct e1000_ipv6_at_entry { + volatile uint8_t ipv6_addr[16]; +}; + +/* Flexible Filter Length Table Entry */ +struct e1000_fflt_entry { + volatile uint32_t length; /* Flexible Filter Length (RW) */ + volatile uint32_t reserved; +}; + +/* Flexible Filter Mask Table Entry */ +struct e1000_ffmt_entry { + volatile uint32_t mask; /* Flexible Filter Mask (RW) */ + volatile uint32_t reserved; +}; + +/* Flexible Filter Value Table Entry */ +struct e1000_ffvt_entry { + volatile uint32_t value; /* Flexible Filter Value (RW) */ + volatile uint32_t reserved; +}; + +/* Four Flexible Filters are supported */ +#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4 + +/* Each Flexible Filter is at most 128 (0x80) bytes in length */ +#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128 + +#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX +#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX +#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX + +/* Register Set. (82543, 82544) + * + * Registers are defined to be 32 bits and should be accessed as 32 bit values. + * These registers are physically located on the NIC, but are mapped into the + * host memory address space. + * + * RW - register is both readable and writable + * RO - register is read only + * WO - register is write only + * R/clr - register is read only and is cleared when read + * A - register array + */ +#define E1000_CTRL 0x00000 /* Device Control - RW */ +#define E1000_STATUS 0x00008 /* Device Status - RO */ +#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ +#define E1000_EERD 0x00014 /* EEPROM Read - RW */ +#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ +#define E1000_MDIC 0x00020 /* MDI Control - RW */ +#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ +#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ +#define E1000_FCT 0x00030 /* Flow Control Type - RW */ +#define E1000_VET 0x00038 /* VLAN Ether Type - RW */ +#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ +#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ +#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ +#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ +#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ +#define E1000_RCTL 0x00100 /* RX Control - RW */ +#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ +#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ +#define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ +#define E1000_TCTL 0x00400 /* TX Control - RW */ +#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */ +#define E1000_TBT 0x00448 /* TX Burst Timer - RW */ +#define E1000_LEDCTL 0x00E00 /* LED Control - RW */ +#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ +#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ +#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ +#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */ +#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */ +#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */ +#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */ +#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */ +#define E1000_RDTR 0x02820 /* RX Delay Timer - RW */ +#define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */ +#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ +#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ +#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ +#define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */ +#define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */ +#define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */ +#define E1000_TDH 0x03810 /* TX Descriptor Head - RW */ +#define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */ +#define E1000_TIDV 0x03820 /* TX Interrupt Delay Value - RW */ +#define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */ +#define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */ +#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ +#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ +#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ +#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ +#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */ +#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */ +#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */ +#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */ +#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */ +#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */ +#define E1000_COLC 0x04028 /* Collision Count - R/clr */ +#define E1000_DC 0x04030 /* Defer Count - R/clr */ +#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */ +#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */ +#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ +#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */ +#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */ +#define E1000_XONTXC 0x0404C /* XON TX Count - R/clr */ +#define E1000_XOFFRXC 0x04050 /* XOFF RX Count - R/clr */ +#define E1000_XOFFTXC 0x04054 /* XOFF TX Count - R/clr */ +#define E1000_FCRUC 0x04058 /* Flow Control RX Unsupported Count- R/clr */ +#define E1000_PRC64 0x0405C /* Packets RX (64 bytes) - R/clr */ +#define E1000_PRC127 0x04060 /* Packets RX (65-127 bytes) - R/clr */ +#define E1000_PRC255 0x04064 /* Packets RX (128-255 bytes) - R/clr */ +#define E1000_PRC511 0x04068 /* Packets RX (255-511 bytes) - R/clr */ +#define E1000_PRC1023 0x0406C /* Packets RX (512-1023 bytes) - R/clr */ +#define E1000_PRC1522 0x04070 /* Packets RX (1024-1522 bytes) - R/clr */ +#define E1000_GPRC 0x04074 /* Good Packets RX Count - R/clr */ +#define E1000_BPRC 0x04078 /* Broadcast Packets RX Count - R/clr */ +#define E1000_MPRC 0x0407C /* Multicast Packets RX Count - R/clr */ +#define E1000_GPTC 0x04080 /* Good Packets TX Count - R/clr */ +#define E1000_GORCL 0x04088 /* Good Octets RX Count Low - R/clr */ +#define E1000_GORCH 0x0408C /* Good Octets RX Count High - R/clr */ +#define E1000_GOTCL 0x04090 /* Good Octets TX Count Low - R/clr */ +#define E1000_GOTCH 0x04094 /* Good Octets TX Count High - R/clr */ +#define E1000_RNBC 0x040A0 /* RX No Buffers Count - R/clr */ +#define E1000_RUC 0x040A4 /* RX Undersize Count - R/clr */ +#define E1000_RFC 0x040A8 /* RX Fragment Count - R/clr */ +#define E1000_ROC 0x040AC /* RX Oversize Count - R/clr */ +#define E1000_RJC 0x040B0 /* RX Jabber Count - R/clr */ +#define E1000_MGTPRC 0x040B4 /* Management Packets RX Count - R/clr */ +#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */ +#define E1000_MGTPTC 0x040BC /* Management Packets TX Count - R/clr */ +#define E1000_TORL 0x040C0 /* Total Octets RX Low - R/clr */ +#define E1000_TORH 0x040C4 /* Total Octets RX High - R/clr */ +#define E1000_TOTL 0x040C8 /* Total Octets TX Low - R/clr */ +#define E1000_TOTH 0x040CC /* Total Octets TX High - R/clr */ +#define E1000_TPR 0x040D0 /* Total Packets RX - R/clr */ +#define E1000_TPT 0x040D4 /* Total Packets TX - R/clr */ +#define E1000_PTC64 0x040D8 /* Packets TX (64 bytes) - R/clr */ +#define E1000_PTC127 0x040DC /* Packets TX (65-127 bytes) - R/clr */ +#define E1000_PTC255 0x040E0 /* Packets TX (128-255 bytes) - R/clr */ +#define E1000_PTC511 0x040E4 /* Packets TX (256-511 bytes) - R/clr */ +#define E1000_PTC1023 0x040E8 /* Packets TX (512-1023 bytes) - R/clr */ +#define E1000_PTC1522 0x040EC /* Packets TX (1024-1522 Bytes) - R/clr */ +#define E1000_MPTC 0x040F0 /* Multicast Packets TX Count - R/clr */ +#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */ +#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */ +#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */ +#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ +#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ +#define E1000_RA 0x05400 /* Receive Address - RW Array */ +#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ +#define E1000_WUC 0x05800 /* Wakeup Control - RW */ +#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ +#define E1000_WUS 0x05810 /* Wakeup Status - RO */ +#define E1000_MANC 0x05820 /* Management Control - RW */ +#define E1000_IPAV 0x05838 /* IP Address Valid - RW */ +#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */ +#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */ +#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ +#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ +#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ +#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ +#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ + +/* Register Set (82542) + * + * Some of the 82542 registers are located at different offsets than they are + * in more current versions of the 8254x. Despite the difference in location, + * the registers function in the same manner. + */ +#define E1000_82542_CTRL E1000_CTRL +#define E1000_82542_STATUS E1000_STATUS +#define E1000_82542_EECD E1000_EECD +#define E1000_82542_EERD E1000_EERD +#define E1000_82542_CTRL_EXT E1000_CTRL_EXT +#define E1000_82542_MDIC E1000_MDIC +#define E1000_82542_FCAL E1000_FCAL +#define E1000_82542_FCAH E1000_FCAH +#define E1000_82542_FCT E1000_FCT +#define E1000_82542_VET E1000_VET +#define E1000_82542_RA 0x00040 +#define E1000_82542_ICR E1000_ICR +#define E1000_82542_ITR E1000_ITR +#define E1000_82542_ICS E1000_ICS +#define E1000_82542_IMS E1000_IMS +#define E1000_82542_IMC E1000_IMC +#define E1000_82542_RCTL E1000_RCTL +#define E1000_82542_RDTR 0x00108 +#define E1000_82542_RDBAL 0x00110 +#define E1000_82542_RDBAH 0x00114 +#define E1000_82542_RDLEN 0x00118 +#define E1000_82542_RDH 0x00120 +#define E1000_82542_RDT 0x00128 +#define E1000_82542_FCRTH 0x00160 +#define E1000_82542_FCRTL 0x00168 +#define E1000_82542_FCTTV E1000_FCTTV +#define E1000_82542_TXCW E1000_TXCW +#define E1000_82542_RXCW E1000_RXCW +#define E1000_82542_MTA 0x00200 +#define E1000_82542_TCTL E1000_TCTL +#define E1000_82542_TIPG E1000_TIPG +#define E1000_82542_TDBAL 0x00420 +#define E1000_82542_TDBAH 0x00424 +#define E1000_82542_TDLEN 0x00428 +#define E1000_82542_TDH 0x00430 +#define E1000_82542_TDT 0x00438 +#define E1000_82542_TIDV 0x00440 +#define E1000_82542_TBT E1000_TBT +#define E1000_82542_VFTA 0x00600 +#define E1000_82542_LEDCTL E1000_LEDCTL +#define E1000_82542_PBA E1000_PBA +#define E1000_82542_RXDCTL E1000_RXDCTL +#define E1000_82542_RADV E1000_RADV +#define E1000_82542_RSRPD E1000_RSRPD +#define E1000_82542_TXDMAC E1000_TXDMAC +#define E1000_82542_TXDCTL E1000_TXDCTL +#define E1000_82542_TADV E1000_TADV +#define E1000_82542_TSPMT E1000_TSPMT +#define E1000_82542_CRCERRS E1000_CRCERRS +#define E1000_82542_ALGNERRC E1000_ALGNERRC +#define E1000_82542_SYMERRS E1000_SYMERRS +#define E1000_82542_RXERRC E1000_RXERRC +#define E1000_82542_MPC E1000_MPC +#define E1000_82542_SCC E1000_SCC +#define E1000_82542_ECOL E1000_ECOL +#define E1000_82542_MCC E1000_MCC +#define E1000_82542_LATECOL E1000_LATECOL +#define E1000_82542_COLC E1000_COLC +#define E1000_82542_DC E1000_DC +#define E1000_82542_TNCRS E1000_TNCRS +#define E1000_82542_SEC E1000_SEC +#define E1000_82542_CEXTERR E1000_CEXTERR +#define E1000_82542_RLEC E1000_RLEC +#define E1000_82542_XONRXC E1000_XONRXC +#define E1000_82542_XONTXC E1000_XONTXC +#define E1000_82542_XOFFRXC E1000_XOFFRXC +#define E1000_82542_XOFFTXC E1000_XOFFTXC +#define E1000_82542_FCRUC E1000_FCRUC +#define E1000_82542_PRC64 E1000_PRC64 +#define E1000_82542_PRC127 E1000_PRC127 +#define E1000_82542_PRC255 E1000_PRC255 +#define E1000_82542_PRC511 E1000_PRC511 +#define E1000_82542_PRC1023 E1000_PRC1023 +#define E1000_82542_PRC1522 E1000_PRC1522 +#define E1000_82542_GPRC E1000_GPRC +#define E1000_82542_BPRC E1000_BPRC +#define E1000_82542_MPRC E1000_MPRC +#define E1000_82542_GPTC E1000_GPTC +#define E1000_82542_GORCL E1000_GORCL +#define E1000_82542_GORCH E1000_GORCH +#define E1000_82542_GOTCL E1000_GOTCL +#define E1000_82542_GOTCH E1000_GOTCH +#define E1000_82542_RNBC E1000_RNBC +#define E1000_82542_RUC E1000_RUC +#define E1000_82542_RFC E1000_RFC +#define E1000_82542_ROC E1000_ROC +#define E1000_82542_RJC E1000_RJC +#define E1000_82542_MGTPRC E1000_MGTPRC +#define E1000_82542_MGTPDC E1000_MGTPDC +#define E1000_82542_MGTPTC E1000_MGTPTC +#define E1000_82542_TORL E1000_TORL +#define E1000_82542_TORH E1000_TORH +#define E1000_82542_TOTL E1000_TOTL +#define E1000_82542_TOTH E1000_TOTH +#define E1000_82542_TPR E1000_TPR +#define E1000_82542_TPT E1000_TPT +#define E1000_82542_PTC64 E1000_PTC64 +#define E1000_82542_PTC127 E1000_PTC127 +#define E1000_82542_PTC255 E1000_PTC255 +#define E1000_82542_PTC511 E1000_PTC511 +#define E1000_82542_PTC1023 E1000_PTC1023 +#define E1000_82542_PTC1522 E1000_PTC1522 +#define E1000_82542_MPTC E1000_MPTC +#define E1000_82542_BPTC E1000_BPTC +#define E1000_82542_TSCTC E1000_TSCTC +#define E1000_82542_TSCTFC E1000_TSCTFC +#define E1000_82542_RXCSUM E1000_RXCSUM +#define E1000_82542_WUC E1000_WUC +#define E1000_82542_WUFC E1000_WUFC +#define E1000_82542_WUS E1000_WUS +#define E1000_82542_MANC E1000_MANC +#define E1000_82542_IPAV E1000_IPAV +#define E1000_82542_IP4AT E1000_IP4AT +#define E1000_82542_IP6AT E1000_IP6AT +#define E1000_82542_WUPL E1000_WUPL +#define E1000_82542_WUPM E1000_WUPM +#define E1000_82542_FFLT E1000_FFLT +#define E1000_82542_FFMT E1000_FFMT +#define E1000_82542_FFVT E1000_FFVT + +/* Statistics counters collected by the MAC */ +struct e1000_shared_stats { + uint64_t crcerrs; + uint64_t algnerrc; + uint64_t symerrs; + uint64_t rxerrc; + uint64_t mpc; + uint64_t scc; + uint64_t ecol; + uint64_t mcc; + uint64_t latecol; + uint64_t colc; + uint64_t dc; + uint64_t tncrs; + uint64_t sec; + uint64_t cexterr; + uint64_t rlec; + uint64_t xonrxc; + uint64_t xontxc; + uint64_t xoffrxc; + uint64_t xofftxc; + uint64_t fcruc; + uint64_t prc64; + uint64_t prc127; + uint64_t prc255; + uint64_t prc511; + uint64_t prc1023; + uint64_t prc1522; + uint64_t gprc; + uint64_t bprc; + uint64_t mprc; + uint64_t gptc; + uint64_t gorcl; + uint64_t gorch; + uint64_t gotcl; + uint64_t gotch; + uint64_t rnbc; + uint64_t ruc; + uint64_t rfc; + uint64_t roc; + uint64_t rjc; + uint64_t mgprc; + uint64_t mgpdc; + uint64_t mgptc; + uint64_t torl; + uint64_t torh; + uint64_t totl; + uint64_t toth; + uint64_t tpr; + uint64_t tpt; + uint64_t ptc64; + uint64_t ptc127; + uint64_t ptc255; + uint64_t ptc511; + uint64_t ptc1023; + uint64_t ptc1522; + uint64_t mptc; + uint64_t bptc; + uint64_t tsctc; + uint64_t tsctfc; +}; + +/* Structure containing variables used by the shared code (e1000_mac.c and + * e1000_phy.c) + */ +struct e1000_shared_adapter { + uint8_t *hw_addr; + e1000_mac_type mac_type; + e1000_media_type media_type; + void *back; + e1000_fc_type fc; + e1000_bus_speed bus_speed; + e1000_bus_width bus_width; + e1000_bus_type bus_type; + uint32_t phy_id; + uint32_t phy_addr; + uint32_t original_fc; + uint32_t txcw_reg; + uint32_t autoneg_failed; + uint32_t max_frame_size; + uint32_t min_frame_size; + uint32_t mc_filter_type; + uint32_t num_mc_addrs; + uint16_t autoneg_advertised; + uint16_t pci_cmd_word; + uint16_t fc_high_water; + uint16_t fc_low_water; + uint16_t fc_pause_time; + uint16_t device_id; + uint16_t vendor_id; + uint16_t subsystem_id; + uint16_t subsystem_vendor_id; + uint8_t revision_id; + boolean_t disable_polarity_correction; + boolean_t get_link_status; + boolean_t tbi_compatibility_en; + boolean_t tbi_compatibility_on; + boolean_t adapter_stopped; + boolean_t fc_send_xon; + boolean_t report_tx_early; + uint8_t autoneg; + uint8_t mdix; + uint8_t forced_speed_duplex; + uint8_t wait_autoneg_complete; + uint8_t dma_fairness; + uint8_t mac_addr[NODE_ADDRESS_SIZE]; + uint8_t perm_mac_addr[NODE_ADDRESS_SIZE]; +}; + + +#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */ +#define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */ + +/* Register Bit Masks */ +/* Device Control */ +#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ +#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ +#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ +#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ +#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ +#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ +#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ +#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ +#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ +#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ +#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ +#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ +#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ +#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ +#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ +#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ +#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ +#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ +#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ +#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ +#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ +#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ +#define E1000_CTRL_RST 0x04000000 /* Global reset */ +#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ +#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ +#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ +#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ +#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ + +/* Device Status */ +#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ +#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ +#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ +#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */ +#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ +#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ +#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */ +#define E1000_STATUS_SPEED_MASK 0x000000C0 +#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ +#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ +#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ +#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ +#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ +#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ +#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ +#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ +#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ + +/* Constants used to intrepret the masked PCI-X bus speed. */ +#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */ +#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */ +#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */ + +/* EEPROM/Flash Control */ +#define E1000_EECD_SK 0x00000001 /* EEPROM Clock */ +#define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */ +#define E1000_EECD_DI 0x00000004 /* EEPROM Data In */ +#define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */ +#define E1000_EECD_FWE_MASK 0x00000030 +#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ +#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ +#define E1000_EECD_FWE_SHIFT 4 +#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */ +#define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */ +#define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */ +#define E1000_EECD_PRES 0x00000100 /* EEPROM Present */ + +/* EEPROM Read */ +#define E1000_EERD_START 0x00000001 /* Start Read */ +#define E1000_EERD_DONE 0x00000010 /* Read Done */ +#define E1000_EERD_ADDR_SHIFT 8 +#define E1000_EERD_ADDR_MASK 0x0000FF00 /* Read Address */ +#define E1000_EERD_DATA_SHIFT 16 +#define E1000_EERD_DATA_MASK 0xFFFF0000 /* Read Data */ + +/* Extended Device Control */ +#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ +#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */ +#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN +#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */ +#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */ +#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */ +#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */ +#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA +#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */ +#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */ +#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */ +#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */ +#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */ +#define E1000_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */ +#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */ +#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ +#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ +#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ +#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 +#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 +#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 +#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000 +#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000 +#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 +#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 +#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 + +/* MDI Control */ +#define E1000_MDIC_DATA_MASK 0x0000FFFF +#define E1000_MDIC_REG_MASK 0x001F0000 +#define E1000_MDIC_REG_SHIFT 16 +#define E1000_MDIC_PHY_MASK 0x03E00000 +#define E1000_MDIC_PHY_SHIFT 21 +#define E1000_MDIC_OP_WRITE 0x04000000 +#define E1000_MDIC_OP_READ 0x08000000 +#define E1000_MDIC_READY 0x10000000 +#define E1000_MDIC_INT_EN 0x20000000 +#define E1000_MDIC_ERROR 0x40000000 + +/* LED Control */ +#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F +#define E1000_LEDCTL_LED0_MODE_SHIFT 0 +#define E1000_LEDCTL_LED0_IVRT 0x00000040 +#define E1000_LEDCTL_LED0_BLINK 0x00000080 +#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00 +#define E1000_LEDCTL_LED1_MODE_SHIFT 8 +#define E1000_LEDCTL_LED1_IVRT 0x00004000 +#define E1000_LEDCTL_LED1_BLINK 0x00008000 +#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000 +#define E1000_LEDCTL_LED2_MODE_SHIFT 16 +#define E1000_LEDCTL_LED2_IVRT 0x00400000 +#define E1000_LEDCTL_LED2_BLINK 0x00800000 +#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 +#define E1000_LEDCTL_LED3_MODE_SHIFT 24 +#define E1000_LEDCTL_LED3_IVRT 0x40000000 +#define E1000_LEDCTL_LED3_BLINK 0x80000000 + +#define E1000_LEDCTL_MODE_LINK_10_1000 0x0 +#define E1000_LEDCTL_MODE_LINK_100_1000 0x1 +#define E1000_LEDCTL_MODE_LINK_UP 0x2 +#define E1000_LEDCTL_MODE_ACTIVITY 0x3 +#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4 +#define E1000_LEDCTL_MODE_LINK_10 0x5 +#define E1000_LEDCTL_MODE_LINK_100 0x6 +#define E1000_LEDCTL_MODE_LINK_1000 0x7 +#define E1000_LEDCTL_MODE_PCIX_MODE 0x8 +#define E1000_LEDCTL_MODE_FULL_DUPLEX 0x9 +#define E1000_LEDCTL_MODE_COLLISION 0xA +#define E1000_LEDCTL_MODE_BUS_SPEED 0xB +#define E1000_LEDCTL_MODE_BUS_SIZE 0xC +#define E1000_LEDCTL_MODE_PAUSED 0xD +#define E1000_LEDCTL_MODE_LED_ON 0xE +#define E1000_LEDCTL_MODE_LED_OFF 0xF + +/* Receive Address */ +#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ + +/* Interrupt Cause Read */ +#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ +#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ +#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ +#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ +#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ +#define E1000_ICR_RXO 0x00000040 /* rx overrun */ +#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ +#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ +#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */ +#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ +#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ +#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ +#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ +#define E1000_ICR_TXD_LOW 0x00008000 +#define E1000_ICR_SRPD 0x00010000 + +/* Interrupt Cause Set */ +#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_ICS_SRPD E1000_ICR_SRPD + +/* Interrupt Mask Set */ +#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_IMS_SRPD E1000_ICR_SRPD + +/* Interrupt Mask Clear */ +#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ +#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */ +#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */ +#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */ +#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ +#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ +#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ +#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ +#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW +#define E1000_IMC_SRPD E1000_ICR_SRPD + +/* Receive Control */ +#define E1000_RCTL_RST 0x00000001 /* Software reset */ +#define E1000_RCTL_EN 0x00000002 /* enable */ +#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ +#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ +#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ +#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ +#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ +#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ +#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ +#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ +#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */ +#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */ +#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ +#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ +#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ +#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ +#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ +#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ +#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ +#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ +#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ +#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ +#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ +#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ +#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ +#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ +#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ +#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ +#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ +#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ +#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ + +/* Receive Descriptor */ +#define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ +#define E1000_RDT_FPDB 0x80000000 /* Flush descriptor block */ +#define E1000_RDLEN_LEN 0x0007ff80 /* descriptor length */ +#define E1000_RDH_RDH 0x0000ffff /* receive descriptor head */ +#define E1000_RDT_RDT 0x0000ffff /* receive descriptor tail */ + +/* Flow Control */ +#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */ +#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */ +#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ +#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ + +/* Receive Descriptor Control */ +#define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */ +#define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */ +#define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */ +#define E1000_RXDCTL_GRAN 0x01000000 /* RXDCTL Granularity */ + +/* Transmit Descriptor Control */ +#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */ +#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */ +#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */ +#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ +#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */ + +/* Transmit Configuration Word */ +#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ +#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */ +#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */ +#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */ +#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */ +#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */ +#define E1000_TXCW_NP 0x00008000 /* TXCW next page */ +#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */ +#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */ +#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */ + +/* Receive Configuration Word */ +#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */ +#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */ +#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */ +#define E1000_RXCW_CC 0x10000000 /* Receive config change */ +#define E1000_RXCW_C 0x20000000 /* Receive config */ +#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ +#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */ + +/* Transmit Control */ +#define E1000_TCTL_RST 0x00000001 /* software reset */ +#define E1000_TCTL_EN 0x00000002 /* enable tx */ +#define E1000_TCTL_BCE 0x00000004 /* busy check enable */ +#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ +#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ +#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ +#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */ +#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ +#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ +#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ + +/* Receive Checksum Control */ +#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */ +#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ +#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ +#define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */ + +/* Definitions for power management and wakeup registers */ +/* Wake Up Control */ +#define E1000_WUC_APME 0x00000001 /* APM Enable */ +#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ +#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ +#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ + +/* Wake Up Filter Control */ +#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ +#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ +#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ +#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ +#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */ +#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */ +#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */ +#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */ +#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */ +#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ +#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */ +#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ +#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ + +/* Wake Up Status */ +#define E1000_WUS_LNKC 0x00000001 /* Link Status Changed */ +#define E1000_WUS_MAG 0x00000002 /* Magic Packet Received */ +#define E1000_WUS_EX 0x00000004 /* Directed Exact Received */ +#define E1000_WUS_MC 0x00000008 /* Directed Multicast Received */ +#define E1000_WUS_BC 0x00000010 /* Broadcast Received */ +#define E1000_WUS_ARP 0x00000020 /* ARP Request Packet Received */ +#define E1000_WUS_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Received */ +#define E1000_WUS_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Received */ +#define E1000_WUS_FLX0 0x00010000 /* Flexible Filter 0 Match */ +#define E1000_WUS_FLX1 0x00020000 /* Flexible Filter 1 Match */ +#define E1000_WUS_FLX2 0x00040000 /* Flexible Filter 2 Match */ +#define E1000_WUS_FLX3 0x00080000 /* Flexible Filter 3 Match */ +#define E1000_WUS_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ + +/* Management Control */ +#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ +#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ +#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */ +#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */ +#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */ +#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */ +#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */ +#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */ +#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ +#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery + * Filtering */ +#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ +#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ +#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ +#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */ +#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */ +#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */ +#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */ +#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */ +#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */ + +#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ +#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ + +/* Wake Up Packet Length */ +#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */ + +#define E1000_MDALIGN 4096 + +/* EEPROM Commands */ +#define EEPROM_READ_OPCODE 0x6 /* EERPOM read opcode */ +#define EEPROM_WRITE_OPCODE 0x5 /* EERPOM write opcode */ +#define EEPROM_ERASE_OPCODE 0x7 /* EERPOM erase opcode */ +#define EEPROM_EWEN_OPCODE 0x13 /* EERPOM erase/write enable */ +#define EEPROM_EWDS_OPCODE 0x10 /* EERPOM erast/write disable */ + +/* EEPROM Word Offsets */ +#define EEPROM_INIT_CONTROL1_REG 0x000A +#define EEPROM_INIT_CONTROL2_REG 0x000F +#define EEPROM_FLASH_VERSION 0x0032 +#define EEPROM_CHECKSUM_REG 0x003F + +/* Mask bits for fields in Word 0x0a of the EEPROM */ +#define EEPROM_WORD0A_ILOS 0x0010 +#define EEPROM_WORD0A_SWDPIO 0x01E0 +#define EEPROM_WORD0A_LRST 0x0200 +#define EEPROM_WORD0A_FD 0x0400 +#define EEPROM_WORD0A_66MHZ 0x0800 + +/* Mask bits for fields in Word 0x0f of the EEPROM */ +#define EEPROM_WORD0F_PAUSE_MASK 0x3000 +#define EEPROM_WORD0F_PAUSE 0x1000 +#define EEPROM_WORD0F_ASM_DIR 0x2000 +#define EEPROM_WORD0F_ANE 0x0800 +#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0 + +/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */ +#define EEPROM_SUM 0xBABA + +/* EEPROM Map defines (WORD OFFSETS)*/ +#define EEPROM_NODE_ADDRESS_BYTE_0 0 +#define EEPROM_PBA_BYTE_1 8 + +/* EEPROM Map Sizes (Byte Counts) */ +#define PBA_SIZE 4 + +/* Collision related configuration parameters */ +#define E1000_COLLISION_THRESHOLD 16 +#define E1000_CT_SHIFT 4 +#define E1000_FDX_COLLISION_DISTANCE 64 +#define E1000_HDX_COLLISION_DISTANCE 64 +#define E1000_GB_HDX_COLLISION_DISTANCE 512 +#define E1000_COLD_SHIFT 12 + +/* The number of Transmit and Receive Descriptors must be a multiple of 8 */ +#define REQ_TX_DESCRIPTOR_MULTIPLE 8 +#define REQ_RX_DESCRIPTOR_MULTIPLE 8 + +/* Default values for the transmit IPG register */ +#define DEFAULT_82542_TIPG_IPGT 10 +#define DEFAULT_82543_TIPG_IPGT_FIBER 9 +#define DEFAULT_82543_TIPG_IPGT_COPPER 8 + +#define E1000_TIPG_IPGT_MASK 0x000003FF +#define E1000_TIPG_IPGR1_MASK 0x000FFC00 +#define E1000_TIPG_IPGR2_MASK 0x3FF00000 + +#define DEFAULT_82542_TIPG_IPGR1 2 +#define DEFAULT_82543_TIPG_IPGR1 8 +#define E1000_TIPG_IPGR1_SHIFT 10 + +#define DEFAULT_82542_TIPG_IPGR2 10 +#define DEFAULT_82543_TIPG_IPGR2 6 +#define E1000_TIPG_IPGR2_SHIFT 20 + +#define E1000_TXDMAC_DPP 0x00000001 + +/* PBA constants */ +#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ +#define E1000_PBA_24K 0x0018 +#define E1000_PBA_40K 0x0028 +#define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */ + +/* Flow Control Constants */ +#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 +#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 +#define FLOW_CONTROL_TYPE 0x8808 + +/* The historical defaults for the flow control values are given below. */ +#define FC_DEFAULT_HI_THRESH (0x8000) /* 32KB */ +#define FC_DEFAULT_LO_THRESH (0x4000) /* 16KB */ +#define FC_DEFAULT_TX_TIMER (0x100) /* ~130 us */ + + +/* The number of bits that we need to shift right to move the "pause" + * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field + * in the TXCW register + */ +#define PAUSE_SHIFT 5 + +/* The number of bits that we need to shift left to move the "SWDPIO" + * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field + * in the CTRL register + */ +#define SWDPIO_SHIFT 17 + +/* The number of bits that we need to shift left to move the "SWDPIO_EXT" + * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The + * Extended CTRL register. + * in the CTRL register + */ +#define SWDPIO__EXT_SHIFT 4 + +/* The number of bits that we need to shift left to move the "ILOS" + * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field + * in the CTRL register + */ +#define ILOS_SHIFT 3 + + +#define RECEIVE_BUFFER_ALIGN_SIZE (256) + +/* The number of milliseconds we wait for auto-negotiation to complete */ +#define LINK_UP_TIMEOUT 500 + +#define E1000_TX_BUFFER_SIZE ((uint32_t)1514) + +/* The carrier extension symbol, as received by the NIC. */ +#define CARRIER_EXTENSION 0x0F + +/* TBI_ACCEPT macro definition: + * + * If Tbi Compatibility mode is turned-on, then we should accept frames with + * receive errors if and only if: + * 1) errors is equal to the CRC error bit. + * 2) The last byte is a Carrier extension (0x0F). + * 3) The frame length (as reported by Hardware) is greater than 64 (60 + * if a VLAN tag was stripped from the frame. + * 4) " " " " " " " <= max_frame_size+1. + * + * This macro requires: + * adapter = a pointer to struct e1000_shared_adapter + * special = the 16 bit special field of the RX descriptor with EOP set + * error = the 8 bit error field of the RX descriptor with EOP set + * length = the sum of all the length fields of the RX descriptors that + * make up the current frame + * last_byte = the last byte of the frame DMAed by the hardware + * max_frame_length = the maximum frame length we want to accept. + * min_frame_length = the minimum frame length we want to accept. + * + * This macro is a conditional that should be used in the interrupt + * handler's Rx processing routine when RxErrors have been detected. + * + * Typical use: + * ... + * if (TBI_ACCEPT) { + * accept_frame = TRUE; + * e1000_tbi_adjust_stats(adapter, MacAddress); + * frame_length--; + * } else { + * accept_frame = FALSE; + * } + * ... + */ + +#define TBI_ACCEPT(adapter, special, errors, length, last_byte) \ + ((adapter)->tbi_compatibility_on && \ + (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \ + ((last_byte) == CARRIER_EXTENSION) && \ + ((length) <= ((adapter)->max_frame_size + 1)) && \ + ((length) > ((special == 0x0000) ? \ + ((adapter)->min_frame_size) : \ + ((adapter)->min_frame_size - VLAN_TAG_SIZE)))) + + +#endif /* _E1000_MAC_H_ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/e1000/e1000_main.c linux-2.5/drivers/net/e1000/e1000_main.c --- linux-2.5.5/drivers/net/e1000/e1000_main.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/e1000/e1000_main.c Fri Mar 1 15:07:38 2002 @@ -0,0 +1,2033 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#define __E1000_MAIN__ +#include "e1000.h" + +char e1000_driver_name[] = "e1000"; + +char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; + +char e1000_driver_version[] = "4.2.4-k2"; + +char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation."; + +/* e1000_pci_tbl - PCI Device ID Table + * + * Private driver_data field (last one) stores an index into e1000_strings + * Wildcard entries (PCI_ANY_ID) should come last + * Last entry must be all 0s + * + * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, + * Class, Class Mask, String Index } + */ +static struct pci_device_id e1000_pci_tbl[] __devinitdata = { + /* Intel(R) PRO/1000 Network Connection */ + {0x8086, 0x1000, 0x8086, 0x1000, 0, 0, 0}, + {0x8086, 0x1001, 0x8086, 0x1003, 0, 0, 0}, + {0x8086, 0x1004, 0x8086, 0x1004, 0, 0, 0}, + {0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0}, + {0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0}, + {0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0}, + /* Compaq Gigabit Ethernet Server Adapter */ + {0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1}, + {0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1}, + {0x8086, 0x1004, 0x0E11, PCI_ANY_ID, 0, 0, 1}, + /* IBM Mobile, Desktop & Server Adapters */ + {0x8086, 0x1000, 0x1014, PCI_ANY_ID, 0, 0, 2}, + {0x8086, 0x1001, 0x1014, PCI_ANY_ID, 0, 0, 2}, + {0x8086, 0x1004, 0x1014, PCI_ANY_ID, 0, 0, 2}, + /* Generic */ + {0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + /* required last entry */ + {0,} +}; + +MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); + +static char *e1000_strings[] = { + "Intel(R) PRO/1000 Network Connection", + "Compaq Gigabit Ethernet Server Adapter", + "IBM Mobile, Desktop & Server Adapters" +}; + +/* Local Function Prototypes */ + +int e1000_up(struct e1000_adapter *adapter); +void e1000_down(struct e1000_adapter *adapter); +static int e1000_init_module(void); +static void e1000_exit_module(void); +static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +static void e1000_remove(struct pci_dev *pdev); +static void e1000_sw_init(struct e1000_adapter *adapter); +static int e1000_open(struct net_device *netdev); +static int e1000_close(struct net_device *netdev); +static int e1000_setup_tx_resources(struct e1000_adapter *adapter); +static int e1000_setup_rx_resources(struct e1000_adapter *adapter); +static void e1000_configure_tx(struct e1000_adapter *adapter); +static void e1000_configure_rx(struct e1000_adapter *adapter); +static void e1000_setup_rctl(struct e1000_adapter *adapter); +static void e1000_clean_tx_ring(struct e1000_adapter *adapter); +static void e1000_clean_rx_ring(struct e1000_adapter *adapter); +static void e1000_free_tx_resources(struct e1000_adapter *adapter); +static void e1000_free_rx_resources(struct e1000_adapter *adapter); +static void e1000_set_multi(struct net_device *netdev); +static void e1000_update_phy_info(unsigned long data); +static void e1000_watchdog(unsigned long data); +static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev); +static void e1000_tx_timeout(struct net_device *dev); +static struct net_device_stats * e1000_get_stats(struct net_device *netdev); +static int e1000_change_mtu(struct net_device *netdev, int new_mtu); +static int e1000_set_mac(struct net_device *netdev, void *p); +static void e1000_update_stats(struct e1000_adapter *adapter); +static inline void e1000_irq_disable(struct e1000_adapter *adapter); +static inline void e1000_irq_enable(struct e1000_adapter *adapter); +static void e1000_intr(int irq, void *data, struct pt_regs *regs); +static void e1000_clean_tx_irq(struct e1000_adapter *adapter); +static void e1000_clean_rx_irq(struct e1000_adapter *adapter); +static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter); +static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); +static void e1000_reset(struct e1000_adapter *adapter); +static void e1000_enter_82542_rst(struct e1000_adapter *adapter); +static void e1000_leave_82542_rst(struct e1000_adapter *adapter); +static inline void e1000_rx_checksum(struct e1000_adapter *adapter, + struct e1000_rx_desc *rx_desc, + struct sk_buff *skb); +void e1000_enable_WOL(struct e1000_adapter *adapter); + +/* Exported from other modules */ + +extern void e1000_check_options(struct e1000_adapter *adapter); +extern void e1000_proc_dev_setup(struct e1000_adapter *adapter); +extern void e1000_proc_dev_free(struct e1000_adapter *adapter); +extern int e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr); + +static struct pci_driver e1000_driver = { + name: e1000_driver_name, + id_table: e1000_pci_tbl, + probe: e1000_probe, + remove: e1000_remove, + /* Power Managment Hooks */ + suspend: NULL, + resume: NULL +}; + +MODULE_AUTHOR("Intel Corporation, "); +MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); +MODULE_LICENSE("Dual BSD/GPL"); + +#ifdef EXPORT_SYMTAB +EXPORT_SYMBOL(e1000_init_module); +EXPORT_SYMBOL(e1000_exit_module); +EXPORT_SYMBOL(e1000_probe); +EXPORT_SYMBOL(e1000_remove); +EXPORT_SYMBOL(e1000_open); +EXPORT_SYMBOL(e1000_close); +EXPORT_SYMBOL(e1000_xmit_frame); +EXPORT_SYMBOL(e1000_intr); +EXPORT_SYMBOL(e1000_set_multi); +EXPORT_SYMBOL(e1000_change_mtu); +EXPORT_SYMBOL(e1000_set_mac); +EXPORT_SYMBOL(e1000_get_stats); +EXPORT_SYMBOL(e1000_watchdog); +EXPORT_SYMBOL(e1000_ioctl); +#endif + +/** + * e1000_init_module - Driver Registration Routine + * + * e1000_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + **/ + +static int __init +e1000_init_module(void) +{ + printk(KERN_INFO "%s - version %s\n", + e1000_driver_string, e1000_driver_version); + + printk(KERN_INFO "%s\n", e1000_copyright); + + return pci_module_init(&e1000_driver); +} + +module_init(e1000_init_module); + +/** + * e1000_exit_module - Driver Exit Cleanup Routine + * + * e1000_exit_module is called just before the driver is removed + * from memory. + **/ + +static void __exit +e1000_exit_module(void) +{ + pci_unregister_driver(&e1000_driver); + + return; +} + +module_exit(e1000_exit_module); + + +int +e1000_up(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + if(request_irq(netdev->irq, &e1000_intr, SA_SHIRQ, + netdev->name, netdev)) + return -1; + + /* hardware has been reset, we need to reload some things */ + + e1000_set_multi(netdev); + + e1000_configure_tx(adapter); + e1000_setup_rctl(adapter); + e1000_configure_rx(adapter); + e1000_alloc_rx_buffers(adapter); + + e1000_clear_hw_cntrs(&adapter->shared); + + mod_timer(&adapter->watchdog_timer, jiffies); + e1000_irq_enable(adapter); + + return 0; +} + +void +e1000_down(struct e1000_adapter *adapter) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + struct net_device *netdev = adapter->netdev; + + e1000_irq_disable(adapter); + free_irq(netdev->irq, netdev); + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_info_timer); + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + /* disable the transmit and receive units */ + + E1000_WRITE_REG(shared, RCTL, 0); + E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP); + + /* delay to allow PCI transactions to complete */ + + msec_delay(10); + + e1000_clean_tx_ring(adapter); + e1000_clean_rx_ring(adapter); + + e1000_reset(adapter); +} + +static void +e1000_reset(struct e1000_adapter *adapter) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + uint32_t ctrl_ext; + + /* Repartition Pba for greater than 9k mtu + * To take effect CTRL.RST is required. + */ + + if(adapter->rx_buffer_len > E1000_RXBUFFER_8192) + E1000_WRITE_REG(shared, PBA, E1000_JUMBO_PBA); + else + E1000_WRITE_REG(shared, PBA, E1000_DEFAULT_PBA); + + /* 82542 2.0 needs MWI disabled while issuing a reset */ + + if(shared->mac_type == e1000_82542_rev2_0) + e1000_enter_82542_rst(adapter); + + /* global reset */ + + E1000_WRITE_REG(shared, CTRL, E1000_CTRL_RST); + msec_delay(10); + + /* EEPROM reload */ + + ctrl_ext = E1000_READ_REG(shared, CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_EE_RST; + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext); + msec_delay(5); + + if(shared->mac_type == e1000_82542_rev2_0) + e1000_leave_82542_rst(adapter); + + shared->tbi_compatibility_on = FALSE; + shared->fc = shared->original_fc; + + e1000_init_hw(shared); + + e1000_enable_WOL(adapter); + + return; +} + +/** + * e1000_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in e1000_pci_tbl + * + * Returns 0 on success, negative on failure + * + * e1000_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + **/ + +static int __devinit +e1000_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct e1000_adapter *adapter; + static int cards_found = 0; + unsigned long mmio_start; + int mmio_len; + int pci_using_dac; + int i; + + if((i = pci_enable_device(pdev))) + return i; + + if(!(i = pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff))) { + pci_using_dac = 1; + } else { + if((i = pci_set_dma_mask(pdev, (u64) 0xffffffff))) { + E1000_ERR("No usable DMA configuration, aborting\n"); + return i; + } + pci_using_dac = 0; + } + + if((i = pci_request_regions(pdev, e1000_driver_name))) + return i; + + pci_set_master(pdev); + + netdev = alloc_etherdev(sizeof(struct e1000_adapter)); + if(!netdev) + goto err_alloc_etherdev; + + SET_MODULE_OWNER(netdev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev->priv; + adapter->netdev = netdev; + adapter->pdev = pdev; + adapter->shared.back = adapter; + + mmio_start = pci_resource_start(pdev, BAR_0); + mmio_len = pci_resource_len(pdev, BAR_0); + + adapter->shared.hw_addr = ioremap(mmio_start, mmio_len); + if(!adapter->shared.hw_addr) + goto err_ioremap; + + netdev->open = &e1000_open; + netdev->stop = &e1000_close; + netdev->hard_start_xmit = &e1000_xmit_frame; + netdev->get_stats = &e1000_get_stats; + netdev->set_multicast_list = &e1000_set_multi; + netdev->set_mac_address = &e1000_set_mac; + netdev->change_mtu = &e1000_change_mtu; + netdev->do_ioctl = &e1000_ioctl; + netdev->tx_timeout = &e1000_tx_timeout; + netdev->watchdog_timeo = HZ; + + netdev->irq = pdev->irq; + netdev->base_addr = mmio_start; + + adapter->bd_number = cards_found; + adapter->id_string = e1000_strings[ent->driver_data]; + + /* setup the private structure */ + + e1000_sw_init(adapter); + + if(adapter->shared.mac_type >= e1000_82543) { + netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM; + } else { + netdev->features = NETIF_F_SG; + } + + if(pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + /* make sure the EEPROM is good */ + + if(!e1000_validate_eeprom_checksum(&adapter->shared)) + goto err_eeprom; + + /* copy the MAC address out of the EEPROM */ + + e1000_read_mac_addr(&adapter->shared); + memcpy(netdev->dev_addr, adapter->shared.mac_addr, netdev->addr_len); + + if(!is_valid_ether_addr(netdev->dev_addr)) + goto err_eeprom; + + e1000_read_part_num(&adapter->shared, &(adapter->part_num)); + e1000_get_bus_info(&adapter->shared); + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &e1000_watchdog; + adapter->watchdog_timer.data = (unsigned long) adapter; + + init_timer(&adapter->phy_info_timer); + adapter->phy_info_timer.function = &e1000_update_phy_info; + adapter->phy_info_timer.data = (unsigned long) adapter; + + register_netdev(netdev); + + /* we're going to reset, so assume we have no link for now */ + + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + printk(KERN_INFO "%s: %s\n", netdev->name, adapter->id_string); + e1000_check_options(adapter); + e1000_proc_dev_setup(adapter); + + /* reset the hardware with the new settings */ + + e1000_reset(adapter); + + cards_found++; + return 0; + +err_eeprom: + iounmap(adapter->shared.hw_addr); +err_ioremap: + pci_release_regions(pdev); + kfree(netdev); +err_alloc_etherdev: + return -ENOMEM; +} + +/** + * e1000_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * e1000_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + * + * This routine is also called to clean up from a failure in + * e1000_probe. The Adapter struct and netdev will always exist, + * all other pointers must be checked for NULL before freeing. + **/ + +static void __devexit +e1000_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev->priv; + + unregister_netdev(netdev); + + e1000_phy_hw_reset(&adapter->shared); + + e1000_proc_dev_free(adapter); + + iounmap(adapter->shared.hw_addr); + pci_release_regions(pdev); + + kfree(netdev); + return; +} + +/** + * e1000_sw_init - Initialize general software structures (struct e1000_adapter) + * @adapter: board private structure to initialize + * + * e1000_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + **/ + +static void __devinit +e1000_sw_init(struct e1000_adapter *adapter) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + + /* PCI config space info */ + + uint16_t *vendor = &shared->vendor_id; + uint16_t *device = &shared->device_id; + uint16_t *subvendor = &shared->subsystem_vendor_id; + uint16_t *subsystem = &shared->subsystem_id; + uint8_t *revision = &shared->revision_id; + + pci_read_config_word(pdev, PCI_VENDOR_ID, vendor); + pci_read_config_word(pdev, PCI_DEVICE_ID, device); + pci_read_config_byte(pdev, PCI_REVISION_ID, revision); + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, subvendor); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, subsystem); + + pci_read_config_word(pdev, PCI_COMMAND, &shared->pci_cmd_word); + + adapter->rx_buffer_len = E1000_RXBUFFER_2048; + shared->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH; + shared->min_frame_size = MINIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH; + + /* identify the MAC */ + + switch (*device) { + case E1000_DEV_ID_82542: + switch (*revision) { + case E1000_82542_2_0_REV_ID: + shared->mac_type = e1000_82542_rev2_0; + break; + case E1000_82542_2_1_REV_ID: + shared->mac_type = e1000_82542_rev2_1; + break; + default: + shared->mac_type = e1000_82542_rev2_0; + E1000_ERR("Could not identify 82542 revision\n"); + } + break; + case E1000_DEV_ID_82543GC_FIBER: + case E1000_DEV_ID_82543GC_COPPER: + shared->mac_type = e1000_82543; + break; + case E1000_DEV_ID_82544EI_COPPER: + case E1000_DEV_ID_82544EI_FIBER: + case E1000_DEV_ID_82544GC_COPPER: + case E1000_DEV_ID_82544GC_LOM: + shared->mac_type = e1000_82544; + break; + default: + /* should never have loaded on this device */ + BUG(); + } + + /* flow control settings */ + + shared->fc_high_water = FC_DEFAULT_HI_THRESH; + shared->fc_low_water = FC_DEFAULT_LO_THRESH; + shared->fc_pause_time = FC_DEFAULT_TX_TIMER; + shared->fc_send_xon = 1; + + /* Media type - copper or fiber */ + + if(shared->mac_type >= e1000_82543) { + uint32_t status = E1000_READ_REG(shared, STATUS); + + if(status & E1000_STATUS_TBIMODE) + shared->media_type = e1000_media_type_fiber; + else + shared->media_type = e1000_media_type_copper; + } else { + shared->media_type = e1000_media_type_fiber; + } + + if(shared->mac_type < e1000_82543) + shared->report_tx_early = 0; + else + shared->report_tx_early = 1; + + shared->wait_autoneg_complete = FALSE; + shared->tbi_compatibility_en = TRUE; + + atomic_set(&adapter->irq_sem, 1); + spin_lock_init(&adapter->stats_lock); +} + +/** + * e1000_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ + +static int +e1000_open(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + + /* allocate transmit descriptors */ + + if(e1000_setup_tx_resources(adapter)) + goto err_setup_tx; + + /* allocate receive descriptors */ + + if(e1000_setup_rx_resources(adapter)) + goto err_setup_rx; + + if(e1000_up(adapter)) + goto err_up; + + return 0; + +err_up: + e1000_free_rx_resources(adapter); +err_setup_rx: + e1000_free_tx_resources(adapter); +err_setup_tx: + e1000_reset(adapter); + + return -EBUSY; +} + +/** + * e1000_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ + +static int +e1000_close(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + + e1000_down(adapter); + + e1000_free_tx_resources(adapter); + e1000_free_rx_resources(adapter); + + return 0; +} + +/** + * e1000_setup_tx_resources - allocate Tx resources (Descriptors) + * @adapter: board private structure + * + * Return 0 on success, negative on failure + * + * e1000_setup_tx_resources allocates all software transmit resources + * and enabled the Tx unit of the MAC. + **/ + +static int +e1000_setup_tx_resources(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *txdr = &adapter->tx_ring; + struct pci_dev *pdev = adapter->pdev; + int size; + + size = sizeof(struct e1000_buffer) * txdr->count; + txdr->buffer_info = kmalloc(size, GFP_KERNEL); + if(!txdr->buffer_info) { + return -ENOMEM; + } + memset(txdr->buffer_info, 0, size); + + /* round up to nearest 4K */ + + txdr->size = txdr->count * sizeof(struct e1000_tx_desc); + E1000_ROUNDUP(txdr->size, 4096); + + txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); + if(!txdr->desc) { + kfree(txdr->buffer_info); + return -ENOMEM; + } + memset(txdr->desc, 0, txdr->size); + + atomic_set(&txdr->unused, txdr->count); + txdr->next_to_use = 0; + txdr->next_to_clean = 0; + + return 0; +} + +/** + * e1000_configure_tx - Configure 8254x Transmit Unit after Reset + * @adapter: board private structure + * + * Configure the Tx unit of the MAC after a reset. + **/ + +static void +e1000_configure_tx(struct e1000_adapter *adapter) +{ + uint64_t tdba = adapter->tx_ring.dma; + uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc); + uint32_t tctl, tipg; + + E1000_WRITE_REG(&adapter->shared, TDBAL, (tdba & 0x00000000FFFFFFFF)); + E1000_WRITE_REG(&adapter->shared, TDBAH, (tdba >> 32)); + + E1000_WRITE_REG(&adapter->shared, TDLEN, tdlen); + + /* Setup the HW Tx Head and Tail descriptor pointers */ + + E1000_WRITE_REG(&adapter->shared, TDH, 0); + E1000_WRITE_REG(&adapter->shared, TDT, 0); + + /* Set the default values for the Tx Inter Packet Gap timer */ + + switch (adapter->shared.mac_type) { + case e1000_82542_rev2_0: + case e1000_82542_rev2_1: + tipg = DEFAULT_82542_TIPG_IPGT; + tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; + tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; + break; + default: + if(adapter->shared.media_type == e1000_media_type_fiber) + tipg = DEFAULT_82543_TIPG_IPGT_FIBER; + else + tipg = DEFAULT_82543_TIPG_IPGT_COPPER; + tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT; + tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT; + } + E1000_WRITE_REG(&adapter->shared, TIPG, tipg); + + /* Set the Tx Interrupt Delay register */ + + E1000_WRITE_REG(&adapter->shared, TIDV, adapter->tx_int_delay); + + /* Program the Transmit Control Register */ + + tctl = E1000_TCTL_PSP | E1000_TCTL_EN | + (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); + + if(adapter->link_duplex == FULL_DUPLEX) { + tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; + } else { + tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT; + } + + E1000_WRITE_REG(&adapter->shared, TCTL, tctl); + + /* Setup Transmit Descriptor Settings for this adapter */ + adapter->txd_cmd = E1000_TXD_CMD_IFCS; + + if(adapter->tx_int_delay > 0) + adapter->txd_cmd |= E1000_TXD_CMD_IDE; + if(adapter->shared.report_tx_early == 1) + adapter->txd_cmd |= E1000_TXD_CMD_RS; + else + adapter->txd_cmd |= E1000_TXD_CMD_RPS; + + return; +} + +/** + * e1000_setup_rx_resources - allocate Rx resources (Descriptors, receive SKBs) + * @adapter: board private structure + * + * Returns 0 on success, negative on failure + * + * e1000_setup_rx_resources allocates all software receive resources + * and network buffers, and enables the Rx unit of the MAC. + **/ + +static int +e1000_setup_rx_resources(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *rxdr = &adapter->rx_ring; + struct pci_dev *pdev = adapter->pdev; + int size; + + size = sizeof(struct e1000_buffer) * rxdr->count; + rxdr->buffer_info = kmalloc(size, GFP_KERNEL); + if(!rxdr->buffer_info) { + return -ENOMEM; + } + memset(rxdr->buffer_info, 0, size); + + /* Round up to nearest 4K */ + + rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc); + E1000_ROUNDUP(rxdr->size, 4096); + + rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); + + if(!rxdr->desc) { + kfree(rxdr->buffer_info); + return -ENOMEM; + } + memset(rxdr->desc, 0, rxdr->size); + + rxdr->next_to_clean = 0; + rxdr->unused_count = rxdr->count; + rxdr->next_to_use = 0; + + return 0; +} + +/** + * e1000_setup_rctl - configure the receive control register + * @adapter: Board private structure + **/ + +static void +e1000_setup_rctl(struct e1000_adapter *adapter) +{ + uint32_t rctl; + + /* Setup the Receive Control Register */ + rctl = E1000_RCTL_EN | E1000_RCTL_BAM | + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (adapter->shared.mc_filter_type << E1000_RCTL_MO_SHIFT); + + if(adapter->shared.tbi_compatibility_on == 1) + rctl |= E1000_RCTL_SBP; + + switch (adapter->rx_buffer_len) { + case E1000_RXBUFFER_2048: + default: + rctl |= E1000_RCTL_SZ_2048; + break; + case E1000_RXBUFFER_4096: + rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + case E1000_RXBUFFER_8192: + rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + case E1000_RXBUFFER_16384: + rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE; + break; + } + + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); +} + +/** + * e1000_configure_rx - Configure 8254x Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Rx unit of the MAC after a reset. + **/ + +static void +e1000_configure_rx(struct e1000_adapter *adapter) +{ + uint64_t rdba = adapter->rx_ring.dma; + uint32_t rdlen = adapter->rx_ring.count * sizeof(struct e1000_rx_desc); + uint32_t rctl; + uint32_t rxcsum; + + /* make sure receives are disabled while setting up the descriptors */ + + rctl = E1000_READ_REG(&adapter->shared, RCTL); + E1000_WRITE_REG(&adapter->shared, RCTL, rctl & ~E1000_RCTL_EN); + + /* set the Receive Delay Timer Register */ + + E1000_WRITE_REG(&adapter->shared, RDTR, + adapter->rx_int_delay | E1000_RDT_FPDB); + + /* Setup the Base and Length of the Rx Descriptor Ring */ + + E1000_WRITE_REG(&adapter->shared, RDBAL, (rdba & 0x00000000FFFFFFFF)); + E1000_WRITE_REG(&adapter->shared, RDBAH, (rdba >> 32)); + + E1000_WRITE_REG(&adapter->shared, RDLEN, rdlen); + + /* Setup the HW Rx Head and Tail Descriptor Pointers */ + E1000_WRITE_REG(&adapter->shared, RDH, 0); + E1000_WRITE_REG(&adapter->shared, RDT, 0); + + /* Enable 82543 Receive Checksum Offload for TCP and UDP */ + if((adapter->shared.mac_type >= e1000_82543) && + (adapter->rx_csum == TRUE)) { + rxcsum = E1000_READ_REG(&adapter->shared, RXCSUM); + rxcsum |= E1000_RXCSUM_TUOFL; + E1000_WRITE_REG(&adapter->shared, RXCSUM, rxcsum); + } + + /* Enable Receives */ + + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); + + return; +} + +/** + * e1000_free_tx_resources - Free Tx Resources + * @adapter: board private structure + * + * Free all transmit software resources + **/ + +static void +e1000_free_tx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + + e1000_clean_tx_ring(adapter); + + kfree(adapter->tx_ring.buffer_info); + adapter->tx_ring.buffer_info = NULL; + + pci_free_consistent(pdev, adapter->tx_ring.size, + adapter->tx_ring.desc, adapter->tx_ring.dma); + + adapter->tx_ring.desc = NULL; + + return; +} + +/** + * e1000_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + **/ + +static void +e1000_clean_tx_ring(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + int i; + + /* Free all the Tx ring sk_buffs */ + + for(i = 0; i < adapter->tx_ring.count; i++) { + if(adapter->tx_ring.buffer_info[i].skb) { + + pci_unmap_page(pdev, + adapter->tx_ring.buffer_info[i].dma, + adapter->tx_ring.buffer_info[i].length, + PCI_DMA_TODEVICE); + + dev_kfree_skb(adapter->tx_ring.buffer_info[i].skb); + + adapter->tx_ring.buffer_info[i].skb = NULL; + } + } + + size = sizeof(struct e1000_buffer) * adapter->tx_ring.count; + memset(adapter->tx_ring.buffer_info, 0, size); + + /* Zero out the descriptor ring */ + + memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size); + + atomic_set(&adapter->tx_ring.unused, adapter->tx_ring.count); + adapter->tx_ring.next_to_use = 0; + adapter->tx_ring.next_to_clean = 0; + + E1000_WRITE_REG(&adapter->shared, TDH, 0); + E1000_WRITE_REG(&adapter->shared, TDT, 0); + + return; +} + +/** + * e1000_free_rx_resources - Free Rx Resources + * @adapter: board private structure + * + * Free all receive software resources + **/ + +static void +e1000_free_rx_resources(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + + e1000_clean_rx_ring(adapter); + + kfree(adapter->rx_ring.buffer_info); + adapter->rx_ring.buffer_info = NULL; + + pci_free_consistent(pdev, adapter->rx_ring.size, + adapter->rx_ring.desc, adapter->rx_ring.dma); + + adapter->rx_ring.desc = NULL; + + return; +} + +/** + * e1000_clean_rx_ring - Free Rx Buffers + * @adapter: board private structure + **/ + +static void +e1000_clean_rx_ring(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + int i; + + /* Free all the Rx ring sk_buffs */ + + for(i = 0; i < adapter->rx_ring.count; i++) { + if(adapter->rx_ring.buffer_info[i].skb) { + + pci_unmap_single(pdev, + adapter->rx_ring.buffer_info[i].dma, + adapter->rx_ring.buffer_info[i].length, + PCI_DMA_FROMDEVICE); + + dev_kfree_skb(adapter->rx_ring.buffer_info[i].skb); + + adapter->rx_ring.buffer_info[i].skb = NULL; + } + } + + size = sizeof(struct e1000_buffer) * adapter->rx_ring.count; + memset(adapter->rx_ring.buffer_info, 0, size); + + /* Zero out the descriptor ring */ + + memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size); + + adapter->rx_ring.unused_count = adapter->rx_ring.count; + adapter->rx_ring.next_to_clean = 0; + adapter->rx_ring.next_to_use = 0; + + E1000_WRITE_REG(&adapter->shared, RDH, 0); + E1000_WRITE_REG(&adapter->shared, RDT, 0); + + return; +} + +/* The 82542 2.0 (revision 2) needs to have the receive unit in reset + * and memory write and invalidate disabled for certain operations + */ +static void +e1000_enter_82542_rst(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct net_device *netdev = adapter->netdev; + uint16_t pci_command_word = adapter->shared.pci_cmd_word; + uint32_t rctl; + + if(pci_command_word & PCI_COMMAND_INVALIDATE) { + pci_command_word &= ~PCI_COMMAND_INVALIDATE; + pci_write_config_word(pdev, PCI_COMMAND, pci_command_word); + } + + rctl = E1000_READ_REG(&adapter->shared, RCTL); + rctl |= E1000_RCTL_RST; + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); + msec_delay(5); + + if(netif_running(netdev)) + e1000_clean_rx_ring(adapter); + return; +} + +static void +e1000_leave_82542_rst(struct e1000_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct net_device *netdev = adapter->netdev; + uint16_t pci_command_word = adapter->shared.pci_cmd_word; + uint32_t rctl; + + rctl = E1000_READ_REG(&adapter->shared, RCTL); + rctl &= ~E1000_RCTL_RST; + E1000_WRITE_REG(&adapter->shared, RCTL, rctl); + msec_delay(5); + + if(pci_command_word & PCI_COMMAND_INVALIDATE) + pci_write_config_word(pdev, PCI_COMMAND, pci_command_word); + + if(netif_running(netdev)) { + e1000_configure_rx(adapter); + e1000_alloc_rx_buffers(adapter); + } + return; +} + +/** + * e1000_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + **/ + +static int +e1000_set_mac(struct net_device *netdev, void *p) +{ + struct e1000_adapter *adapter = netdev->priv; + struct sockaddr *addr = p; + + /* 82542 2.0 needs to be in reset to write receive address registers */ + + if(adapter->shared.mac_type == e1000_82542_rev2_0) + e1000_enter_82542_rst(adapter); + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->shared.mac_addr, addr->sa_data, netdev->addr_len); + + e1000_rar_set(&adapter->shared, adapter->shared.mac_addr, 0); + + if(adapter->shared.mac_type == e1000_82542_rev2_0) + e1000_leave_82542_rst(adapter); + + return 0; +} + +/** + * e1000_set_multi - Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_multi entry point is called whenever the multicast address + * list or the network interface flags are updated. This routine is + * resposible for configuring the hardware for proper multicast, + * promiscuous mode, and all-multi behavior. + **/ + +static void +e1000_set_multi(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + struct e1000_shared_adapter *shared = &adapter->shared; + struct dev_mc_list *mc_ptr; + uint32_t rctl; + uint32_t hash_value; + int i; + + /* Check for Promiscuous and All Multicast modes */ + + rctl = E1000_READ_REG(shared, RCTL); + + if(netdev->flags & IFF_PROMISC) { + rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); + } else if(netdev->flags & IFF_ALLMULTI) { + rctl |= E1000_RCTL_MPE; + rctl &= ~E1000_RCTL_UPE; + } else { + rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); + } + + E1000_WRITE_REG(shared, RCTL, rctl); + + /* 82542 2.0 needs to be in reset to write receive address registers */ + + if(shared->mac_type == e1000_82542_rev2_0) + e1000_enter_82542_rst(adapter); + + /* load the first 15 multicast address into the exact filters 1-15 + * RAR 0 is used for the station MAC adddress + * if there are not 15 addresses, go ahead and clear the filters + */ + mc_ptr = netdev->mc_list; + + for(i = 1; i < E1000_RAR_ENTRIES; i++) { + if(mc_ptr) { + e1000_rar_set(shared, mc_ptr->dmi_addr, i); + mc_ptr = mc_ptr->next; + } else { + E1000_WRITE_REG_ARRAY(shared, RA, i << 1, 0); + E1000_WRITE_REG_ARRAY(shared, RA, (i << 1) + 1, 0); + } + } + + /* clear the old settings from the multicast hash table */ + + for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) + E1000_WRITE_REG_ARRAY(shared, MTA, i, 0); + + /* load any remaining addresses into the hash table */ + + for(; mc_ptr; mc_ptr = mc_ptr->next) { + hash_value = e1000_hash_mc_addr(shared, mc_ptr->dmi_addr); + e1000_mta_set(shared, hash_value); + } + + if(shared->mac_type == e1000_82542_rev2_0) + e1000_leave_82542_rst(adapter); + return; +} + + +/* need to wait a few seconds after link up to get diagnostic information from the phy */ + +static void +e1000_update_phy_info(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + e1000_phy_get_info(&adapter->shared, &adapter->phy_info); + return; +} + +/** + * e1000_watchdog - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + **/ + +static void +e1000_watchdog(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + struct net_device *netdev = adapter->netdev; + + e1000_check_for_link(&adapter->shared); + + if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU) { + if(!netif_carrier_ok(netdev)) { + e1000_get_speed_and_duplex(&adapter->shared, + &adapter->link_speed, + &adapter->link_duplex); + + printk(KERN_INFO + "e1000: %s NIC Link is Up %d Mbps %s\n", + netdev->name, adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? + "Full Duplex" : "Half Duplex"); + + netif_carrier_on(netdev); + adapter->trans_finish = jiffies; + netif_wake_queue(netdev); + mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); + } + } else { + if(netif_carrier_ok(netdev)) { + adapter->link_speed = 0; + adapter->link_duplex = 0; + printk(KERN_INFO + "e1000: %s NIC Link is Down\n", + netdev->name); + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + } + + e1000_update_stats(adapter); + + /* Reset the timer */ + mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); + + return; +} + +/** + * e1000_xmit_frame - Transmit entry point + * @skb: buffer with frame data to transmit + * @netdev: network interface device structure + * + * Returns 0 on success, 1 on error + * + * e1000_xmit_frame is called by the stack to initiate a transmit. + * The out of resource condition is checked after each successful Tx + * so that the stack can be notified, preventing the driver from + * ever needing to drop a frame. The atomic operations on + * tx_ring.unused are used to syncronize with the transmit + * interrupt processing code without the need for a spinlock. + **/ + +#define TXD_USE_COUNT(x) (((x) >> 12) + ((x) & 0x0fff ? 1 : 0)) + +#define SETUP_TXD_PAGE(L, P, O) do { \ + tx_ring->buffer_info[i].length = (L); \ + tx_ring->buffer_info[i].dma = \ + pci_map_page(pdev, (P), (O), (L), PCI_DMA_TODEVICE); \ + tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma); \ + tx_desc->lower.data = cpu_to_le32(txd_lower | (L)); \ + tx_desc->upper.data = cpu_to_le32(txd_upper); \ +} while (0) + +#define SETUP_TXD_PTR(L, P) \ + SETUP_TXD_PAGE((L), virt_to_page(P), (unsigned long)(P) & ~PAGE_MASK) + +#define QUEUE_TXD() do { i = (i + 1) % tx_ring->count; \ + atomic_dec(&tx_ring->unused); } while (0) + + +static int +e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + struct e1000_desc_ring *tx_ring = &adapter->tx_ring; + struct pci_dev *pdev = adapter->pdev; + struct e1000_tx_desc *tx_desc; + int f, len, offset, txd_needed; + skb_frag_t *frag; + + int i = tx_ring->next_to_use; + uint32_t txd_upper = 0; + uint32_t txd_lower = adapter->txd_cmd; + + + /* If controller appears hung, force transmit timeout */ + + if (time_after(netdev->trans_start, adapter->trans_finish + HZ) && + /* If transmitting XOFFs, we're not really hung */ + !(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_TXOFF)) { + adapter->trans_finish = jiffies; + netif_stop_queue(netdev); + return 1; + } + + txd_needed = TXD_USE_COUNT(skb->len - skb->data_len); + + for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) { + frag = &skb_shinfo(skb)->frags[f]; + txd_needed += TXD_USE_COUNT(frag->size); + } + + if(skb->ip_summed == CHECKSUM_HW) + txd_needed += 1; + + /* make sure there are enough Tx descriptors available in the ring */ + + if(atomic_read(&tx_ring->unused) <= (txd_needed + 1)) { + adapter->net_stats.tx_dropped++; + netif_stop_queue(netdev); + return 1; + } + + if(skb->ip_summed == CHECKSUM_HW) { + struct e1000_context_desc *context_desc; + uint8_t css = skb->h.raw - skb->data; + uint8_t cso = (skb->h.raw + skb->csum) - skb->data; + + context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + + context_desc->upper_setup.tcp_fields.tucss = css; + context_desc->upper_setup.tcp_fields.tucso = cso; + context_desc->upper_setup.tcp_fields.tucse = 0; + context_desc->tcp_seg_setup.data = 0; + context_desc->cmd_and_length = + cpu_to_le32(txd_lower | E1000_TXD_CMD_DEXT); + + QUEUE_TXD(); + + txd_upper |= E1000_TXD_POPTS_TXSM << 8; + txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + } + + tx_desc = E1000_TX_DESC(*tx_ring, i); + len = skb->len - skb->data_len; + offset = 0; + + while(len > 4096) { + SETUP_TXD_PTR(4096, skb->data + offset); + QUEUE_TXD(); + + tx_desc = E1000_TX_DESC(*tx_ring, i); + len -= 4096; + offset += 4096; + } + + SETUP_TXD_PTR(len, skb->data + offset); + + for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) { + frag = &skb_shinfo(skb)->frags[f]; + + QUEUE_TXD(); + + tx_desc = E1000_TX_DESC(*tx_ring, i); + len = frag->size; + offset = 0; + + while(len > 4096) { + SETUP_TXD_PAGE(4096, frag->page, + frag->page_offset + offset); + QUEUE_TXD(); + + tx_desc = E1000_TX_DESC(*tx_ring, i); + len -= 4096; + offset += 4096; + } + SETUP_TXD_PAGE(len, frag->page, frag->page_offset + offset); + } + + /* EOP and SKB pointer go with the last fragment */ + + tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP); + tx_ring->buffer_info[i].skb = skb; + + QUEUE_TXD(); + + tx_ring->next_to_use = i; + + /* Move the HW Tx Tail Pointer */ + + E1000_WRITE_REG(&adapter->shared, TDT, i); + + netdev->trans_start = jiffies; + + return 0; +} + +#undef TXD_USE_COUNT +#undef SETUP_TXD +#undef QUEUE_TXD + +/** + * e1000_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + **/ + +static void +e1000_tx_timeout(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + + e1000_down(adapter); + e1000_up(adapter); +} + +/** + * e1000_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + **/ + +static struct net_device_stats * +e1000_get_stats(struct net_device *netdev) +{ + struct e1000_adapter *adapter = netdev->priv; + + return &adapter->net_stats; +} + +/** + * e1000_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + **/ + +static int +e1000_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct e1000_adapter *adapter = netdev->priv; + int old_mtu = adapter->rx_buffer_len; + int max_frame = new_mtu + ENET_HEADER_SIZE + CRC_LENGTH; + + if((max_frame < MINIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH) || + (max_frame > MAX_JUMBO_FRAME_SIZE + CRC_LENGTH)) { + E1000_ERR("Invalid MTU setting\n"); + return -EINVAL; + } + + if(max_frame <= MAXIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH) { + adapter->rx_buffer_len = E1000_RXBUFFER_2048; + + } else if(adapter->shared.mac_type < e1000_82543) { + E1000_ERR("Jumbo Frames not supported on 82542\n"); + return -EINVAL; + + } else if(max_frame <= E1000_RXBUFFER_2048) { + adapter->rx_buffer_len = E1000_RXBUFFER_2048; + + } else if(max_frame <= E1000_RXBUFFER_4096) { + adapter->rx_buffer_len = E1000_RXBUFFER_4096; + + } else if(max_frame <= E1000_RXBUFFER_8192) { + adapter->rx_buffer_len = E1000_RXBUFFER_8192; + + } else { + adapter->rx_buffer_len = E1000_RXBUFFER_16384; + } + + if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) { + + e1000_down(adapter); + e1000_clean_rx_ring(adapter); + e1000_clean_tx_ring(adapter); + e1000_up(adapter); + } + + netdev->mtu = new_mtu; + adapter->shared.max_frame_size = max_frame; + + return 0; +} + +/** + * e1000_update_stats - Update the board statistics counters + * @adapter: board private structure + **/ + +static void +e1000_update_stats(struct e1000_adapter *adapter) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + unsigned long flags; + +#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF + + spin_lock_irqsave(&adapter->stats_lock, flags); + + /* these counters are modified from e1000_adjust_tbi_stats, + * called from the interrupt context, so they must only + * be written while holding adapter->stats_lock + */ + + adapter->stats.crcerrs += E1000_READ_REG(shared, CRCERRS); + adapter->stats.gprc += E1000_READ_REG(shared, GPRC); + adapter->stats.gorcl += E1000_READ_REG(shared, GORCL); + adapter->stats.gorch += E1000_READ_REG(shared, GORCH); + adapter->stats.bprc += E1000_READ_REG(shared, BPRC); + adapter->stats.mprc += E1000_READ_REG(shared, MPRC); + adapter->stats.roc += E1000_READ_REG(shared, ROC); + adapter->stats.prc64 += E1000_READ_REG(shared, PRC64); + adapter->stats.prc127 += E1000_READ_REG(shared, PRC127); + adapter->stats.prc255 += E1000_READ_REG(shared, PRC255); + adapter->stats.prc511 += E1000_READ_REG(shared, PRC511); + adapter->stats.prc1023 += E1000_READ_REG(shared, PRC1023); + adapter->stats.prc1522 += E1000_READ_REG(shared, PRC1522); + + spin_unlock_irqrestore(&adapter->stats_lock, flags); + + /* the rest of the counters are only modified here */ + + adapter->stats.symerrs += E1000_READ_REG(shared, SYMERRS); + adapter->stats.mpc += E1000_READ_REG(shared, MPC); + adapter->stats.scc += E1000_READ_REG(shared, SCC); + adapter->stats.ecol += E1000_READ_REG(shared, ECOL); + adapter->stats.mcc += E1000_READ_REG(shared, MCC); + adapter->stats.latecol += E1000_READ_REG(shared, LATECOL); + adapter->stats.colc += E1000_READ_REG(shared, COLC); + adapter->stats.dc += E1000_READ_REG(shared, DC); + adapter->stats.sec += E1000_READ_REG(shared, SEC); + adapter->stats.rlec += E1000_READ_REG(shared, RLEC); + adapter->stats.xonrxc += E1000_READ_REG(shared, XONRXC); + adapter->stats.xontxc += E1000_READ_REG(shared, XONTXC); + adapter->stats.xoffrxc += E1000_READ_REG(shared, XOFFRXC); + adapter->stats.xofftxc += E1000_READ_REG(shared, XOFFTXC); + adapter->stats.fcruc += E1000_READ_REG(shared, FCRUC); + adapter->stats.gptc += E1000_READ_REG(shared, GPTC); + adapter->stats.gotcl += E1000_READ_REG(shared, GOTCL); + adapter->stats.gotch += E1000_READ_REG(shared, GOTCH); + adapter->stats.rnbc += E1000_READ_REG(shared, RNBC); + adapter->stats.ruc += E1000_READ_REG(shared, RUC); + adapter->stats.rfc += E1000_READ_REG(shared, RFC); + adapter->stats.rjc += E1000_READ_REG(shared, RJC); + adapter->stats.torl += E1000_READ_REG(shared, TORL); + adapter->stats.torh += E1000_READ_REG(shared, TORH); + adapter->stats.totl += E1000_READ_REG(shared, TOTL); + adapter->stats.toth += E1000_READ_REG(shared, TOTH); + adapter->stats.tpr += E1000_READ_REG(shared, TPR); + adapter->stats.tpt += E1000_READ_REG(shared, TPT); + adapter->stats.ptc64 += E1000_READ_REG(shared, PTC64); + adapter->stats.ptc127 += E1000_READ_REG(shared, PTC127); + adapter->stats.ptc255 += E1000_READ_REG(shared, PTC255); + adapter->stats.ptc511 += E1000_READ_REG(shared, PTC511); + adapter->stats.ptc1023 += E1000_READ_REG(shared, PTC1023); + adapter->stats.ptc1522 += E1000_READ_REG(shared, PTC1522); + adapter->stats.mptc += E1000_READ_REG(shared, MPTC); + adapter->stats.bptc += E1000_READ_REG(shared, BPTC); + + if(adapter->shared.mac_type >= e1000_82543) { + adapter->stats.algnerrc += E1000_READ_REG(shared, ALGNERRC); + adapter->stats.rxerrc += E1000_READ_REG(shared, RXERRC); + adapter->stats.tncrs += E1000_READ_REG(shared, TNCRS); + adapter->stats.cexterr += E1000_READ_REG(shared, CEXTERR); + adapter->stats.tsctc += E1000_READ_REG(shared, TSCTC); + adapter->stats.tsctfc += E1000_READ_REG(shared, TSCTFC); + } + + /* Fill out the OS statistics structure */ + + adapter->net_stats.rx_packets = adapter->stats.gprc; + adapter->net_stats.tx_packets = adapter->stats.gptc; + adapter->net_stats.rx_bytes = adapter->stats.gorcl; + adapter->net_stats.tx_bytes = adapter->stats.gotcl; + adapter->net_stats.multicast = adapter->stats.mprc; + adapter->net_stats.collisions = adapter->stats.colc; + + /* Rx Errors */ + + adapter->net_stats.rx_errors = adapter->stats.rxerrc + + adapter->stats.crcerrs + adapter->stats.algnerrc + + adapter->stats.rlec + adapter->stats.rnbc + + adapter->stats.mpc + adapter->stats.cexterr; + adapter->net_stats.rx_dropped = adapter->stats.rnbc; + adapter->net_stats.rx_length_errors = adapter->stats.rlec; + adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; + adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; + adapter->net_stats.rx_fifo_errors = adapter->stats.mpc; + adapter->net_stats.rx_missed_errors = adapter->stats.mpc; + + /* Tx Errors */ + + adapter->net_stats.tx_errors = adapter->stats.ecol + + adapter->stats.latecol; + adapter->net_stats.tx_aborted_errors = adapter->stats.ecol; + adapter->net_stats.tx_window_errors = adapter->stats.latecol; + + /* Tx Dropped needs to be maintained elsewhere */ + + if(adapter->shared.media_type == e1000_media_type_copper) { + adapter->phy_stats.idle_errors += + (e1000_read_phy_reg(shared, PHY_1000T_STATUS) + & PHY_IDLE_ERROR_COUNT_MASK); + adapter->phy_stats.receive_errors += + e1000_read_phy_reg(shared, M88E1000_RX_ERR_CNTR); + } + return; +} + +/** + * e1000_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + **/ + +static inline void +e1000_irq_disable(struct e1000_adapter *adapter) +{ + atomic_inc(&adapter->irq_sem); + E1000_WRITE_REG(&adapter->shared, IMC, ~0); + synchronize_irq(); + return; +} + +/** + * e1000_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + **/ + +static inline void +e1000_irq_enable(struct e1000_adapter *adapter) +{ + if(atomic_dec_and_test(&adapter->irq_sem)) + E1000_WRITE_REG(&adapter->shared, IMS, IMS_ENABLE_MASK); + return; +} + +/** + * e1000_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + * @pt_regs: CPU registers structure + **/ + +static void +e1000_intr(int irq, void *data, struct pt_regs *regs) +{ + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev->priv; + uint32_t icr; + int i = E1000_MAX_INTR; + + while(i && (icr = E1000_READ_REG(&adapter->shared, ICR))) { + + if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + /* run the watchdog ASAP */ + adapter->shared.get_link_status = 1; + mod_timer(&adapter->watchdog_timer, jiffies); + } + + e1000_clean_rx_irq(adapter); + e1000_clean_tx_irq(adapter); + i--; + } + + return; +} + +/** + * e1000_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure + **/ + +static void +e1000_clean_tx_irq(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *tx_ring = &adapter->tx_ring; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_tx_desc *tx_desc; + int i; + + i = tx_ring->next_to_clean; + tx_desc = E1000_TX_DESC(*tx_ring, i); + + while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { + + if(tx_ring->buffer_info[i].dma) { + + pci_unmap_page(pdev, + tx_ring->buffer_info[i].dma, + tx_ring->buffer_info[i].length, + PCI_DMA_TODEVICE); + + tx_ring->buffer_info[i].dma = 0; + } + + if(tx_ring->buffer_info[i].skb) { + + dev_kfree_skb_irq(tx_ring->buffer_info[i].skb); + + tx_ring->buffer_info[i].skb = NULL; + } + + memset(tx_desc, 0, sizeof(struct e1000_tx_desc)); + mb(); + + atomic_inc(&tx_ring->unused); + i = (i + 1) % tx_ring->count; + tx_desc = E1000_TX_DESC(*tx_ring, i); + + adapter->trans_finish = jiffies; + } + + tx_ring->next_to_clean = i; + + if(netif_queue_stopped(netdev) && netif_carrier_ok(netdev) && + (atomic_read(&tx_ring->unused) > E1000_TX_QUEUE_WAKE)) { + + netif_wake_queue(netdev); + } + return; +} + +/** + * e1000_clean_rx_irq - Send received data up the network stack, + * @adapter: board private structure + **/ + +static void +e1000_clean_rx_irq(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *rx_ring = &adapter->rx_ring; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc; + struct sk_buff *skb; + unsigned long flags; + uint32_t length; + uint8_t last_byte; + int i; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC(*rx_ring, i); + + while(rx_desc->status & E1000_RXD_STAT_DD) { + + pci_unmap_single(pdev, + rx_ring->buffer_info[i].dma, + rx_ring->buffer_info[i].length, + PCI_DMA_FROMDEVICE); + + skb = rx_ring->buffer_info[i].skb; + length = le16_to_cpu(rx_desc->length); + + if(!(rx_desc->status & E1000_RXD_STAT_EOP)) { + + /* All receives must fit into a single buffer */ + + E1000_DBG("Receive packet consumed multiple buffers\n"); + + dev_kfree_skb_irq(skb); + memset(rx_desc, 0, 16); + mb(); + rx_ring->buffer_info[i].skb = NULL; + + rx_ring->unused_count++; + + i = (i + 1) % rx_ring->count; + + rx_desc = E1000_RX_DESC(*rx_ring, i); + continue; + } + + if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { + + last_byte = *(skb->data + length - 1); + + if(TBI_ACCEPT(&adapter->shared, rx_desc->special, + rx_desc->errors, length, last_byte)) { + + spin_lock_irqsave(&adapter->stats_lock, flags); + + e1000_tbi_adjust_stats(&adapter->shared, + &adapter->stats, + length, skb->data); + + spin_unlock_irqrestore(&adapter->stats_lock, + flags); + length--; + } else { + + dev_kfree_skb_irq(skb); + memset(rx_desc, 0, 16); + mb(); + rx_ring->buffer_info[i].skb = NULL; + + rx_ring->unused_count++; + i = (i + 1) % rx_ring->count; + + rx_desc = E1000_RX_DESC(*rx_ring, i); + continue; + } + } + + /* Good Receive */ + skb_put(skb, length - CRC_LENGTH); + + /* Receive Checksum Offload */ + e1000_rx_checksum(adapter, rx_desc, skb); + + skb->protocol = eth_type_trans(skb, netdev); + netif_rx(skb); + + memset(rx_desc, 0, sizeof(struct e1000_rx_desc)); + mb(); + rx_ring->buffer_info[i].skb = NULL; + + rx_ring->unused_count++; + + i = (i + 1) % rx_ring->count; + + rx_desc = E1000_RX_DESC(*rx_ring, i); + } + + rx_ring->next_to_clean = i; + + e1000_alloc_rx_buffers(adapter); + + return; +} + +/** + * e1000_alloc_rx_buffers - Replace used receive buffers + * @data: address of board private structure + **/ + +static void +e1000_alloc_rx_buffers(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *rx_ring = &adapter->rx_ring; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct e1000_rx_desc *rx_desc; + struct sk_buff *skb; + int reserve_len; + int i; + + if(!netif_running(netdev)) + return; + + reserve_len = 2; + + i = rx_ring->next_to_use; + + while(!rx_ring->buffer_info[i].skb) { + rx_desc = E1000_RX_DESC(*rx_ring, i); + + skb = alloc_skb(adapter->rx_buffer_len + reserve_len, + GFP_ATOMIC); + + if(!skb) { + /* Better luck next round */ + break; + } + + /* Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, reserve_len); + + skb->dev = netdev; + + rx_ring->buffer_info[i].skb = skb; + rx_ring->buffer_info[i].length = adapter->rx_buffer_len; + rx_ring->buffer_info[i].dma = + pci_map_single(pdev, + skb->data, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + + rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma); + + /* move tail */ + E1000_WRITE_REG(&adapter->shared, RDT, i); + + atomic_dec(&rx_ring->unused); + + i = (i + 1) % rx_ring->count; + } + + rx_ring->next_to_use = i; + return; +} + +/** + * e1000_ioctl - + * @netdev: + * @ifreq: + * @cmd: + **/ + +static int +e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCETHTOOL: + return e1000_ethtool_ioctl(netdev, ifr); + default: + return -EOPNOTSUPP; + } +} + +/** + * e1000_rx_checksum - Receive Checksum Offload for 82543 + * @adapter: board private structure + * @rx_desc: receive descriptor + * @sk_buff: socket buffer with received data + **/ + +static inline void +e1000_rx_checksum(struct e1000_adapter *adapter, + struct e1000_rx_desc *rx_desc, + struct sk_buff *skb) +{ + /* 82543 or newer only */ + if((adapter->shared.mac_type < e1000_82543) || + /* Ignore Checksum bit is set */ + (rx_desc->status & E1000_RXD_STAT_IXSM) || + /* TCP Checksum has not been calculated */ + (!(rx_desc->status & E1000_RXD_STAT_TCPCS))) { + skb->ip_summed = CHECKSUM_NONE; + return; + } + + /* At this point we know the hardware did the TCP checksum */ + /* now look at the TCP checksum error bit */ + if(rx_desc->errors & E1000_RXD_ERR_TCPE) { + /* let the stack verify checksum errors */ + skb->ip_summed = CHECKSUM_NONE; + adapter->hw_csum_err++; + } else { + /* TCP checksum is good */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + adapter->hw_csum_good++; + } + return; +} + + +/** + * e1000_enable_WOL - Wake On Lan Support (Magic Pkt) + * @adapter: Adapter structure + **/ + +void +e1000_enable_WOL(struct e1000_adapter *adapter) +{ + uint32_t wuc; + + if(adapter->shared.mac_type < e1000_82544) + return; + + if(adapter->wol) { + wuc = E1000_WUC_APME | E1000_WUC_PME_EN | + E1000_WUC_PME_STATUS | E1000_WUC_APMPME; + + E1000_WRITE_REG(&adapter->shared, WUC, wuc); + + E1000_WRITE_REG(&adapter->shared, WUFC, adapter->wol); + } + + return; +} + +void +e1000_write_pci_cfg(struct e1000_shared_adapter *shared, + uint32_t reg, uint16_t *value) +{ + struct e1000_adapter *adapter = shared->back; + + pci_write_config_word(adapter->pdev, reg, *value); + return; +} + +/* e1000_main.c */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/e1000/e1000_osdep.h linux-2.5/drivers/net/e1000/e1000_osdep.h --- linux-2.5.5/drivers/net/e1000/e1000_osdep.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/e1000/e1000_osdep.h Tue Feb 26 21:24:49 2002 @@ -0,0 +1,142 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +/* glue for the OS independant part of e1000 + * includes register access macros + */ + +#ifndef _E1000_OSDEP_H_ +#define _E1000_OSDEP_H_ + +#include +#include +#include +#include +#include + +#define usec_delay(x) udelay(x) +#define msec_delay(x) do { if(in_interrupt()) { \ + mdelay(x); \ + } else { \ + set_current_state(TASK_UNINTERRUPTIBLE); \ + schedule_timeout((x * HZ)/1000); \ + } } while(0) + +#define PCI_COMMAND_REGISTER PCI_COMMAND +#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE + +typedef enum { + FALSE = 0, + TRUE = 1 +} boolean_t; + +#define ASSERT(x) if(!(x)) BUG() +#define MSGOUT(S, A, B) printk(KERN_DEBUG S "\n", A, B) + +#if DBG +#define DEBUGOUT(S) printk(KERN_DEBUG S "\n") +#define DEBUGOUT1(S, A...) printk(KERN_DEBUG S "\n", A) +#else +#define DEBUGOUT(S) +#define DEBUGOUT1(S, A...) +#endif + +#define DEBUGFUNC(F) DEBUGOUT(F) +#define DEBUGOUT2 DEBUGOUT1 +#define DEBUGOUT3 DEBUGOUT2 +#define DEBUGOUT7 DEBUGOUT3 + + +#define E1000_WRITE_REG(a, reg, value) ( \ + ((a)->mac_type >= e1000_82543) ? \ + (writel((value), ((a)->hw_addr + E1000_##reg))) : \ + (writel((value), ((a)->hw_addr + E1000_82542_##reg)))) + +#define E1000_READ_REG(a, reg) ( \ + ((a)->mac_type >= e1000_82543) ? \ + readl((a)->hw_addr + E1000_##reg) : \ + readl((a)->hw_addr + E1000_82542_##reg)) + +#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \ + ((a)->mac_type >= e1000_82543) ? \ + writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2))) : \ + writel((value), ((a)->hw_addr + E1000_82542_##reg + ((offset) << 2)))) + +#define E1000_READ_REG_ARRAY(a, reg, offset) ( \ + ((a)->mac_type >= e1000_82543) ? \ + readl((a)->hw_addr + E1000_##reg + ((offset) << 2)) : \ + readl((a)->hw_addr + E1000_82542_##reg + ((offset) << 2))) + +#endif /* _E1000_OSDEP_H_ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/e1000/e1000_param.c linux-2.5/drivers/net/e1000/e1000_param.c --- linux-2.5.5/drivers/net/e1000/e1000_param.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/e1000/e1000_param.c Tue Feb 26 21:24:49 2002 @@ -0,0 +1,709 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include "e1000.h" + +/* This is the only thing that needs to be changed to adjust the + * maximum number of ports that the driver can manage. + */ + +#define E1000_MAX_NIC 32 + +#define OPTION_UNSET -1 +#define OPTION_DISABLED 0 +#define OPTION_ENABLED 1 + +/* Module Parameters are always initialized to -1, so that the driver + * can tell the difference between no user specified value or the + * user asking for the default value. + * The true default values are loaded in when e1000_check_options is called. + * + * This is a GCC extension to ANSI C. + * See the item "Labeled Elements in Initializers" in the section + * "Extensions to the C Language Family" of the GCC documentation. + */ + +#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET } + +/* All parameters are treated the same, as an integer array of values. + * This macro just reduces the need to repeat the same declaration code + * over and over (plus this helps to avoid typo bugs). + */ + +#define E1000_PARAM(X, S) \ +static const int __devinitdata X[E1000_MAX_NIC + 1] = E1000_PARAM_INIT; \ +MODULE_PARM(X, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); \ +MODULE_PARM_DESC(X, S); + +/* Transmit Descriptor Count + * + * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers + * Valid Range: 80-4096 for 82544 + * + * Default Value: 256 + */ + +E1000_PARAM(TxDescriptors, "Number of transmit descriptors"); + +/* Receive Descriptor Count + * + * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers + * Valid Range: 80-4096 for 82544 + * + * Default Value: 80 + */ + +E1000_PARAM(RxDescriptors, "Number of receive descriptors"); + +/* User Specified Speed Override + * + * Valid Range: 0, 10, 100, 1000 + * - 0 - auto-negotiate at all supported speeds + * - 10 - only link at 10 Mbps + * - 100 - only link at 100 Mbps + * - 1000 - only link at 1000 Mbps + * + * Default Value: 0 + */ + +E1000_PARAM(Speed, "Speed setting"); + +/* User Specified Duplex Override + * + * Valid Range: 0-2 + * - 0 - auto-negotiate for duplex + * - 1 - only link at half duplex + * - 2 - only link at full duplex + * + * Default Value: 0 + */ + +E1000_PARAM(Duplex, "Duplex setting"); + +/* Auto-negotiation Advertisement Override + * + * Valid Range: 0x00-0x0F, 0x20-0x2F + * + * The AutoNeg value is a bit mask describing which speed and duplex + * combinations should be advertised during auto-negotiation. + * The supported speed and duplex modes are listed below + * + * Bit 7 6 5 4 3 2 1 0 + * Speed (Mbps) N/A N/A 1000 N/A 100 100 10 10 + * Duplex Full Full Half Full Half + * + * Default Value: 0x2F + */ + +E1000_PARAM(AutoNeg, "Advertised auto-negotiation setting"); + +/* User Specified Flow Control Override + * + * Valid Range: 0-3 + * - 0 - No Flow Control + * - 1 - Rx only, respond to PAUSE frames but do not generate them + * - 2 - Tx only, generate PAUSE frames but ignore them on receive + * - 3 - Full Flow Control Support + * + * Default Value: Read flow control settings from the EEPROM + */ + +E1000_PARAM(FlowControl, "Flow Control setting"); + +/* XsumRX - Receive Checksum Offload Enable/Disable + * + * Valid Range: 0, 1 + * - 0 - disables all checksum offload + * - 1 - enables receive IP/TCP/UDP checksum offload + * on 82543 based NICs + * + * Default Value: 1 + */ + +E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload"); + +/* Transmit Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + * + * Default Value: 64 + */ + +E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay"); + +/* Receive Interrupt Delay in units of 1.024 microseconds + * + * Valid Range: 0-65535 + * + * Default Value: 64 + */ + +E1000_PARAM(RxIntDelay, "Receive Interrupt Delay"); + +/* MDI-X Support Enable/Disable - Applies only to Copper PHY + * + * Valid Range: 0, 3 + * - 0 - Auto in all modes + * - 1 - MDI + * - 2 - MDI-X + * - 3 - Auto in 1000 Base-T mode (MDI in 10 Base-T and 100 Base-T) + * + * Default Value: 0 (Auto) + */ + +E1000_PARAM(MdiX, "Set MDI/MDI-X Mode"); + +/* Automatic Correction of Reversed Cable Polarity Enable/Disable + * This setting applies only to Copper PHY + * + * Valid Range: 0, 1 + * - 0 - Disabled + * - 1 - Enabled + * + * Default Value: 1 (Enabled) + */ + +E1000_PARAM(DisablePolarityCorrection, + "Disable or enable Automatic Correction for Reversed Cable Polarity"); + + +#define AUTONEG_ADV_DEFAULT 0x2F +#define AUTONEG_ADV_MASK 0x2F +#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL + +#define DEFAULT_TXD 256 +#define MAX_TXD 256 +#define MIN_TXD 80 +#define MAX_82544_TXD 4096 + +#define DEFAULT_RXD 80 +#define MAX_RXD 256 +#define MIN_RXD 80 +#define MAX_82544_RXD 4096 + +#define DEFAULT_TIDV 64 +#define MAX_TIDV 0xFFFF +#define MIN_TIDV 0 + +#define DEFAULT_RIDV 64 +#define MAX_RIDV 0xFFFF +#define MIN_RIDV 0 + +#define DEFAULT_MDIX 0 +#define MAX_MDIX 3 +#define MIN_MDIX 0 + + +struct e1000_option { + enum { enable_option, range_option, list_option } type; + char *name; + char *err; + int def; + union { + struct { /* range_option info */ + int min; + int max; + } r; + struct { /* list_option info */ + int nr; + struct e1000_opt_list { int i; char *str; } *p; + } l; + } arg; +}; + + +static int __devinit +e1000_validate_option(int *value, struct e1000_option *opt) +{ + if(*value == OPTION_UNSET) { + *value = opt->def; + return 0; + } + + switch (opt->type) { + case enable_option: + switch (*value) { + case OPTION_ENABLED: + printk(KERN_INFO "%s Enabled\n", opt->name); + return 0; + case OPTION_DISABLED: + printk(KERN_INFO "%s Disabled\n", opt->name); + return 0; + } + break; + case range_option: + if(*value >= opt->arg.r.min && *value <= opt->arg.r.max) { + printk(KERN_INFO "%s set to %i\n", opt->name, *value); + return 0; + } + break; + case list_option: { + int i; + struct e1000_opt_list *ent; + + for(i = 0; i < opt->arg.l.nr; i++) { + ent = &opt->arg.l.p[i]; + if(*value == ent->i) { + if(ent->str[0] != '\0') + printk(KERN_INFO "%s\n", ent->str); + return 0; + } + } + } + break; + default: + BUG(); + } + + printk(KERN_INFO "Invalid %s specified (%i) %s\n", + opt->name, *value, opt->err); + *value = opt->def; + return -1; +} + +#define LIST_LEN(l) (sizeof(l) / sizeof(l[0])) + +static void e1000_check_fiber_options(struct e1000_adapter *adapter); +static void e1000_check_copper_options(struct e1000_adapter *adapter); + +/** + * e1000_check_options - Range Checking for Command Line Parameters + * @adapter: board private structure + * + * This routine checks all command line paramters for valid user + * input. If an invalid value is given, or if no user specified + * value exists, a default value is used. The final value is stored + * in a variable in the adapter structure. + **/ + +void __devinit +e1000_check_options(struct e1000_adapter *adapter) +{ + int bd = adapter->bd_number; + if(bd >= E1000_MAX_NIC) { + printk(KERN_NOTICE + "Warning: no configuration for board #%i\n", bd); + printk(KERN_NOTICE "Using defaults for all values\n"); + bd = E1000_MAX_NIC; + } + + { /* Transmit Descriptor Count */ + struct e1000_option opt = { + type: range_option, + name: "Transmit Descriptors", + err: "using default of " __MODULE_STRING(DEFAULT_TXD), + def: DEFAULT_TXD, + arg: { r: { min: MIN_TXD }} + }; + struct e1000_desc_ring *tx_ring = &adapter->tx_ring; + e1000_mac_type mac_type = adapter->shared.mac_type; + opt.arg.r.max = mac_type < e1000_82544 ? MAX_TXD : MAX_82544_TXD; + + tx_ring->count = TxDescriptors[bd]; + e1000_validate_option(&tx_ring->count, &opt); + E1000_ROUNDUP(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE); + } + { /* Receive Descriptor Count */ + struct e1000_option opt = { + type: range_option, + name: "Receive Descriptors", + err: "using default of " __MODULE_STRING(DEFAULT_RXD), + def: DEFAULT_RXD, + arg: { r: { min: MIN_RXD }} + }; + struct e1000_desc_ring *rx_ring = &adapter->rx_ring; + e1000_mac_type mac_type = adapter->shared.mac_type; + opt.arg.r.max = mac_type < e1000_82544 ? MAX_RXD : MAX_82544_RXD; + + rx_ring->count = RxDescriptors[bd]; + e1000_validate_option(&rx_ring->count, &opt); + E1000_ROUNDUP(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE); + } + { /* Checksum Offload Enable/Disable */ + struct e1000_option opt = { + type: enable_option, + name: "Checksum Offload", + err: "defaulting to Enabled", + def: OPTION_ENABLED + }; + + int rx_csum = XsumRX[bd]; + e1000_validate_option(&rx_csum, &opt); + adapter->rx_csum = rx_csum; + } + { /* Flow Control */ + + struct e1000_opt_list fc_list[] = + {{ e1000_fc_none, "Flow Control Disabled" }, + { e1000_fc_rx_pause,"Flow Control Receive Only" }, + { e1000_fc_tx_pause,"Flow Control Transmit Only" }, + { e1000_fc_full, "Flow Control Enabled" }, + { e1000_fc_default, "Flow Control Hardware Default" }}; + + struct e1000_option opt = { + type: list_option, + name: "Flow Control", + err: "reading default settings from EEPROM", + def: e1000_fc_default, + arg: { l: { nr: LIST_LEN(fc_list), p: fc_list }} + }; + + int fc = FlowControl[bd]; + e1000_validate_option(&fc, &opt); + adapter->shared.fc = adapter->shared.original_fc = fc; + } + { /* Transmit Interrupt Delay */ + struct e1000_option opt = { + type: range_option, + name: "Transmit Interrupt Delay", + err: "using default of " __MODULE_STRING(DEFAULT_TIDV), + def: DEFAULT_TIDV, + arg: { r: { min: MIN_TIDV, max: MAX_TIDV }} + }; + + adapter->tx_int_delay = TxIntDelay[bd]; + e1000_validate_option(&adapter->tx_int_delay, &opt); + } + { /* Receive Interrupt Delay */ + struct e1000_option opt = { + type: range_option, + name: "Receive Interrupt Delay", + err: "using default of " __MODULE_STRING(DEFAULT_RIDV), + def: DEFAULT_RIDV, + arg: { r: { min: MIN_RIDV, max: MAX_RIDV }} + }; + + adapter->rx_int_delay = RxIntDelay[bd]; + e1000_validate_option(&adapter->rx_int_delay, &opt); + } + + switch(adapter->shared.media_type) { + case e1000_media_type_fiber: + e1000_check_fiber_options(adapter); + break; + case e1000_media_type_copper: + e1000_check_copper_options(adapter); + break; + default: + BUG(); + } +} + +/** + * e1000_check_fiber_options - Range Checking for Link Options, Fiber Version + * @adapter: board private structure + * + * Handles speed and duplex options on fiber adapters + **/ + +static void __devinit +e1000_check_fiber_options(struct e1000_adapter *adapter) +{ + int bd = adapter->bd_number; + bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd; + + if((Speed[bd] != OPTION_UNSET)) { + printk(KERN_INFO "Speed not valid for fiber adapters, " + "parameter ignored\n"); + } + if((Duplex[bd] != OPTION_UNSET)) { + printk(KERN_INFO "Duplex not valid for fiber adapters, " + "parameter ignored\n"); + } + if((AutoNeg[bd] != OPTION_UNSET)) { + printk(KERN_INFO "AutoNeg not valid for fiber adapters, " + "parameter ignored\n"); + } +} + +/** + * e1000_check_copper_options - Range Checking for Link Options, Copper Version + * @adapter: board private structure + * + * Handles speed and duplex options on copper adapters + **/ + +static void __devinit +e1000_check_copper_options(struct e1000_adapter *adapter) +{ + int speed, dplx; + int bd = adapter->bd_number; + bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd; + + { /* Speed */ + struct e1000_opt_list speed_list[] = {{ 0, "" }, + { SPEED_10, "" }, + { SPEED_100, "" }, + { SPEED_1000, "" }}; + struct e1000_option opt = { + type: list_option, + name: "Speed", + err: "parameter ignored", + def: 0, + arg: { l: { nr: LIST_LEN(speed_list), p: speed_list }} + }; + + speed = Speed[bd]; + e1000_validate_option(&speed, &opt); + } + { /* Duplex */ + struct e1000_opt_list dplx_list[] = {{ 0, "" }, + { HALF_DUPLEX, "" }, + { FULL_DUPLEX, "" }}; + struct e1000_option opt = { + type: list_option, + name: "Duplex", + err: "parameter ignored", + def: 0, + arg: { l: { nr: LIST_LEN(dplx_list), p: dplx_list }} + }; + + dplx = Duplex[bd]; + e1000_validate_option(&dplx, &opt); + } + + if(AutoNeg[bd] != OPTION_UNSET && (speed != 0 || dplx != 0)) { + printk(KERN_INFO + "AutoNeg specified along with Speed or Duplex, " + "parameter ignored\n"); + adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT; + } else { /* Autoneg */ + struct e1000_opt_list an_list[] = + #define AA "Autoneg advertising " + {{ 0x01, AA "10/HD" }, + { 0x02, AA "10/FD" }, + { 0x03, AA "10/FD, 10/HD" }, + { 0x04, AA "100/HD" }, + { 0x05, AA "100/HD, 10/HD" }, + { 0x06, AA "100/HD, 10/FD" }, + { 0x07, AA "100/HD, 10/FD, 10/HD" }, + { 0x08, AA "100/FD" }, + { 0x09, AA "100/FD, 10/HD" }, + { 0x0a, AA "100/FD, 10/FD" }, + { 0x0b, AA "100/FD, 10/FD, 10/HD" }, + { 0x0c, AA "100/FD, 100/HD" }, + { 0x0d, AA "100/FD, 100/HD, 10/HD" }, + { 0x0e, AA "100/FD, 100/HD, 10/FD" }, + { 0x0f, AA "100/FD, 100/HD, 10/FD, 10/HD" }, + { 0x20, AA "1000/FD" }, + { 0x21, AA "1000/FD, 10/HD" }, + { 0x22, AA "1000/FD, 10/FD" }, + { 0x23, AA "1000/FD, 10/FD, 10/HD" }, + { 0x24, AA "1000/FD, 100/HD" }, + { 0x25, AA "1000/FD, 100/HD, 10/HD" }, + { 0x26, AA "1000/FD, 100/HD, 10/FD" }, + { 0x27, AA "1000/FD, 100/HD, 10/FD, 10/HD" }, + { 0x28, AA "1000/FD, 100/FD" }, + { 0x29, AA "1000/FD, 100/FD, 10/HD" }, + { 0x2a, AA "1000/FD, 100/FD, 10/FD" }, + { 0x2b, AA "1000/FD, 100/FD, 10/FD, 10/HD" }, + { 0x2c, AA "1000/FD, 100/FD, 100/HD" }, + { 0x2d, AA "1000/FD, 100/FD, 100/HD, 10/HD" }, + { 0x2e, AA "1000/FD, 100/FD, 100/HD, 10/FD" }, + { 0x2f, AA "1000/FD, 100/FD, 100/HD, 10/FD, 10/HD" }}; + + struct e1000_option opt = { + type: list_option, + name: "Autoneg", + err: "parameter ignored", + def: AUTONEG_ADV_DEFAULT, + arg: { l: { nr: LIST_LEN(an_list), p: an_list }} + }; + + int an = AutoNeg[bd]; + e1000_validate_option(&an, &opt); + adapter->shared.autoneg_advertised = an; + } + + switch (speed + dplx) { + case 0: + adapter->shared.autoneg = 1; + if(Speed[bd] != OPTION_UNSET || Duplex[bd] != OPTION_UNSET) + printk(KERN_INFO + "Speed and duplex autonegotiation enabled\n"); + break; + case HALF_DUPLEX: + printk(KERN_INFO "Half Duplex specified without Speed\n"); + printk(KERN_INFO "Using Autonegotiation at Half Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_10_HALF | + ADVERTISE_100_HALF; + break; + case FULL_DUPLEX: + printk(KERN_INFO "Full Duplex specified without Speed\n"); + printk(KERN_INFO "Using Autonegotiation at Full Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_10_FULL | + ADVERTISE_100_FULL | + ADVERTISE_1000_FULL; + break; + case SPEED_10: + printk(KERN_INFO "10 Mbps Speed specified without Duplex\n"); + printk(KERN_INFO "Using Autonegotiation at 10 Mbps only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_10_HALF | + ADVERTISE_10_FULL; + break; + case SPEED_10 + HALF_DUPLEX: + printk(KERN_INFO "Forcing to 10 Mbps Half Duplex\n"); + adapter->shared.autoneg = 0; + adapter->shared.forced_speed_duplex = e1000_10_half; + adapter->shared.autoneg_advertised = 0; + break; + case SPEED_10 + FULL_DUPLEX: + printk(KERN_INFO "Forcing to 10 Mbps Full Duplex\n"); + adapter->shared.autoneg = 0; + adapter->shared.forced_speed_duplex = e1000_10_full; + adapter->shared.autoneg_advertised = 0; + break; + case SPEED_100: + printk(KERN_INFO "100 Mbps Speed specified without Duplex\n"); + printk(KERN_INFO "Using Autonegotiation at 100 Mbps only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_100_HALF | + ADVERTISE_100_FULL; + break; + case SPEED_100 + HALF_DUPLEX: + printk(KERN_INFO "Forcing to 100 Mbps Half Duplex\n"); + adapter->shared.autoneg = 0; + adapter->shared.forced_speed_duplex = e1000_100_half; + adapter->shared.autoneg_advertised = 0; + break; + case SPEED_100 + FULL_DUPLEX: + printk(KERN_INFO "Forcing to 100 Mbps Full Duplex\n"); + adapter->shared.autoneg = 0; + adapter->shared.forced_speed_duplex = e1000_100_full; + adapter->shared.autoneg_advertised = 0; + break; + case SPEED_1000: + printk(KERN_INFO "1000 Mbps Speed specified without Duplex\n"); + printk(KERN_INFO + "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; + break; + case SPEED_1000 + HALF_DUPLEX: + printk(KERN_INFO "Half Duplex is not supported at 1000 Mbps\n"); + printk(KERN_INFO + "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; + break; + case SPEED_1000 + FULL_DUPLEX: + printk(KERN_INFO + "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); + adapter->shared.autoneg = 1; + adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL; + break; + default: + BUG(); + } + + /* a few other copper only options */ + + { /* MDI/MDI-X */ + struct e1000_option opt = { + type: range_option, + name: "MDI/MDI-X", + err: "using default of " __MODULE_STRING(DEFAULT_MDIX), + def: DEFAULT_MDIX, + arg: { r: { min: MIN_MDIX, max: MAX_MDIX }} + }; + + int mdix = MdiX[bd]; + e1000_validate_option(&mdix, &opt); + adapter->shared.mdix = mdix; + } + { /* Automatic Correction for Reverse Cable Polarity */ + /* option is actually to disable polarity correction, + * so setting to OPTION_ENABLED turns the hardware feature off */ + struct e1000_option opt = { + type: enable_option, + name: "Disable Polarity Correction", + err: "defaulting to Disabled", + def: OPTION_DISABLED, + }; + + int dpc = DisablePolarityCorrection[bd]; + e1000_validate_option(&dpc, &opt); + adapter->shared.disable_polarity_correction = dpc; + } + + /* Speed, AutoNeg and MDI/MDI-X must all play nice */ + if (!e1000_validate_mdi_setting(&(adapter->shared))) { + printk(KERN_INFO "Speed, AutoNeg and MDI-X specifications are " + "incompatible. Setting MDI-X to a compatible value.\n"); + } +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/e1000/e1000_phy.c linux-2.5/drivers/net/e1000/e1000_phy.c --- linux-2.5.5/drivers/net/e1000/e1000_phy.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/e1000/e1000_phy.c Tue Feb 26 21:24:49 2002 @@ -0,0 +1,1485 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* e1000_phy.c + * Shared functions for accessing and configuring the PHY + */ + +#include "e1000_mac.h" +#include "e1000_phy.h" + +/****************************************************************************** +* Raises the Management Data Clock +* +* shared - Struct containing variables accessed by shared code +* ctrl_reg - Device control register's current value +******************************************************************************/ +static void +e1000_raise_mdc(struct e1000_shared_adapter *shared, + uint32_t *ctrl_reg) +{ + /* Raise the clock input to the Management Data Clock (by setting + * the MDC bit), and then delay 2 microseconds. + */ + E1000_WRITE_REG(shared, CTRL, (*ctrl_reg | E1000_CTRL_MDC)); + usec_delay(2); + return; +} + +/****************************************************************************** +* Lowers the Management Data Clock +* +* shared - Struct containing variables accessed by shared code +* ctrl_reg - Device control register's current value +******************************************************************************/ +static void +e1000_lower_mdc(struct e1000_shared_adapter *shared, + uint32_t *ctrl_reg) +{ + /* Lower the clock input to the Management Data Clock (by clearing + * the MDC bit), and then delay 2 microseconds. + */ + E1000_WRITE_REG(shared, CTRL, (*ctrl_reg & ~E1000_CTRL_MDC)); + usec_delay(2); + return; +} + +/****************************************************************************** +* Shifts data bits out to the PHY +* +* shared - Struct containing variables accessed by shared code +* data - Data to send out to the PHY +* count - Number of bits to shift out +* +* Bits are shifted out in MSB to LSB order. +******************************************************************************/ +static void +e1000_phy_shift_out(struct e1000_shared_adapter *shared, + uint32_t data, + uint16_t count) +{ + uint32_t ctrl_reg; + uint32_t mask; + + ASSERT(count <= 32); + + /* We need to shift "count" number of bits out to the PHY. So, the + * value in the "Data" parameter will be shifted out to the PHY + * one bit at a time. In order to do this, "Data" must be broken + * down into bits, which is what the "while" logic does below. + */ + mask = 0x01; + mask <<= (count - 1); + + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Set MDIO_DIR (SWDPIO1) and MDC_DIR (SWDPIO2) direction bits to + * be used as output pins. + */ + ctrl_reg |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR); + + while(mask) { + /* A "1" is shifted out to the PHY by setting the MDIO bit to + * "1" and then raising and lowering the Management Data Clock + * (MDC). A "0" is shifted out to the PHY by setting the MDIO + * bit to "0" and then raising and lowering the clock. + */ + if(data & mask) + ctrl_reg |= E1000_CTRL_MDIO; + else + ctrl_reg &= ~E1000_CTRL_MDIO; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + usec_delay(2); + + e1000_raise_mdc(shared, &ctrl_reg); + e1000_lower_mdc(shared, &ctrl_reg); + + mask = mask >> 1; + } + + /* Clear the data bit just before leaving this routine. */ + ctrl_reg &= ~E1000_CTRL_MDIO; + return; +} + +/****************************************************************************** +* Shifts data bits in from the PHY +* +* shared - Struct containing variables accessed by shared code +* +* Bits are shifted in in MSB to LSB order. +******************************************************************************/ +static uint16_t +e1000_phy_shift_in(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint16_t data = 0; + uint8_t i; + + /* In order to read a register from the PHY, we need to shift in a + * total of 18 bits from the PHY. The first two bit (TurnAround) + * times are used to avoid contention on the MDIO pin when a read + * operation is performed. These two bits are ignored by us and + * thrown away. Bits are "shifted in" by raising the clock input + * to the Management Data Clock (setting the MDC bit), and then + * reading the value of the MDIO bit. + */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as + * input. + */ + ctrl_reg &= ~E1000_CTRL_MDIO_DIR; + ctrl_reg &= ~E1000_CTRL_MDIO; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + /* Raise and Lower the clock before reading in the data. This + * accounts for the TurnAround bits. The first clock occurred + * when we clocked out the last bit of the Register Address. + */ + e1000_raise_mdc(shared, &ctrl_reg); + e1000_lower_mdc(shared, &ctrl_reg); + + for(data = 0, i = 0; i < 16; i++) { + data = data << 1; + e1000_raise_mdc(shared, &ctrl_reg); + + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Check to see if we shifted in a "1". */ + if(ctrl_reg & E1000_CTRL_MDIO) + data |= 1; + + e1000_lower_mdc(shared, &ctrl_reg); + } + + e1000_raise_mdc(shared, &ctrl_reg); + e1000_lower_mdc(shared, &ctrl_reg); + + /* Clear the MDIO bit just before leaving this routine. */ + ctrl_reg &= ~E1000_CTRL_MDIO; + + return (data); +} + +/****************************************************************************** +* Force PHY speed and duplex settings to shared->forced_speed_duplex +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +static void +e1000_phy_force_speed_duplex(struct e1000_shared_adapter *shared) +{ + uint32_t tctl_reg; + uint32_t ctrl_reg; + uint32_t shift; + uint16_t mii_ctrl_reg; + uint16_t mii_status_reg; + uint16_t phy_data; + uint16_t i; + + DEBUGFUNC("e1000_phy_force_speed_duplex"); + + /* Turn off Flow control if we are forcing speed and duplex. */ + shared->fc = e1000_fc_none; + + DEBUGOUT1("shared->fc = %d\n", shared->fc); + + /* Read the Device Control Register. */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */ + ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ctrl_reg &= ~(DEVICE_SPEED_MASK); + + /* Clear the Auto Speed Detect Enable bit. */ + ctrl_reg &= ~E1000_CTRL_ASDE; + + /* Read the MII Control Register. */ + mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL); + + /* We need to disable autoneg in order to force link and duplex. */ + + mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN; + + /* Are we forcing Full or Half Duplex? */ + if(shared->forced_speed_duplex == e1000_100_full || + shared->forced_speed_duplex == e1000_10_full) { + + /* We want to force full duplex so we SET the full duplex bits + * in the Device and MII Control Registers. + */ + ctrl_reg |= E1000_CTRL_FD; + mii_ctrl_reg |= MII_CR_FULL_DUPLEX; + + DEBUGOUT("Full Duplex\n"); + } else { + + /* We want to force half duplex so we CLEAR the full duplex + * bits in the Device and MII Control Registers. + */ + ctrl_reg &= ~E1000_CTRL_FD; + mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX; /* Do this implies HALF */ + + DEBUGOUT("Half Duplex\n"); + } + + /* Are we forcing 100Mbps??? */ + if(shared->forced_speed_duplex == e1000_100_full || + shared->forced_speed_duplex == e1000_100_half) { + + /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */ + ctrl_reg |= E1000_CTRL_SPD_100; + mii_ctrl_reg |= MII_CR_SPEED_100; + mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); + + DEBUGOUT("Forcing 100mb "); + } else { /* Force 10MB Full or Half */ + + /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */ + ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + mii_ctrl_reg |= MII_CR_SPEED_10; + mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); + + DEBUGOUT("Forcing 10mb "); + } + + /* Now we need to configure the Collision Distance. We need to read + * the Transmit Control Register to do this. + * Note: This must be done for both Half or Full Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + DEBUGOUT1("tctl_reg = %x\n", tctl_reg); + + if(!(mii_ctrl_reg & MII_CR_FULL_DUPLEX)) { + + /* We are in Half Duplex mode so we need to set up our collision + * distance for 10/100. + */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } else { + /* We are in Full Duplex mode. We have the same collision + * distance regardless of speed. + */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_FDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } + + /* Write the configured values back to the Transmit Control Reg. */ + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + /* Write the configured values back to the Device Control Reg. */ + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + /* Write the MII Control Register with the new PHY configuration. */ + phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + /* Clear Auto-Crossover to force MDI manually. + * M88E1000 requires MDI forced whenever speed/duplex is forced + */ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data); + + DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data); + + /* Need to reset the PHY or these bits will get ignored. */ + mii_ctrl_reg |= MII_CR_RESET; + + e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); + + /* The wait_autoneg_complete flag may be a little misleading here. + * Since we are forcing speed and duplex, Auto-Neg is not enabled. + * But we do want to delay for a period while forcing only so we + * don't generate false No Link messages. So we will wait here + * only if the user has set wait_autoneg_complete to 1, which is + * the default. + */ + if(shared->wait_autoneg_complete) { + /* We will wait for autoneg to complete. */ + DEBUGOUT("Waiting for forced speed/duplex link.\n"); + mii_status_reg = 0; + + /* We will wait for autoneg to complete or 4.5 seconds to expire. */ + for(i = PHY_FORCE_TIME; i > 0; i--) { + /* Read the MII Status Register and wait for Auto-Neg + * Complete bit to be set. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + if(mii_status_reg & MII_SR_LINK_STATUS) + break; + + msec_delay(100); + } /* end for loop */ + + if(i == 0) { /* We didn't get link */ + + /* Reset the DSP and wait again for link. */ + e1000_phy_reset_dsp(shared); + } + + /* This loop will early-out if the link condition has been met. */ + for(i = PHY_FORCE_TIME; i > 0; i--) { + if(mii_status_reg & MII_SR_LINK_STATUS) + break; + + msec_delay(100); + /* Read the MII Status Register and wait for Auto-Neg + * Complete bit to be set. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + } /* end for loop */ + } /* end if wait_autoneg_complete */ + /* + * Because we reset the PHY above, we need to re-force TX_CLK in the + * Extended PHY Specific Control Register to 25MHz clock. This + * value defaults back to a 2.5MHz clock when the PHY is reset. + */ + phy_data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); + + phy_data |= M88E1000_EPSCR_TX_CLK_25; + + e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); + + /* In addition, because of the s/w reset above, we need to enable + * CRS on TX. This must be set for both full and half duplex + * operation. + */ + phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data); + DEBUGOUT1("M88E1000 Phy Specific Ctrl Reg = %4x\r\n", phy_data); + + return; +} + +/***************************************************************************** +* Reads the value from a PHY register +* +* shared - Struct containing variables accessed by shared code +* reg_addr - address of the PHY register to read +******************************************************************************/ +uint16_t +e1000_read_phy_reg(struct e1000_shared_adapter *shared, + uint32_t reg_addr) +{ + uint32_t i; + uint32_t data = 0; + uint32_t command = 0; + + ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS); + + if(shared->mac_type > e1000_82543) { + /* Set up Op-code, Phy Address, and + * register address in the MDI Control register. The MAC will + * take care of interfacing with the PHY to retrieve the + * desired data. + */ + command = ((reg_addr << E1000_MDIC_REG_SHIFT) | + (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_READ)); + + E1000_WRITE_REG(shared, MDIC, command); + + /* Check every 10 usec to see if the read completed. The read + * may take as long as 64 usecs (we'll wait 100 usecs max) + * from the CPU Write to the Ready bit assertion. + */ + for(i = 0; i < 64; i++) { + usec_delay(10); + + data = E1000_READ_REG(shared, MDIC); + + if(data & E1000_MDIC_READY) + break; + } + } else { + /* We must first send a preamble through the MDIO pin to signal the + * beginning of an MII instruction. This is done by sending 32 + * consecutive "1" bits. + */ + e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); + + /* Now combine the next few fields that are required for a read + * operation. We use this method instead of calling the + * e1000_phy_shift_out routine five different times. The format of + * a MII read instruction consists of a shift out of 14 bits and is + * defined as follows: + * + * followed by a shift in of 18 bits. This first two bits shifted + * in are TurnAround bits used to avoid contention on the MDIO pin + * when a READ operation is performed. These two bits are thrown + * away followed by a shift in of 16 bits which contains the + * desired data. + */ + command = ((reg_addr) | + (shared->phy_addr << 5) | + (PHY_OP_READ << 10) | (PHY_SOF << 12)); + + e1000_phy_shift_out(shared, command, 14); + + /* Now that we've shifted out the read command to the MII, we need + * to "shift in" the 16-bit value (18 total bits) of the requested + * PHY register address. + */ + data = (uint32_t) e1000_phy_shift_in(shared); + } + + ASSERT(!(data & E1000_MDIC_ERROR)); + + return ((uint16_t) data); +} + +/****************************************************************************** +* Writes a value to a PHY register +* +* shared - Struct containing variables accessed by shared code +* reg_addr - address of the PHY register to write +* data - data to write to the PHY +******************************************************************************/ +void +e1000_write_phy_reg(struct e1000_shared_adapter *shared, + uint32_t reg_addr, + uint16_t data) +{ + uint32_t i; + uint32_t command = 0; + uint32_t mdic_reg; + + ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS); + + if(shared->mac_type > e1000_82543) { + /* Set up Op-code, Phy Address, register + * address, and data intended for the PHY register in the MDI + * Control register. The MAC will take care of interfacing + * with the PHY to send the desired data. + */ + command = (((uint32_t) data) | + (reg_addr << E1000_MDIC_REG_SHIFT) | + (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_WRITE)); + + E1000_WRITE_REG(shared, MDIC, command); + + /* Check every 10 usec to see if the read completed. The read + * may take as long as 64 usecs (we'll wait 100 usecs max) + * from the CPU Write to the Ready bit assertion. + */ + for(i = 0; i < 10; i++) { + usec_delay(10); + + mdic_reg = E1000_READ_REG(shared, MDIC); + + if(mdic_reg & E1000_MDIC_READY) + break; + } + } else { + /* We'll need to use the SW defined pins to shift the write command + * out to the PHY. We first send a preamble to the PHY to signal the + * beginning of the MII instruction. This is done by sending 32 + * consecutive "1" bits. + */ + e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); + + /* Now combine the remaining required fields that will indicate + * a write operation. We use this method instead of calling the + * e1000_phy_shift_out routine for each field in the command. The + * format of a MII write instruction is as follows: + * . + */ + command = ((PHY_TURNAROUND) | + (reg_addr << 2) | + (shared->phy_addr << 7) | + (PHY_OP_WRITE << 12) | (PHY_SOF << 14)); + command <<= 16; + command |= ((uint32_t) data); + + e1000_phy_shift_out(shared, command, 32); + } + return; +} + +/****************************************************************************** +* Returns the PHY to the power-on reset state +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +void +e1000_phy_hw_reset(struct e1000_shared_adapter *shared) +{ + uint32_t ctrl_reg; + uint32_t ctrl_ext_reg; + + DEBUGFUNC("e1000_phy_hw_reset"); + + DEBUGOUT("Resetting Phy...\n"); + + if(shared->mac_type > e1000_82543) { + /* Read the device control register and assert the + * E1000_CTRL_PHY_RST bit. Hold for 20ms and then take it out + * of reset. + */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + ctrl_reg |= E1000_CTRL_PHY_RST; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + msec_delay(20); + + ctrl_reg &= ~E1000_CTRL_PHY_RST; + + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + msec_delay(20); + } else { + /* Read the Extended Device Control Register, assert the + * PHY_RESET_DIR bit. Then clock it out to the PHY. + */ + ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); + + ctrl_ext_reg |= E1000_CTRL_PHY_RESET_DIR4; + + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + + msec_delay(20); + + /* Set the reset bit in the device control register and clock + * it out to the PHY. + */ + ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); + + ctrl_ext_reg &= ~E1000_CTRL_PHY_RESET4; + + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + + msec_delay(20); + + ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT); + + ctrl_ext_reg |= E1000_CTRL_PHY_RESET4; + + E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg); + + msec_delay(20); + } + return; +} + +/****************************************************************************** +* Resets the PHY +* +* shared - Struct containing variables accessed by shared code +* +* Sets bit 15 of the MII Control regiser +******************************************************************************/ +boolean_t +e1000_phy_reset(struct e1000_shared_adapter *shared) +{ + uint16_t reg_data; + uint16_t i; + + DEBUGFUNC("e1000_phy_reset"); + + /* Read the MII control register, set the reset bit and write the + * value back by clocking it out to the PHY. + */ + reg_data = e1000_read_phy_reg(shared, PHY_CTRL); + + reg_data |= MII_CR_RESET; + + e1000_write_phy_reg(shared, PHY_CTRL, reg_data); + + /* Wait for bit 15 of the MII Control Register to be cleared + * indicating the PHY has been reset. + */ + i = 0; + while((reg_data & MII_CR_RESET) && i++ < 500) { + reg_data = e1000_read_phy_reg(shared, PHY_CTRL); + usec_delay(1); + } + + if(i >= 500) { + DEBUGOUT("Timeout waiting for PHY to reset.\n"); + return FALSE; + } + return TRUE; +} + +/****************************************************************************** +* Detects which PHY is present and the speed and duplex +* +* shared - Struct containing variables accessed by shared code +* ctrl_reg - current value of the device control register +******************************************************************************/ +boolean_t +e1000_phy_setup(struct e1000_shared_adapter *shared, + uint32_t ctrl_reg) +{ + uint16_t mii_ctrl_reg; + uint16_t mii_status_reg; + uint16_t phy_specific_ctrl_reg; + uint16_t mii_autoneg_adv_reg; + uint16_t mii_1000t_ctrl_reg; + uint16_t i; + uint16_t data; + uint16_t autoneg_hw_setting; + uint16_t autoneg_fc_setting; + boolean_t restart_autoneg = FALSE; + boolean_t force_autoneg_restart = FALSE; + + DEBUGFUNC("e1000_phy_setup"); + + /* We want to enable the Auto-Speed Detection bit in the Device + * Control Register. When set to 1, the MAC automatically detects + * the resolved speed of the link and self-configures appropriately. + * The Set Link Up bit must also be set for this behavior work + * properly. + */ + /* Nothing but 82543 and newer */ + ASSERT(shared->mac_type >= e1000_82543); + + /* With 82543, we need to force speed/duplex + * on the MAC equal to what the PHY speed/duplex configuration is. + * In addition, on 82543, we need to perform a hardware reset + * on the PHY to take it out of reset. + */ + if(shared->mac_type >= e1000_82544) { + ctrl_reg |= E1000_CTRL_SLU; + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + } else { + ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU); + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + if(shared->mac_type == e1000_82543) + e1000_phy_hw_reset(shared); + } + + if(!e1000_detect_gig_phy(shared)) { + /* No PHY detected, return FALSE */ + DEBUGOUT("PhySetup failure, did not detect valid phy.\n"); + return (FALSE); + } + + DEBUGOUT1("Phy ID = %x \n", shared->phy_id); + + /* Read the MII Control Register. */ + mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL); + + DEBUGOUT1("MII Ctrl Reg contents = %x\n", mii_ctrl_reg); + + /* Check to see if the Auto Neg Enable bit is set in the MII Control + * Register. If not, we could be in a situation where a driver was + * loaded previously and was forcing speed and duplex. Then the + * driver was unloaded but a e1000_phy_hw_reset was not performed, so + * link was still being forced and link was still achieved. Then + * the driver was reloaded with the intention to auto-negotiate, but + * since link is already established we end up not restarting + * auto-neg. So if the auto-neg bit is not enabled and the driver + * is being loaded with the desire to auto-neg, we set this flag to + * to ensure the restart of the auto-neg engine later in the logic. + */ + if(!(mii_ctrl_reg & MII_CR_AUTO_NEG_EN)) + force_autoneg_restart = TRUE; + + /* Clear the isolate bit for normal operation and write it back to + * the MII Control Reg. Although the spec says this doesn't need + * to be done when the PHY address is not equal to zero, we do it + * anyway just to be safe. + */ + mii_ctrl_reg &= ~(MII_CR_ISOLATE); + + e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); + + data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + + DEBUGOUT1("M88E1000 PSCR: %x \n", data); + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, data); + + data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); + + /* Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + data |= M88E1000_EPSCR_TX_CLK_25; + + e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, data); + + /* Certain PHYs will set the default of MII register 4 differently. + * We need to check this against our fc value. If it is + * different, we need to setup up register 4 correctly and restart + * autonegotiation. + */ + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV); + + /* Shift right to put 10T-Half bit in bit 0 + * Isolate the four bits for 100/10 Full/Half. + */ + autoneg_hw_setting = (mii_autoneg_adv_reg >> 5) & 0xF; + + /* Get the 1000T settings. */ + mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL); + + /* Isolate and OR in the 1000T settings. */ + autoneg_hw_setting |= ((mii_1000t_ctrl_reg & 0x0300) >> 4); + + /* mask all bits in the MII Auto-Neg Advertisement Register + * except for ASM_DIR and PAUSE and shift. This value + * will be used later to see if we need to restart Auto-Negotiation. + */ + autoneg_fc_setting = ((mii_autoneg_adv_reg & 0x0C00) >> 10); + + /* Perform some bounds checking on the shared->autoneg_advertised + * parameter. If this variable is zero, then set it to the default. + */ + shared->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT; + + /* If autoneg_advertised is zero, we assume it was not defaulted + * by the calling code so we set to advertise full capability. + */ + if(shared->autoneg_advertised == 0) + shared->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; + + /* We could be in the situation where Auto-Neg has already completed + * and the user has not indicated any overrides. In this case we + * simply need to call e1000_get_speed_and_duplex to obtain the Auto- + * Negotiated speed and duplex, then return. + */ + if(!force_autoneg_restart && shared->autoneg && + (shared->autoneg_advertised == autoneg_hw_setting) && + (shared->fc == autoneg_fc_setting)) { + + DEBUGOUT("No overrides - Reading MII Status Reg..\n"); + + /* Read the MII Status Register. We read this twice because + * certain bits are "sticky" and need to be read twice. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + DEBUGOUT1("MII Status Reg contents = %x\n", mii_status_reg); + + /* Do we have link now? (if so, auto-neg has completed) */ + if(mii_status_reg & MII_SR_LINK_STATUS) { + data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data); + + /* We have link, so we need to finish the config process: + * 1) Set up the MAC to the current PHY speed/duplex + * if we are on 82543. If we + * are on newer silicon, we only need to configure + * collision distance in the Transmit Control Register. + * 2) Set up flow control on the MAC to that established + * with the link partner. + */ + if(shared->mac_type >= e1000_82544) + e1000_config_collision_dist(shared); + else + e1000_config_mac_to_phy(shared, data); + + e1000_config_fc_after_link_up(shared); + + return (TRUE); + } + } + + /* Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + phy_specific_ctrl_reg &= ~M88E1000_PSCR_AUTO_X_MODE; + + switch (shared->mdix) { + case 1: + phy_specific_ctrl_reg |= M88E1000_PSCR_MDI_MANUAL_MODE; + break; + case 2: + phy_specific_ctrl_reg |= M88E1000_PSCR_MDIX_MANUAL_MODE; + break; + case 3: + phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_1000T; + break; + case 0: + default: + phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_MODE; + break; + } + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg); + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + + phy_specific_ctrl_reg &= ~M88E1000_PSCR_POLARITY_REVERSAL; + + if(shared->disable_polarity_correction == 1) + phy_specific_ctrl_reg |= M88E1000_PSCR_POLARITY_REVERSAL; + + e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg); + + /* Options: + * autoneg = 1 (default) + * PHY will advertise value(s) parsed from + * autoneg_advertised and fc + * autoneg = 0 + * PHY will be set to 10H, 10F, 100H, or 100F + * depending on value parsed from forced_speed_duplex. + */ + + /* Is autoneg enabled? This is enabled by default or by software override. + * If so, call e1000_phy_setup_autoneg routine to parse the + * autoneg_advertised and fc options. If autoneg is NOT enabled, then the + * user should have provided a speed/duplex override. If so, then call + * e1000_phy_force_speed_duplex to parse and set this up. Otherwise, + * we are in an error situation and need to bail. + */ + if(shared->autoneg) { + DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); + restart_autoneg = e1000_phy_setup_autoneg(shared); + } else { + DEBUGOUT("Forcing speed and duplex\n"); + e1000_phy_force_speed_duplex(shared); + } + + /* Based on information parsed above, check the flag to indicate + * whether we need to restart Auto-Neg. + */ + if(restart_autoneg) { + DEBUGOUT("Restarting Auto-Neg\n"); + + /* Read the MII Control Register. */ + mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL); + + /* Restart auto-negotiation by setting the Auto Neg Enable bit and + * the Auto Neg Restart bit. + */ + mii_ctrl_reg |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + + e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg); + + /* Does the user want to wait for Auto-Neg to complete here, or + * check at a later time (for example, callback routine). + */ + if(shared->wait_autoneg_complete) + e1000_wait_autoneg(shared); + } /* end if restart_autoneg */ + + /* Read the MII Status Register. */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + DEBUGOUT1("Checking for link status - MII Status Reg contents = %x\n", + mii_status_reg); + + /* Check link status. Wait up to 100 microseconds for link to + * become valid. + */ + for(i = 0; i < 10; i++) { + if(mii_status_reg & MII_SR_LINK_STATUS) + break; + usec_delay(10); + DEBUGOUT(". "); + + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + } + + if(mii_status_reg & MII_SR_LINK_STATUS) { + /* Yes, so configure MAC to PHY settings as well as flow control + * registers. + */ + data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + + DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data); + + /* We have link, so we need to finish the config process: + * 1) Set up the MAC to the current PHY speed/duplex + * if we are on 82543. If we + * are on newer silicon, we only need to configure + * collision distance in the Transmit Control Register. + * 2) Set up flow control on the MAC to that established with + * the link partner. + */ + if(shared->mac_type >= e1000_82544) + e1000_config_collision_dist(shared); + else + e1000_config_mac_to_phy(shared, data); + + e1000_config_fc_after_link_up(shared); + + DEBUGOUT("Valid link established!!!\n"); + } else { + DEBUGOUT("Unable to establish link!!!\n"); + } + + return (TRUE); +} + +/****************************************************************************** +* Configures PHY autoneg and flow control advertisement settings +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +boolean_t +e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared) +{ + uint16_t mii_autoneg_adv_reg; + uint16_t mii_1000t_ctrl_reg; + + DEBUGFUNC("e1000_phy_setup_autoneg"); + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV); + + /* Read the MII 1000Base-T Control Register (Address 9). */ + mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL); + + /* Need to parse both autoneg_advertised and fc and set up + * the appropriate PHY registers. First we will parse for + * autoneg_advertised software override. Since we can advertise + * a plethora of combinations, we need to check each bit + * individually. + */ + + /* First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). + */ + mii_autoneg_adv_reg &= ~REG4_SPEED_MASK; + mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK; + + DEBUGOUT1("autoneg_advertised %x\n", shared->autoneg_advertised); + + /* Do we want to advertise 10 Mb Half Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_10_HALF) { + DEBUGOUT("Advertise 10mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; + } + + /* Do we want to advertise 10 Mb Full Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_10_FULL) { + DEBUGOUT("Advertise 10mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; + } + + /* Do we want to advertise 100 Mb Half Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_100_HALF) { + DEBUGOUT("Advertise 100mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; + } + + /* Do we want to advertise 100 Mb Full Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_100_FULL) { + DEBUGOUT("Advertise 100mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; + } + + /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ + if(shared->autoneg_advertised & ADVERTISE_1000_HALF) { + DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n"); + } + + /* Do we want to advertise 1000 Mb Full Duplex? */ + if(shared->autoneg_advertised & ADVERTISE_1000_FULL) { + DEBUGOUT("Advertise 1000mb Full duplex\n"); + mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; + } + + /* Check for a software override of the flow control settings, and + * setup the PHY advertisement registers accordingly. If + * auto-negotiation is enabled, then software will have to set the + * "PAUSE" bits to the correct value in the Auto-Negotiation + * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (shared->fc) { + case e1000_fc_none: /* 0 */ + /* Flow control (RX & TX) is completely disabled by a + * software over-ride. + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_rx_pause: /* 1 */ + /* RX Flow control is enabled, and TX Flow control is + * disabled, by a software over-ride. + */ + + /* Since there really isn't a way to advertise that we are + * capable of RX Pause ONLY, we will advertise that we + * support both symmetric and asymmetric RX PAUSE. Later + * (in e1000_config_fc_after_link_up) we will disable the + *shared's ability to send PAUSE frames. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_tx_pause: /* 2 */ + /* TX Flow control is enabled, and RX Flow control is + * disabled, by a software over-ride. + */ + mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; + mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; + break; + case e1000_fc_full: /* 3 */ + /* Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + default: + /* We should never get here. The value should be 0-3. */ + DEBUGOUT("Flow control param set incorrectly\n"); + ASSERT(0); + break; + } + + /* Write the MII Auto-Neg Advertisement Register (Address 4). */ + e1000_write_phy_reg(shared, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); + + DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); + + /* Write the MII 1000Base-T Control Register (Address 9). */ + e1000_write_phy_reg(shared, PHY_1000T_CTRL, mii_1000t_ctrl_reg); + return (TRUE); +} + +/****************************************************************************** +* Sets MAC speed and duplex settings to reflect the those in the PHY +* +* shared - Struct containing variables accessed by shared code +* mii_reg - data to write to the MII control register +* +* The contents of the PHY register containing the needed information need to +* be passed in. +******************************************************************************/ +void +e1000_config_mac_to_phy(struct e1000_shared_adapter *shared, + uint16_t mii_reg) +{ + uint32_t ctrl_reg; + uint32_t tctl_reg; + uint32_t shift; + + DEBUGFUNC("e1000_config_mac_to_phy"); + + /* We need to read the Transmit Control register to configure the + * collision distance. + * Note: This must be done for both Half or Full Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + DEBUGOUT1("tctl_reg = %x\n", tctl_reg); + + /* Read the Device Control Register and set the bits to Force Speed + * and Duplex. + */ + ctrl_reg = E1000_READ_REG(shared, CTRL); + + ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ctrl_reg &= ~(DEVICE_SPEED_MASK); + + DEBUGOUT1("MII Register Data = %x\r\n", mii_reg); + + /* Clear the ILOS bit. */ + ctrl_reg &= ~E1000_CTRL_ILOS; + + /* Set up duplex in the Device Control and Transmit Control + * registers depending on negotiated values. + */ + if(mii_reg & M88E1000_PSSR_DPLX) { + ctrl_reg |= E1000_CTRL_FD; + + /* We are in Full Duplex mode. We have the same collision + * distance regardless of speed. + */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_FDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } else { + ctrl_reg &= ~E1000_CTRL_FD; + + /* We are in Half Duplex mode. Our Half Duplex collision + * distance is different for Gigabit than for 10/100 so we will + * set accordingly. + */ + if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { + /* 1000Mbs HDX */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_GB_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */ + } else { + /* 10/100Mbs HDX */ + tctl_reg &= ~E1000_TCTL_COLD; + shift = E1000_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } + } + + /* Set up speed in the Device Control register depending on + * negotiated values. + */ + if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) + ctrl_reg |= E1000_CTRL_SPD_1000; + else if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) + ctrl_reg |= E1000_CTRL_SPD_100; + else + ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + + /* Write the configured values back to the Transmit Control Reg. */ + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + /* Write the configured values back to the Device Control Reg. */ + E1000_WRITE_REG(shared, CTRL, ctrl_reg); + + return; +} + +/****************************************************************************** +* Sets the collision distance in the Transmit Control register +* +* shared - Struct containing variables accessed by shared code +* +* Link should have been established previously. Reads the speed and duplex +* information from the Device Status register. +******************************************************************************/ +void +e1000_config_collision_dist(struct e1000_shared_adapter *shared) +{ + uint32_t tctl_reg; + uint16_t speed; + uint16_t duplex; + uint32_t shift; + + DEBUGFUNC("e1000_config_collision_dist"); + + /* Get our current speed and duplex from the Device Status Register. */ + e1000_get_speed_and_duplex(shared, &speed, &duplex); + + /* We need to configure the Collision Distance for both Full or + * Half Duplex. + */ + tctl_reg = E1000_READ_REG(shared, TCTL); + DEBUGOUT1("tctl_reg = %x\n", tctl_reg); + + /* mask the Collision Distance bits in the Transmit Control Reg. */ + tctl_reg &= ~E1000_TCTL_COLD; + + if(duplex == FULL_DUPLEX) { + /* We are in Full Duplex mode. Therefore, the collision distance + * is the same regardless of speed. + */ + shift = E1000_FDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } else { + /* We are in Half Duplex mode. Half Duplex collision distance is + * different for Gigabit vs. 10/100, so we will set accordingly. + */ + if(speed == SPEED_1000) { /* 1000Mbs HDX */ + shift = E1000_GB_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */ + } else { /* 10/100Mbs HDX */ + shift = E1000_HDX_COLLISION_DISTANCE; + shift <<= E1000_COLD_SHIFT; + tctl_reg |= shift; + } + } + + /* Write the configured values back to the Transmit Control Reg. */ + E1000_WRITE_REG(shared, TCTL, tctl_reg); + + return; +} + +/****************************************************************************** +* Probes the expected PHY address for known PHY IDs +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +boolean_t +e1000_detect_gig_phy(struct e1000_shared_adapter *shared) +{ + uint32_t phy_id_high; + uint16_t phy_id_low; + + DEBUGFUNC("e1000_detect_gig_phy"); + + /* Read the PHY ID Registers to identify which PHY is onboard. */ + shared->phy_addr = 1; + + phy_id_high = e1000_read_phy_reg(shared, PHY_ID1); + + usec_delay(2); + + phy_id_low = e1000_read_phy_reg(shared, PHY_ID2); + + shared->phy_id = (phy_id_low | (phy_id_high << 16)) & PHY_REVISION_MASK; + + if(shared->phy_id == M88E1000_12_PHY_ID || + shared->phy_id == M88E1000_14_PHY_ID || + shared->phy_id == M88E1000_I_PHY_ID) { + + DEBUGOUT2("phy_id 0x%x detected at address 0x%x\n", + shared->phy_id, shared->phy_addr); + return (TRUE); + } else { + DEBUGOUT("Could not auto-detect Phy!\n"); + return (FALSE); + } +} + +/****************************************************************************** +* Resets the PHY's DSP +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +void +e1000_phy_reset_dsp(struct e1000_shared_adapter *shared) +{ + e1000_write_phy_reg(shared, 29, 0x1d); + e1000_write_phy_reg(shared, 30, 0xc1); + e1000_write_phy_reg(shared, 30, 0x00); + return; +} + +/****************************************************************************** +* Blocks until autoneg completes or times out (~4.5 seconds) +* +* shared - Struct containing variables accessed by shared code +******************************************************************************/ +boolean_t +e1000_wait_autoneg(struct e1000_shared_adapter *shared) +{ + uint16_t i; + uint16_t mii_status_reg; + boolean_t autoneg_complete = FALSE; + + DEBUGFUNC("e1000_wait_autoneg"); + + /* We will wait for autoneg to complete. */ + DEBUGOUT("Waiting for Auto-Neg to complete.\n"); + mii_status_reg = 0; + + /* We will wait for autoneg to complete or 4.5 seconds to expire. */ + + for(i = PHY_AUTO_NEG_TIME; i > 0; i--) { + /* Read the MII Status Register and wait for Auto-Neg + * Complete bit to be set. + */ + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + + if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) { + autoneg_complete = TRUE; + break; + } + + msec_delay(100); + } + + return (autoneg_complete); +} + +/****************************************************************************** +* Get PHY information from various PHY registers +* +* shared - Struct containing variables accessed by shared code +* phy_status_info - PHY information structure +******************************************************************************/ +boolean_t +e1000_phy_get_info(struct e1000_shared_adapter *shared, + struct e1000_phy_info *phy_status_info) +{ + uint16_t phy_mii_status_reg; + uint16_t phy_specific_ctrl_reg; + uint16_t phy_specific_status_reg; + uint16_t phy_specific_ext_ctrl_reg; + uint16_t phy_1000t_stat_reg; + + phy_status_info->cable_length = e1000_cable_length_undefined; + phy_status_info->extended_10bt_distance = + e1000_10bt_ext_dist_enable_undefined; + phy_status_info->cable_polarity = e1000_rev_polarity_undefined; + phy_status_info->polarity_correction = e1000_polarity_reversal_undefined; + phy_status_info->link_reset = e1000_down_no_idle_undefined; + phy_status_info->mdix_mode = e1000_auto_x_mode_undefined; + phy_status_info->local_rx = e1000_1000t_rx_status_undefined; + phy_status_info->remote_rx = e1000_1000t_rx_status_undefined; + + /* PHY info only valid for copper media. */ + if(shared == NULL || shared->media_type != e1000_media_type_copper) + return FALSE; + + /* PHY info only valid for LINK UP. Read MII status reg + * back-to-back to get link status. + */ + phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS); + if((phy_mii_status_reg & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) + return FALSE; + + /* Read various PHY registers to get the PHY info. */ + phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL); + phy_specific_status_reg = + e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS); + phy_specific_ext_ctrl_reg = + e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL); + phy_1000t_stat_reg = e1000_read_phy_reg(shared, PHY_1000T_STATUS); + + phy_status_info->cable_length = + ((phy_specific_status_reg & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT); + + phy_status_info->extended_10bt_distance = + (phy_specific_ctrl_reg & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >> + M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT; + + phy_status_info->cable_polarity = + (phy_specific_status_reg & M88E1000_PSSR_REV_POLARITY) >> + M88E1000_PSSR_REV_POLARITY_SHIFT; + + phy_status_info->polarity_correction = + (phy_specific_ctrl_reg & M88E1000_PSCR_POLARITY_REVERSAL) >> + M88E1000_PSCR_POLARITY_REVERSAL_SHIFT; + + phy_status_info->link_reset = + (phy_specific_ext_ctrl_reg & M88E1000_EPSCR_DOWN_NO_IDLE) >> + M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT; + + phy_status_info->mdix_mode = + (phy_specific_status_reg & M88E1000_PSSR_MDIX) >> + M88E1000_PSSR_MDIX_SHIFT; + + phy_status_info->local_rx = + (phy_1000t_stat_reg & SR_1000T_LOCAL_RX_STATUS) >> + SR_1000T_LOCAL_RX_STATUS_SHIFT; + + phy_status_info->remote_rx = + (phy_1000t_stat_reg & SR_1000T_REMOTE_RX_STATUS) >> + SR_1000T_REMOTE_RX_STATUS_SHIFT; + + return TRUE; +} + +boolean_t +e1000_validate_mdi_setting(struct e1000_shared_adapter *shared) +{ + if(!shared->autoneg && (shared->mdix == 0 || shared->mdix == 3)) { + shared->mdix = 1; + return FALSE; + } + return TRUE; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/e1000/e1000_phy.h linux-2.5/drivers/net/e1000/e1000_phy.h --- linux-2.5.5/drivers/net/e1000/e1000_phy.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/e1000/e1000_phy.h Tue Feb 26 21:24:49 2002 @@ -0,0 +1,422 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* e1000_phy.h + * Structures, enums, and macros for the PHY + */ + +#ifndef _E1000_PHY_H_ +#define _E1000_PHY_H_ + +#include "e1000_osdep.h" + +/* PHY status info structure and supporting enums */ +typedef enum { + e1000_cable_length_50 = 0, + e1000_cable_length_50_80, + e1000_cable_length_80_110, + e1000_cable_length_110_140, + e1000_cable_length_140, + e1000_cable_length_undefined = 0xFF +} e1000_cable_length; + +typedef enum { + e1000_10bt_ext_dist_enable_normal = 0, + e1000_10bt_ext_dist_enable_lower, + e1000_10bt_ext_dist_enable_undefined = 0xFF +} e1000_10bt_ext_dist_enable; + +typedef enum { + e1000_rev_polarity_normal = 0, + e1000_rev_polarity_reversed, + e1000_rev_polarity_undefined = 0xFF +} e1000_rev_polarity; + +typedef enum { + e1000_polarity_reversal_enabled = 0, + e1000_polarity_reversal_disabled, + e1000_polarity_reversal_undefined = 0xFF +} e1000_polarity_reversal; + +typedef enum { + e1000_down_no_idle_no_detect = 0, + e1000_down_no_idle_detect, + e1000_down_no_idle_undefined = 0xFF +} e1000_down_no_idle; + +typedef enum { + e1000_auto_x_mode_manual_mdi = 0, + e1000_auto_x_mode_manual_mdix, + e1000_auto_x_mode_auto1, + e1000_auto_x_mode_auto2, + e1000_auto_x_mode_undefined = 0xFF +} e1000_auto_x_mode; + +typedef enum { + e1000_1000t_rx_status_not_ok = 0, + e1000_1000t_rx_status_ok, + e1000_1000t_rx_status_undefined = 0xFF +} e1000_1000t_rx_status; + +struct e1000_phy_info { + e1000_cable_length cable_length; + e1000_10bt_ext_dist_enable extended_10bt_distance; + e1000_rev_polarity cable_polarity; + e1000_polarity_reversal polarity_correction; + e1000_down_no_idle link_reset; + e1000_auto_x_mode mdix_mode; + e1000_1000t_rx_status local_rx; + e1000_1000t_rx_status remote_rx; +}; + +struct e1000_phy_stats { + uint32_t idle_errors; + uint32_t receive_errors; +}; + +/* Function Prototypes */ +uint16_t e1000_read_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr); +void e1000_write_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr, uint16_t data); +void e1000_phy_hw_reset(struct e1000_shared_adapter *shared); +boolean_t e1000_phy_reset(struct e1000_shared_adapter *shared); +boolean_t e1000_phy_setup(struct e1000_shared_adapter *shared, uint32_t ctrl_reg); +boolean_t e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared); +void e1000_config_mac_to_phy(struct e1000_shared_adapter *shared, uint16_t mii_reg); +void e1000_config_collision_dist(struct e1000_shared_adapter *shared); +boolean_t e1000_detect_gig_phy(struct e1000_shared_adapter *shared); +void e1000_phy_reset_dsp(struct e1000_shared_adapter *shared); +boolean_t e1000_wait_autoneg(struct e1000_shared_adapter *shared); +boolean_t e1000_phy_get_info(struct e1000_shared_adapter *shared, struct e1000_phy_info *phy_status_info); +boolean_t e1000_validate_mdi_setting(struct e1000_shared_adapter *shared); + +/* Bit definitions for the Management Data IO (MDIO) and Management Data + * Clock (MDC) pins in the Device Control Register. + */ +#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0 +#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0 +#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2 +#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2 +#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3 +#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3 +#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR +#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA + +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ +#define PHY_CTRL 0x00 /* Control Register */ +#define PHY_STATUS 0x01 /* Status Regiser */ +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ +#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ +#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */ +#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ +#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ + +/* M88E1000 Specific Registers */ +#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ +#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ +#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */ +#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */ +#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ +#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ + +#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ + +/* PHY Control Register */ +#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ + +/* PHY Status Register */ +#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ +#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ + +/* Autoneg Advertisement Register */ +#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ +#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ +#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ +#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ +#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ +#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ + +/* Link Partner Ability Register (Base Page) */ +#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */ +#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */ +#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */ +#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */ +#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */ +#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */ +#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ +#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ +#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */ +#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */ +#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */ + +/* Autoneg Expansion Register */ +#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */ +#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */ +#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */ +#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ +#define NWAY_ER_PAR_DETECT_FAULT 0x0100 /* LP is 100TX Full Duplex Capable */ + +/* Next Page TX Register */ +#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges + * of different NP + */ +#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg + * 0 = cannot comply with msg + */ +#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ +#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow + * 0 = sending last NP + */ + +/* Link Partner Next Page Register */ +#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges + * of different NP + */ +#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg + * 0 = cannot comply with msg + */ +#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ +#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */ +#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow + * 0 = sending last NP + */ + +/* 1000BASE-T Control Register */ +#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ +#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ +#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */ + /* 0=DTE device */ +#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ + /* 0=Configure PHY as Slave */ +#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ + /* 0=Automatic Master/Slave config */ +#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ +#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ +#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ +#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ +#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ + +/* 1000BASE-T Status Register */ +#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */ +#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */ +#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ +#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ +#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ +#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */ +#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ +#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12 +#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13 + +/* Extended Status Register */ +#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ +#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ +#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ +#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ + +#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */ +#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */ + +#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */ + /* (0=enable, 1=disable) */ + +/* M88E1000 PHY Specific Control Register */ +#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ +#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ +#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, + * 0=CLK125 toggling + */ +#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ + /* Manual MDI configuration */ +#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ +#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, + * 100BASE-TX/10BASE-T: + * MDI Mode + */ +#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled + * all speeds. + */ +#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 + /* 1=Enable Extended 10BASE-T distance + * (Lower 10BASE-T RX Threshold) + * 0=Normal 10BASE-T RX Threshold */ +#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100 + /* 1=5-Bit interface in 100BASE-TX + * 0=MII interface in 100BASE-TX */ +#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ +#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ +#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ + +#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT 1 +#define M88E1000_PSCR_AUTO_X_MODE_SHIFT 5 +#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7 + +/* M88E1000 PHY Specific Status Register */ +#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */ +#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ +#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ +#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M; + * 3=110-140M;4=>140M */ +#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */ +#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ +#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */ +#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ +#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ +#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */ +#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */ +#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ + +#define M88E1000_PSSR_REV_POLARITY_SHIFT 1 +#define M88E1000_PSSR_MDIX_SHIFT 6 +#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 + +/* M88E1000 Extended PHY Specific Control Register */ +#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */ +#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 /* 1=Lost lock detect enabled. + * Will assert lost lock and bring + * link down if idle not seen + * within 1ms in 1000BASE-T + */ +#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */ +#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ +#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ + +#define M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT 15 + +/* Bit definitions for valid PHY IDs. */ +#define M88E1000_12_PHY_ID 0x01410C50 +#define M88E1000_14_PHY_ID 0x01410C40 +#define M88E1000_I_PHY_ID 0x01410C30 + +/* Miscellaneous PHY bit definitions. */ +#define PHY_PREAMBLE 0xFFFFFFFF +#define PHY_SOF 0x01 +#define PHY_OP_READ 0x02 +#define PHY_OP_WRITE 0x01 +#define PHY_TURNAROUND 0x02 +#define PHY_PREAMBLE_SIZE 32 +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 +#define E1000_PHY_ADDRESS 0x01 +#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */ +#define PHY_FORCE_TIME 20 /* 2.0 Seconds */ +#define PHY_REVISION_MASK 0xFFFFFFF0 +#define DEVICE_SPEED_MASK 0x00000300 /* Device Ctrl Reg Speed Mask */ +#define REG4_SPEED_MASK 0x01E0 +#define REG9_SPEED_MASK 0x0300 +#define ADVERTISE_10_HALF 0x0001 +#define ADVERTISE_10_FULL 0x0002 +#define ADVERTISE_100_HALF 0x0004 +#define ADVERTISE_100_FULL 0x0008 +#define ADVERTISE_1000_HALF 0x0010 +#define ADVERTISE_1000_FULL 0x0020 +#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */ + +#endif /* _E1000_PHY_H_ */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/e1000/e1000_proc.c linux-2.5/drivers/net/e1000/e1000_proc.c --- linux-2.5.5/drivers/net/e1000/e1000_proc.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/e1000/e1000_proc.c Tue Feb 26 21:24:49 2002 @@ -0,0 +1,760 @@ +/******************************************************************************* + + This software program is available to you under a choice of one of two + licenses. You may choose to be licensed under either the GNU General Public + License (GPL) Version 2, June 1991, available at + http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the + text of which follows: + + Recipient has requested a license and Intel Corporation ("Intel") is willing + to grant a license for the software entitled Linux Base Driver for the + Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided + by Intel Corporation. The following definitions apply to this license: + + "Licensed Patents" means patent claims licensable by Intel Corporation which + are necessarily infringed by the use of sale of the Software alone or when + combined with the operating system referred to below. + + "Recipient" means the party to whom Intel delivers this Software. + + "Licensee" means Recipient and those third parties that receive a license to + any operating system available under the GNU Public License version 2.0 or + later. + + Copyright (c) 1999 - 2002 Intel Corporation. + All rights reserved. + + The license is provided to Recipient and Recipient's Licensees under the + following terms. + + Redistribution and use in source and binary forms of the Software, with or + without modification, are permitted provided that the following conditions + are met: + + Redistributions of source code of the Software may retain the above + copyright notice, this list of conditions and the following disclaimer. + + Redistributions in binary form of the Software may reproduce the above + copyright notice, this list of conditions and the following disclaimer in + the documentation and/or materials provided with the distribution. + + Neither the name of Intel Corporation nor the names of its contributors + shall be used to endorse or promote products derived from this Software + without specific prior written permission. + + Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, + royalty-free patent license under Licensed Patents to make, use, sell, offer + to sell, import and otherwise transfer the Software, if any, in source code + and object code form. This license shall include changes to the Software + that are error corrections or other minor changes to the Software that do + not add functionality or features when the Software is incorporated in any + version of an operating system that has been distributed under the GNU + General Public License 2.0 or later. This patent license shall apply to the + combination of the Software and any operating system licensed under the GNU + Public License version 2.0 or later if, at the time Intel provides the + Software to Recipient, such addition of the Software to the then publicly + available versions of such operating systems available under the GNU Public + License version 2.0 or later (whether in gold, beta or alpha form) causes + such combination to be covered by the Licensed Patents. The patent license + shall not apply to any other combinations which include the Software. NO + hardware per se is licensed hereunder. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/* + * Proc fs support. + * + * Read-only files created by driver (if CONFIG_PROC_FS): + * + * /proc/net/PRO_LAN_Adapters/.info + * /proc/net/PRO_LAN_Adapters// + * + * where is the system device name, i.e eth0. + * is the driver attribute name. + * + * There is one file for each driver attribute, where the contents + * of the file is the attribute value. The ethx.info file contains + * a list of all driver attributes in one file. + * + */ + +#include "e1000.h" + +#ifdef CONFIG_PROC_FS + +#include + +#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters" +#define TAG_MAX_LENGTH 36 + +extern char e1000_driver_name[]; +extern char e1000_driver_version[]; + +/* + * The list of driver proc attributes is stored in a proc_list link + * list. The list is build with proc_list_setup and is used to + * build the proc fs nodes. The private data for each node is the + * corresponding link in the link list. + */ + +struct proc_list { + struct list_head list; /* link list */ + char tag[TAG_MAX_LENGTH]; /* attribute name */ + void *data; /* attribute data */ + size_t len; /* sizeof data */ + char *(*func)(void *, size_t, char *); /* format data func */ +}; + +static int +e1000_proc_read(char *page, char **start, off_t off, int count, int *eof) +{ + int len = strlen(page); + + page[len++] = '\n'; + + if(len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if(len > count) + len = count; + if(len < 0) + len = 0; + + return len; +} + +static int +e1000_proc_info_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct list_head *proc_list_head = data, *curr; + struct proc_list *elem; + char *p = page; + char buf[64]; + + list_for_each(curr, proc_list_head) { + elem = list_entry(curr, struct proc_list, list); + + if(strlen(elem->tag) == 0) + p += sprintf(p, "\n"); + else + p += sprintf(p, "%-32s %s\n", elem->tag, + elem->func(elem->data, elem->len, buf)); + } + + *p = '\0'; + + return e1000_proc_read(page, start, off, count, eof); +} + +static int +e1000_proc_single_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct proc_list *elem = data; + + sprintf(page, "%s", elem->func(elem->data, elem->len, page)); + + return e1000_proc_read(page, start, off, count, eof); +} + +static void __devexit +e1000_proc_dirs_free(char *name, struct list_head *proc_list_head) +{ + struct proc_dir_entry *intel_proc_dir, *proc_dir; + char info_name[strlen(name) + strlen(".info")]; + + for(intel_proc_dir = proc_net->subdir; intel_proc_dir; + intel_proc_dir = intel_proc_dir->next) { + if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) && + (memcmp(intel_proc_dir->name, + ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)) == 0)) + break; + } + + if(!intel_proc_dir) + return; + + for(proc_dir = intel_proc_dir->subdir; proc_dir; + proc_dir = proc_dir->next) { + if ((proc_dir->namelen == strlen(name)) && + !memcmp(proc_dir->name, name, strlen(name))) + break; + } + + if(proc_dir) { + struct list_head *curr; + struct proc_list *elem; + + list_for_each(curr, proc_list_head) { + elem = list_entry(curr, struct proc_list, list); + remove_proc_entry(elem->tag, proc_dir); + } + + strcpy(info_name, name); + strcat(info_name, ".info"); + + remove_proc_entry(info_name, intel_proc_dir); + remove_proc_entry(name, intel_proc_dir); + } + + /* If the intel dir is empty, remove it */ + + for(proc_dir = intel_proc_dir->subdir; proc_dir; + proc_dir = proc_dir->next) { + + /* ignore . and .. */ + + if(*(proc_dir->name) == '.') + continue; + break; + } + + if(!proc_dir) + remove_proc_entry(ADAPTERS_PROC_DIR, proc_net); + + return; +} + + +static int __devinit +e1000_proc_singles_create(struct proc_dir_entry *parent, + struct list_head *proc_list_head) +{ + struct list_head *curr; + struct proc_list *elem; + + list_for_each(curr, proc_list_head) { + struct proc_dir_entry *proc_entry; + + elem = list_entry(curr, struct proc_list, list); + + if(strlen(elem->tag) == 0) + continue; + + if(!(proc_entry = + create_proc_entry(elem->tag, S_IFREG, parent))) + return 0; + + proc_entry->read_proc = e1000_proc_single_read; + proc_entry->data = elem; + SET_MODULE_OWNER(proc_entry); + } + + return 1; +} + +static int __devinit +e1000_proc_dirs_create(char *name, struct list_head *proc_list_head) +{ + struct proc_dir_entry *intel_proc_dir, *proc_dir, *info_entry; + char info_name[strlen(name) + strlen(".info")]; + + for(intel_proc_dir = proc_net->subdir; intel_proc_dir; + intel_proc_dir = intel_proc_dir->next) { + if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) && + (memcmp(intel_proc_dir->name, + ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)) == 0)) + break; + } + + if(!intel_proc_dir) + if(!(intel_proc_dir = + create_proc_entry(ADAPTERS_PROC_DIR, + S_IFDIR, proc_net))) + return 0; + + if(!(proc_dir = + create_proc_entry(name, S_IFDIR, intel_proc_dir))) + return 0; + SET_MODULE_OWNER(proc_dir); + + if(!e1000_proc_singles_create(proc_dir, proc_list_head)) + return 0; + + strcpy(info_name, name); + strcat(info_name, ".info"); + + if(!(info_entry = + create_proc_entry(info_name, S_IFREG, intel_proc_dir))) + return 0; + SET_MODULE_OWNER(info_entry); + + info_entry->read_proc = e1000_proc_info_read; + info_entry->data = proc_list_head; + + return 1; +} + +static void __devinit +e1000_proc_list_add(struct list_head *proc_list_head, char *tag, + void *data, size_t len, + char *(*func)(void *, size_t, char *)) +{ + struct proc_list *new = (struct proc_list *) + kmalloc(sizeof(struct proc_list), GFP_KERNEL); + + if(!new) + return; + + strncpy(new->tag, tag, TAG_MAX_LENGTH); + new->data = data; + new->len = len; + new->func = func; + + list_add_tail(&new->list, proc_list_head); + + return; +} + +static void __devexit +e1000_proc_list_free(struct list_head *proc_list_head) +{ + struct proc_list *elem; + + while(!list_empty(proc_list_head)) { + elem = list_entry(proc_list_head->next, struct proc_list, list); + list_del(&elem->list); + kfree(elem); + } + + return; +} + +/* + * General purpose formating functions + */ + +static char * +e1000_proc_str(void *data, size_t len, char *buf) +{ + sprintf(buf, "%s", (char *)data); + return buf; +} + +static char * +e1000_proc_hex(void *data, size_t len, char *buf) +{ + switch(len) { + case sizeof(uint8_t): + sprintf(buf, "0x%02x", *(uint8_t *)data); + break; + case sizeof(uint16_t): + sprintf(buf, "0x%04x", *(uint16_t *)data); + break; + case sizeof(uint32_t): + sprintf(buf, "0x%08x", *(uint32_t *)data); + break; + case sizeof(uint64_t): + sprintf(buf, "0x%08Lx", (unsigned long long)*(uint64_t *)data); + break; + } + return buf; +} + +static char * +e1000_proc_unsigned(void *data, size_t len, char *buf) +{ + switch(len) { + case sizeof(uint8_t): + sprintf(buf, "%u", *(uint8_t *)data); + break; + case sizeof(uint16_t): + sprintf(buf, "%u", *(uint16_t *)data); + break; + case sizeof(uint32_t): + sprintf(buf, "%u", *(uint32_t *)data); + break; + case sizeof(uint64_t): + sprintf(buf, "%Lu", (unsigned long long)*(uint64_t *)data); + break; + } + return buf; +} + +/* + * Specific formating functions + */ + +static char * +e1000_proc_part_number(void *data, size_t len, char *buf) +{ + sprintf(buf, "%06x-%03x", *(uint32_t *)data >> 8, + *(uint32_t *)data & 0x000000FF); + return buf; +} + +static char * +e1000_proc_slot(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + sprintf(buf, "%u", PCI_SLOT(adapter->pdev->devfn)); + return buf; +} + +static char * +e1000_proc_bus_type(void *data, size_t len, char *buf) +{ + e1000_bus_type bus_type = *(e1000_bus_type *)data; + sprintf(buf, + bus_type == e1000_bus_type_pci ? "PCI" : + bus_type == e1000_bus_type_pcix ? "PCI-X" : + "UNKNOWN"); + return buf; +} + +static char * +e1000_proc_bus_speed(void *data, size_t len, char *buf) +{ + e1000_bus_speed bus_speed = *(e1000_bus_speed *)data; + sprintf(buf, + bus_speed == e1000_bus_speed_33 ? "33MHz" : + bus_speed == e1000_bus_speed_66 ? "66MHz" : + bus_speed == e1000_bus_speed_100 ? "100MHz" : + bus_speed == e1000_bus_speed_133 ? "133MHz" : + "UNKNOWN"); + return buf; +} + +static char * +e1000_proc_bus_width(void *data, size_t len, char *buf) +{ + e1000_bus_width bus_width = *(e1000_bus_width *)data; + sprintf(buf, + bus_width == e1000_bus_width_32 ? "32-bit" : + bus_width == e1000_bus_width_64 ? "64-bit" : + "UNKNOWN"); + return buf; +} + +static char * +e1000_proc_hwaddr(void *data, size_t len, char *buf) +{ + unsigned char *hwaddr = data; + sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + hwaddr[0], hwaddr[1], hwaddr[2], + hwaddr[3], hwaddr[4], hwaddr[5]); + return buf; +} + +static char * +e1000_proc_link(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + sprintf(buf, netif_running(adapter->netdev) ? + netif_carrier_ok(adapter->netdev) ? + "up" : "down" : "N/A"); + return buf; +} + +static char * +e1000_proc_link_speed(void *data, size_t len, char *buf) +{ + uint16_t link_speed = *(uint16_t *)data; + sprintf(buf, link_speed ? "%u" : "N/A", link_speed); + return buf; +} + +static char * +e1000_proc_link_duplex(void *data, size_t len, char *buf) +{ + uint16_t link_duplex = *(uint16_t *)data; + sprintf(buf, + link_duplex == FULL_DUPLEX ? "Full" : + link_duplex == HALF_DUPLEX ? "Half" : + "N/A"); + return buf; +} + +static char * +e1000_proc_state(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + sprintf(buf, adapter->netdev->flags & IFF_UP ? "up" : "down"); + return buf; +} + +static char * +e1000_proc_media_type(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + sprintf(buf, + adapter->shared.media_type == e1000_media_type_copper ? + "Copper" : "Fiber"); + return buf; +} + +static char * +e1000_proc_cable_length(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_cable_length cable_length = adapter->phy_info.cable_length; + sprintf(buf, "%s%s", + cable_length == e1000_cable_length_50 ? "0-50" : + cable_length == e1000_cable_length_50_80 ? "50-80" : + cable_length == e1000_cable_length_80_110 ? "80-110" : + cable_length == e1000_cable_length_110_140 ? "110-140" : + cable_length == e1000_cable_length_140 ? "> 140" : + "Unknown", + cable_length != e1000_cable_length_undefined ? + " Meters (+/- 20 Meters)" : ""); + return buf; +} + +static char * +e1000_proc_extended(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_10bt_ext_dist_enable dist_enable = + adapter->phy_info.extended_10bt_distance; + sprintf(buf, + dist_enable == e1000_10bt_ext_dist_enable_normal ? "Disabled" : + dist_enable == e1000_10bt_ext_dist_enable_lower ? "Enabled" : + "Unknown"); + return buf; +} + +static char * +e1000_proc_cable_polarity(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_rev_polarity polarity = adapter->phy_info.cable_polarity; + sprintf(buf, + polarity == e1000_rev_polarity_normal ? "Normal" : + polarity == e1000_rev_polarity_reversed ? "Reversed" : + "Unknown"); + return buf; +} + +static char * +e1000_proc_polarity_correction(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_polarity_reversal correction = + adapter->phy_info.polarity_correction; + sprintf(buf, + correction == e1000_polarity_reversal_enabled ? "Disabled" : + correction == e1000_polarity_reversal_disabled ? "Enabled" : + "Undefined"); + return buf; +} + +static char * +e1000_proc_link_reset_enabled(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_down_no_idle link_reset = adapter->phy_info.link_reset; + sprintf(buf, + link_reset == e1000_down_no_idle_no_detect ? "Disabled" : + link_reset == e1000_down_no_idle_detect ? "Enabled" : + "Unknown"); + return buf; +} + +static char * +e1000_proc_mdi_x_enabled(void *data, size_t len, char *buf) +{ + struct e1000_adapter *adapter = data; + e1000_auto_x_mode mdix_mode = adapter->phy_info.mdix_mode; + sprintf(buf, mdix_mode == 0 ? "MDI" : "MDI-X"); + return buf; +} + +static char * +e1000_proc_rx_status(void *data, size_t len, char *buf) +{ + e1000_1000t_rx_status rx_status = *(e1000_1000t_rx_status *)data; + sprintf(buf, + rx_status == e1000_1000t_rx_status_not_ok ? "NOT_OK" : + rx_status == e1000_1000t_rx_status_ok ? "OK" : + "Unknown"); + return buf; +} + +/* + * e1000_proc_list_setup - build link list of proc praramters + * @adapter: board private structure + * + * Order matters - ethx.info entries are ordered in the order links + * are added to list. + */ + +#define LIST_ADD_F(T,D,F) \ + e1000_proc_list_add(proc_list_head, (T), (D), sizeof(*(D)), (F)) +#define LIST_ADD_BLANK() LIST_ADD_F("", NULL, NULL) +#define LIST_ADD_S(T,D) LIST_ADD_F((T), (D), e1000_proc_str) +#define LIST_ADD_H(T,D) LIST_ADD_F((T), (D), e1000_proc_hex) +#define LIST_ADD_U(T,D) LIST_ADD_F((T), (D), e1000_proc_unsigned) + +static void __devinit +e1000_proc_list_setup(struct e1000_adapter *adapter) +{ + struct e1000_shared_adapter *shared = &adapter->shared; + struct list_head *proc_list_head = &adapter->proc_list_head; + + INIT_LIST_HEAD(proc_list_head); + + LIST_ADD_S("Description", adapter->id_string); + LIST_ADD_F("Part_Number", &adapter->part_num, e1000_proc_part_number); + LIST_ADD_S("Driver_Name", e1000_driver_name); + LIST_ADD_S("Driver_Version", e1000_driver_version); + LIST_ADD_H("PCI_Vendor", &shared->vendor_id); + LIST_ADD_H("PCI_Device_ID", &shared->device_id); + LIST_ADD_H("PCI_Subsystem_Vendor", &shared->subsystem_vendor_id); + LIST_ADD_H("PCI_Subsystem_ID", &shared->subsystem_id); + LIST_ADD_H("PCI_Revision_ID", &shared->revision_id); + LIST_ADD_U("PCI_Bus", &adapter->pdev->bus->number); + LIST_ADD_F("PCI_Slot", adapter, e1000_proc_slot); + + if(adapter->shared.mac_type >= e1000_82543) { + LIST_ADD_F("PCI_Bus_Type", + &shared->bus_type, e1000_proc_bus_type); + LIST_ADD_F("PCI_Bus_Speed", + &shared->bus_speed, e1000_proc_bus_speed); + LIST_ADD_F("PCI_Bus_Width", + &shared->bus_width, e1000_proc_bus_width); + } + + LIST_ADD_U("IRQ", &adapter->pdev->irq); + LIST_ADD_S("System_Device_Name", adapter->netdev->name); + LIST_ADD_F("Current_HWaddr", + adapter->netdev->dev_addr, e1000_proc_hwaddr); + LIST_ADD_F("Permanent_HWaddr", + adapter->shared.perm_mac_addr, e1000_proc_hwaddr); + + LIST_ADD_BLANK(); + + LIST_ADD_F("Link", adapter, e1000_proc_link); + LIST_ADD_F("Speed", &adapter->link_speed, e1000_proc_link_speed); + LIST_ADD_F("Duplex", &adapter->link_duplex, e1000_proc_link_duplex); + LIST_ADD_F("State", adapter, e1000_proc_state); + + LIST_ADD_BLANK(); + + /* Standard net device stats */ + LIST_ADD_U("Rx_Packets", &adapter->net_stats.rx_packets); + LIST_ADD_U("Tx_Packets", &adapter->net_stats.tx_packets); + LIST_ADD_U("Rx_Bytes", &adapter->net_stats.rx_bytes); + LIST_ADD_U("Tx_Bytes", &adapter->net_stats.tx_bytes); + LIST_ADD_U("Rx_Errors", &adapter->net_stats.rx_errors); + LIST_ADD_U("Tx_Errors", &adapter->net_stats.tx_errors); + LIST_ADD_U("Rx_Dropped", &adapter->net_stats.rx_dropped); + LIST_ADD_U("Tx_Dropped", &adapter->net_stats.tx_dropped); + + LIST_ADD_U("Multicast", &adapter->net_stats.multicast); + LIST_ADD_U("Collisions", &adapter->net_stats.collisions); + + LIST_ADD_U("Rx_Length_Errors", &adapter->net_stats.rx_length_errors); + LIST_ADD_U("Rx_Over_Errors", &adapter->net_stats.rx_over_errors); + LIST_ADD_U("Rx_CRC_Errors", &adapter->net_stats.rx_crc_errors); + LIST_ADD_U("Rx_Frame_Errors", &adapter->net_stats.rx_frame_errors); + LIST_ADD_U("Rx_FIFO_Errors", &adapter->net_stats.rx_fifo_errors); + LIST_ADD_U("Rx_Missed_Errors", &adapter->net_stats.rx_missed_errors); + + LIST_ADD_U("Tx_Aborted_Errors", &adapter->net_stats.tx_aborted_errors); + LIST_ADD_U("Tx_Carrier_Errors", &adapter->net_stats.tx_carrier_errors); + LIST_ADD_U("Tx_FIFO_Errors", &adapter->net_stats.tx_fifo_errors); + LIST_ADD_U("Tx_Heartbeat_Errors", + &adapter->net_stats.tx_heartbeat_errors); + LIST_ADD_U("Tx_Window_Errors", &adapter->net_stats.tx_window_errors); + + /* 8254x-specific stats */ + LIST_ADD_U("Tx_Abort_Late_Coll", &adapter->stats.latecol); + LIST_ADD_U("Tx_Deferred_Ok", &adapter->stats.dc); + LIST_ADD_U("Tx_Single_Coll_Ok", &adapter->stats.scc); + LIST_ADD_U("Tx_Multi_Coll_Ok", &adapter->stats.mcc); + LIST_ADD_U("Rx_Long_Length_Errors", &adapter->stats.roc); + LIST_ADD_U("Rx_Short_Length_Errors", &adapter->stats.ruc); + + /* The 82542 does not have an alignment error count register */ + if(adapter->shared.mac_type >= e1000_82543) + LIST_ADD_U("Rx_Align_Errors", &adapter->stats.algnerrc); + + LIST_ADD_U("Rx_Flow_Control_XON", &adapter->stats.xonrxc); + LIST_ADD_U("Rx_Flow_Control_XOFF", &adapter->stats.xoffrxc); + LIST_ADD_U("Tx_Flow_Control_XON", &adapter->stats.xontxc); + LIST_ADD_U("Tx_Flow_Control_XOFF", &adapter->stats.xofftxc); + LIST_ADD_U("Rx_CSum_Offload_Good", &adapter->hw_csum_good); + LIST_ADD_U("Rx_CSum_Offload_Errors", &adapter->hw_csum_err); + + LIST_ADD_BLANK(); + + /* Cable diags */ + LIST_ADD_F("PHY_Media_Type", adapter, e1000_proc_media_type); + if(adapter->shared.media_type == e1000_media_type_copper) { + LIST_ADD_F("PHY_Cable_Length", + adapter, e1000_proc_cable_length); + LIST_ADD_F("PHY_Extended_10Base_T_Distance", + adapter, e1000_proc_extended); + LIST_ADD_F("PHY_Cable_Polarity", + adapter, e1000_proc_cable_polarity); + LIST_ADD_F("PHY_Disable_Polarity_Correction", + adapter, e1000_proc_polarity_correction); + LIST_ADD_U("PHY_Idle_Errors", + &adapter->phy_stats.idle_errors); + LIST_ADD_F("PHY_Link_Reset_Enabled", + adapter, e1000_proc_link_reset_enabled); + LIST_ADD_U("PHY_Receive_Errors", + &adapter->phy_stats.receive_errors); + LIST_ADD_F("PHY_MDI_X_Enabled", + adapter, e1000_proc_mdi_x_enabled); + LIST_ADD_F("PHY_Local_Receiver_Status", + &adapter->phy_info.local_rx, + e1000_proc_rx_status); + LIST_ADD_F("PHY_Remote_Receiver_Status", + &adapter->phy_info.remote_rx, + e1000_proc_rx_status); + } + + return; +} + +/* + * e1000_proc_dev_setup - create proc fs nodes and link list + * @adapter: board private structure + */ + +void __devinit +e1000_proc_dev_setup(struct e1000_adapter *adapter) +{ + e1000_proc_list_setup(adapter); + + e1000_proc_dirs_create(adapter->netdev->name,&adapter->proc_list_head); + + return; +} + +/* + * e1000_proc_dev_free - free proc fs nodes and link list + * @adapter: board private structure + */ + +void __devexit +e1000_proc_dev_free(struct e1000_adapter *adapter) +{ + e1000_proc_dirs_free(adapter->netdev->name, &adapter->proc_list_head); + + e1000_proc_list_free(&adapter->proc_list_head); + + return; +} + +#else /* CONFIG_PROC_FS */ + +void __devinit e1000_proc_dev_setup(struct e1000_adapter *adapter) {} +void __devexit e1000_proc_dev_free(struct e1000_adapter *adapter) {} + +#endif /* CONFIG_PROC_FS */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/eepro100.c linux-2.5/drivers/net/eepro100.c --- linux-2.5.5/drivers/net/eepro100.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/net/eepro100.c Sun Mar 3 20:15:15 2002 @@ -1377,7 +1377,7 @@ /* workaround for hardware bug on 10 mbit half duplex */ - if ((sp->partner == 0) || (sp->chip_id == 1)) { + if ((sp->partner==0) && (sp->chip_id==1)) { wait_for_cmd_done(ioaddr + SCBCmd); outb(0 , ioaddr + SCBCmd); } @@ -1791,6 +1791,7 @@ } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); + dev->last_rx = jiffies; sp->stats.rx_packets++; sp->stats.rx_bytes += pkt_len; } @@ -2288,7 +2289,7 @@ name: "eepro100", id_table: eepro100_pci_tbl, probe: eepro100_init_one, - remove: eepro100_remove_one, + remove: __devexit_p(eepro100_remove_one), #ifdef CONFIG_PM suspend: eepro100_suspend, resume: eepro100_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/epic100.c linux-2.5/drivers/net/epic100.c --- linux-2.5.5/drivers/net/epic100.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/net/epic100.c Fri Feb 8 02:15:53 2002 @@ -1533,7 +1533,7 @@ name: DRV_NAME, id_table: epic_pci_tbl, probe: epic_init_one, - remove: epic_remove_one, + remove: __devexit_p(epic_remove_one), #ifdef CONFIG_PM suspend: epic_suspend, resume: epic_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/fc/Makefile linux-2.5/drivers/net/fc/Makefile --- linux-2.5.5/drivers/net/fc/Makefile Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/fc/Makefile Mon Feb 4 22:15:16 2002 @@ -1,7 +1,7 @@ # # Makefile for linux/drivers/net/fc # -# 9 Aug 2000, Christoph Hellwig +# 9 Aug 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/fealnx.c linux-2.5/drivers/net/fealnx.c --- linux-2.5.5/drivers/net/fealnx.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/net/fealnx.c Fri Jan 18 22:19:46 2002 @@ -1929,7 +1929,7 @@ name: "fealnx", id_table: fealnx_pci_tbl, probe: fealnx_init_one, - remove: fealnx_remove_one, + remove: __devexit_p(fealnx_remove_one), }; static int __init fealnx_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/gt96100eth.c linux-2.5/drivers/net/gt96100eth.c --- linux-2.5.5/drivers/net/gt96100eth.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/net/gt96100eth.c Sun Mar 3 17:54:35 2002 @@ -1,5 +1,5 @@ /* - * Copyright 2000 MontaVista Software Inc. + * Copyright 2000, 2001 MontaVista Software Inc. * Author: MontaVista Software, Inc. * stevel@mvista.com or source@mvista.com * @@ -22,8 +22,23 @@ * * Ethernet driver for the MIPS GT96100 Advanced Communication Controller. * + * Revision history + * + * 11.11.2001 Moved to 2.4.14, ppopov@mvista.com. Modified driver to add + * proper gt96100A support. + * 12.05.2001 Moved eth port 0 to irq 3 (mapped to GT_SERINT0 on EV96100A) + * in order for both ports to work. Also cleaned up boot + * option support (mac address string parsing), fleshed out + * gt96100_cleanup_module(), and other general code cleanups + * . */ +#ifndef __OPTIMIZE__ +#error You must compile this file with the correct options! +#error See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + #ifndef __mips__ #error This driver only works with MIPS architectures! #endif @@ -45,34 +60,49 @@ #include #include #include +#include #include #include #include -#include "gt96100eth.h" +#define DESC_BE 1 +#define DESC_DATA_BE 1 -#ifdef GT96100_DEBUG -static int gt96100_debug = GT96100_DEBUG; -#else -static int gt96100_debug = 3; -#endif +#define GT96100_DEBUG 2 + +#include "gt96100eth.h" // prototypes -static void *dmaalloc(size_t size, dma_addr_t * dma_handle); +static void* dmaalloc(size_t size, dma_addr_t *dma_handle); static void dmafree(size_t size, void *vaddr); +static void gt96100_delay(int msec); static int gt96100_add_hash_entry(struct net_device *dev, - unsigned char *addr); + unsigned char* addr); static void read_mib_counters(struct gt96100_private *gp); -static int read_MII(struct net_device *dev, u32 reg); -static int write_MII(struct net_device *dev, u32 reg, u16 data); -static void dump_MII(struct net_device *dev); +static int read_MII(int phy_addr, u32 reg); +static int write_MII(int phy_addr, u32 reg, u16 data); +#if 0 +static void dump_tx_ring(struct net_device *dev); +static void dump_rx_ring(struct net_device *dev); +#endif +static int gt96100_init_module(void); +static void gt96100_cleanup_module(void); +static void dump_MII(int dbg_lvl, struct net_device *dev); +static void dump_tx_desc(int dbg_lvl, struct net_device *dev, int i); +static void dump_rx_desc(int dbg_lvl, struct net_device *dev, int i); +static void dump_skb(int dbg_lvl, struct net_device *dev, + struct sk_buff *skb); +static void dump_hw_addr(int dbg_lvl, struct net_device *dev, + const char* pfx, unsigned char* addr_str); static void update_stats(struct gt96100_private *gp); static void abort(struct net_device *dev, u32 abort_bits); static void hard_stop(struct net_device *dev); static void enable_ether_irq(struct net_device *dev); static void disable_ether_irq(struct net_device *dev); -static int __init gt96100_probe1(struct net_device *dev, long ioaddr, - int irq, int port_num); +static int gt96100_probe1(int port_num); +static void reset_tx(struct net_device *dev); +static void reset_rx(struct net_device *dev); +static int gt96100_check_tx_consistent(struct gt96100_private *gp); static int gt96100_init(struct net_device *dev); static int gt96100_open(struct net_device *dev); static int gt96100_close(struct net_device *dev); @@ -81,134 +111,229 @@ static void gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void gt96100_tx_timeout(struct net_device *dev); static void gt96100_set_rx_mode(struct net_device *dev); -static struct net_device_stats *gt96100_get_stats(struct net_device *dev); +static struct net_device_stats* gt96100_get_stats(struct net_device *dev); -static char version[] __devinitdata = - "gt96100eth.c:0.1 stevel@mvista.com\n"; +extern char * __init prom_getcmdline(void); -// FIX! Need real Ethernet addresses -static unsigned char gt96100_station_addr[2][6] __devinitdata = - { {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, -{0x01, 0x02, 0x03, 0x04, 0x05, 0x07} -}; +static int max_interrupt_work = 32; #define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0)) #define RUN_AT(x) (jiffies + (x)) -// For reading/writing 32-bit words from/to DMA memory +// For reading/writing 32-bit words and half-words from/to DMA memory +#ifdef DESC_BE #define cpu_to_dma32 cpu_to_be32 #define dma32_to_cpu be32_to_cpu +#define cpu_to_dma16 cpu_to_be16 +#define dma16_to_cpu be16_to_cpu +#else +#define cpu_to_dma32 cpu_to_le32 +#define dma32_to_cpu le32_to_cpu +#define cpu_to_dma16 cpu_to_le16 +#define dma16_to_cpu le16_to_cpu +#endif + +static char mac0[18] = "00.02.03.04.05.06"; +static char mac1[18] = "00.01.02.03.04.05"; +MODULE_PARM(mac0, "c18"); +MODULE_PARM(mac1, "c18"); +MODULE_PARM_DESC(mac0, "MAC address for GT96100 ethernet port 0"); +MODULE_PARM_DESC(mac1, "MAC address for GT96100 ethernet port 1"); /* - * Base address and interupt of the GT96100 ethernet controllers + * Info for the GT96100 ethernet controller's ports. */ -static struct { - unsigned int port; - int irq; +static struct gt96100_if_t { + struct net_device *dev; + unsigned int iobase; // IO Base address of this port + int irq; // IRQ number of this port + char *mac_str; } gt96100_iflist[NUM_INTERFACES] = { { - GT96100_ETH0_BASE, GT96100_ETHER0_IRQ}, { - GT96100_ETH1_BASE, GT96100_ETHER1_IRQ} + NULL, + GT96100_ETH0_BASE, GT96100_ETHER0_IRQ, + mac0 + }, + { + NULL, + GT96100_ETH1_BASE, GT96100_ETHER1_IRQ, + mac1 + } }; +static inline const char* +chip_name(int chip_rev) +{ + switch (chip_rev) { + case REV_GT96100: + return "GT96100"; + case REV_GT96100A_1: + case REV_GT96100A: + return "GT96100A"; + default: + return "Unknown GT96100"; + } +} + /* DMA memory allocation, derived from pci_alloc_consistent. */ -static void *dmaalloc(size_t size, dma_addr_t * dma_handle) +static void * +dmaalloc(size_t size, dma_addr_t *dma_handle) { void *ret; - - ret = - (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, - get_order(size)); - + + ret = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA, + get_order(size)); + if (ret != NULL) { - dma_cache_inv((unsigned long) ret, size); + dma_cache_inv((unsigned long)ret, size); if (dma_handle != NULL) *dma_handle = virt_to_phys(ret); /* bump virtual address up to non-cached area */ - ret = KSEG1ADDR(ret); + ret = (void*)KSEG1ADDR(ret); } return ret; } -static void dmafree(size_t size, void *vaddr) +static void +dmafree(size_t size, void *vaddr) { - vaddr = KSEG0ADDR(vaddr); - free_pages((unsigned long) vaddr, get_order(size)); + vaddr = (void*)KSEG0ADDR(vaddr); + free_pages((unsigned long)vaddr, get_order(size)); } -static int read_MII(struct net_device *dev, u32 reg) + +static void +gt96100_delay(int ms) +{ + if (in_interrupt()) + return; + else { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(ms*HZ/1000); + } +} + +static int +parse_mac_addr(struct net_device *dev, char* macstr) +{ + int i, j; + unsigned char result, value; + + for (i=0; i<6; i++) { + result = 0; + if (i != 5 && *(macstr+2) != '.') { + err(__FILE__ "invalid mac address format: %d %c\n", + i, *(macstr+2)); + return -EINVAL; + } + + for (j=0; j<2; j++) { + if (isxdigit(*macstr) && + (value = isdigit(*macstr) ? *macstr-'0' : + toupper(*macstr)-'A'+10) < 16) { + result = result*16 + value; + macstr++; + } else { + err(__FILE__ "invalid mac address " + "character: %c\n", *macstr); + return -EINVAL; + } + } + + macstr++; // step over '.' + dev->dev_addr[i] = result; + } + + return 0; +} + + +static int +read_MII(int phy_addr, u32 reg) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; int timedout = 20; - u32 smir = smirOpCode | (gp->phy_addr << smirPhyAdBit) | - (reg << smirRegAdBit); + u32 smir = smirOpCode | (phy_addr << smirPhyAdBit) | + (reg << smirRegAdBit); // wait for last operation to complete while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) { // snooze for 1 msec and check again -#if 0 - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(10 * HZ / 10000); -#else - mdelay(1); -#endif + gt96100_delay(1); if (--timedout == 0) { - printk(KERN_ERR "%s: read_MII busy timeout!!\n", - dev->name); - return -1; + printk(KERN_ERR __FUNCTION__ ": busy timeout!!\n"); + return -ENODEV; } } - + GT96100_WRITE(GT96100_ETH_SMI_REG, smir); timedout = 20; // wait for read to complete - while (!(smir = GT96100_READ(GT96100_ETH_SMI_REG) & smirReadValid)) { + while (!((smir = GT96100_READ(GT96100_ETH_SMI_REG)) & smirReadValid)) { // snooze for 1 msec and check again -#if 0 - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(10 * HZ / 10000); -#else - mdelay(1); -#endif - + gt96100_delay(1); + if (--timedout == 0) { - printk(KERN_ERR "%s: read_MII timeout!!\n", - dev->name); - return -1; + printk(KERN_ERR __FUNCTION__ ": timeout!!\n"); + return -ENODEV; } } - return (int) (smir & smirDataMask); + return (int)(smir & smirDataMask); +} + +static void +dump_tx_desc(int dbg_lvl, struct net_device *dev, int i) +{ + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + gt96100_td_t *td = &gp->tx_ring[i]; + + dbg(dbg_lvl, "Tx descriptor at 0x%08lx:\n", virt_to_phys(td)); + dbg(dbg_lvl, + " cmdstat=%04x, byte_cnt=%04x, buff_ptr=%04x, next=%04x\n", + dma32_to_cpu(td->cmdstat), + dma16_to_cpu(td->byte_cnt), + dma32_to_cpu(td->buff_ptr), + dma32_to_cpu(td->next)); +} + +static void +dump_rx_desc(int dbg_lvl, struct net_device *dev, int i) +{ + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + gt96100_rd_t *rd = &gp->rx_ring[i]; + + dbg(dbg_lvl, "Rx descriptor at 0x%08lx:\n", virt_to_phys(rd)); + dbg(dbg_lvl, " cmdstat=%04x, buff_sz=%04x, byte_cnt=%04x, " + "buff_ptr=%04x, next=%04x\n", + dma32_to_cpu(rd->cmdstat), + dma16_to_cpu(rd->buff_sz), + dma16_to_cpu(rd->byte_cnt), + dma32_to_cpu(rd->buff_ptr), + dma32_to_cpu(rd->next)); } -static int write_MII(struct net_device *dev, u32 reg, u16 data) +static int +write_MII(int phy_addr, u32 reg, u16 data) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; int timedout = 20; - u32 smir = - (gp->phy_addr << smirPhyAdBit) | (reg << smirRegAdBit) | data; + u32 smir = (phy_addr << smirPhyAdBit) | + (reg << smirRegAdBit) | data; // wait for last operation to complete while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) { // snooze for 1 msec and check again -#if 0 - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(10 * HZ / 10000); -#else - mdelay(1); -#endif - + gt96100_delay(1); + if (--timedout == 0) { - printk(KERN_ERR "%s: write_MII busy timeout!!\n", - dev->name); + printk(KERN_ERR __FUNCTION__ ": busy timeout!!\n"); return -1; } } @@ -217,109 +342,203 @@ return 0; } +#if 0 +// These routines work, just disabled to avoid compile warnings +static void +dump_tx_ring(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + int i; + + dbg(0, __FUNCTION__ ": txno/txni/cnt=%d/%d/%d\n", + gp->tx_next_out, gp->tx_next_in, gp->tx_count); -static void dump_MII(struct net_device *dev) + for (i=0; ipriv; + int i; + + dbg(0, __FUNCTION__ ": rxno=%d\n", gp->rx_next_out); + + for (i=0; ipriv; + + if (dbg_lvl <= GT96100_DEBUG) { + for (i=0; i<7; i++) { + if ((val = read_MII(gp->phy_addr, i)) >= 0) + printk("MII Reg %d=%x\n", i, val); + } + for (i=16; i<21; i++) { + if ((val = read_MII(gp->phy_addr, i)) >= 0) + printk("MII Reg %d=%x\n", i, val); + } + } +} - for (i = 0; i < 7; i++) { - if ((val = read_MII(dev, i)) >= 0) - printk("%s: MII Reg %d=%x\n", dev->name, i, val); - } - for (i = 16; i < 21; i++) { - if ((val = read_MII(dev, i)) >= 0) - printk("%s: MII Reg %d=%x\n", dev->name, i, val); +static void +dump_hw_addr(int dbg_lvl, struct net_device *dev, const char* pfx, + unsigned char* addr_str) +{ + int i; + char buf[100], octet[5]; + + if (dbg_lvl <= GT96100_DEBUG) { + strcpy(buf, pfx); + for (i = 0; i < 6; i++) { + sprintf(octet, "%2.2x%s", + addr_str[i], i<5 ? ":" : "\n"); + strcat(buf, octet); + } + info("%s", buf); + } +} + + +static void +dump_skb(int dbg_lvl, struct net_device *dev, struct sk_buff *skb) +{ + int i; + unsigned char* skbdata; + + if (dbg_lvl <= GT96100_DEBUG) { + dbg(dbg_lvl, __FUNCTION__ + ": skb=%p, skb->data=%p, skb->len=%d\n", + skb, skb->data, skb->len); + + skbdata = (unsigned char*)KSEG1ADDR(skb->data); + + for (i=0; ilen; i++) { + if (!(i % 16)) + printk(KERN_DEBUG "\n %3.3x: %2.2x,", + i, skbdata[i]); + else + printk(KERN_DEBUG "%2.2x,", skbdata[i]); + } + printk(KERN_DEBUG "\n"); } } static int -gt96100_add_hash_entry(struct net_device *dev, unsigned char *addr) +gt96100_add_hash_entry(struct net_device *dev, unsigned char* addr) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; - u16 hashResult, stmp; - unsigned char ctmp, hash_ea[6]; - u32 tblEntry, *tblEntryAddr; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + //u16 hashResult, stmp; + //unsigned char ctmp, hash_ea[6]; + u32 tblEntry1, tblEntry0, *tblEntryAddr; int i; - for (i = 0; i < 6; i++) { + tblEntry1 = hteValid | hteRD; + tblEntry1 |= (u32)addr[5] << 3; + tblEntry1 |= (u32)addr[4] << 11; + tblEntry1 |= (u32)addr[3] << 19; + tblEntry1 |= ((u32)addr[2] & 0x1f) << 27; + dbg(3, __FUNCTION__ ": tblEntry1=%x\n", tblEntry1); + tblEntry0 = ((u32)addr[2] >> 5) & 0x07; + tblEntry0 |= (u32)addr[1] << 3; + tblEntry0 |= (u32)addr[0] << 11; + dbg(3, __FUNCTION__ ": tblEntry0=%x\n", tblEntry0); + +#if 0 + + for (i=0; i<6; i++) { // nibble swap ctmp = nibswap(addr[i]); // invert every nibble - hash_ea[i] = ((ctmp & 1) << 3) | ((ctmp & 8) >> 3) | - ((ctmp & 2) << 1) | ((ctmp & 4) >> 1); - hash_ea[i] |= ((ctmp & 0x10) << 3) | ((ctmp & 0x80) >> 3) | - ((ctmp & 0x20) << 1) | ((ctmp & 0x40) >> 1); + hash_ea[i] = ((ctmp&1)<<3) | ((ctmp&8)>>3) | + ((ctmp&2)<<1) | ((ctmp&4)>>1); + hash_ea[i] |= ((ctmp&0x10)<<3) | ((ctmp&0x80)>>3) | + ((ctmp&0x20)<<1) | ((ctmp&0x40)>>1); } + dump_hw_addr(3, dev, __FUNCTION__ ": nib swap/invt addr=", hash_ea); + if (gp->hash_mode == 0) { - hashResult = ((u16) hash_ea[0] & 0xfc) << 7; - stmp = - ((u16) hash_ea[0] & 0x03) | (((u16) hash_ea[1] & 0x7f) - << 2); - stmp ^= - (((u16) hash_ea[1] >> 7) & 0x01) | ((u16) hash_ea[2] << - 1); - stmp ^= (u16) hash_ea[3] | (((u16) hash_ea[4] & 1) << 8); + hashResult = ((u16)hash_ea[0] & 0xfc) << 7; + stmp = ((u16)hash_ea[0] & 0x03) | + (((u16)hash_ea[1] & 0x7f) << 2); + stmp ^= (((u16)hash_ea[1] >> 7) & 0x01) | + ((u16)hash_ea[2] << 1); + stmp ^= (u16)hash_ea[3] | (((u16)hash_ea[4] & 1) << 8); hashResult |= stmp; } else { - return -1; // don't support hash mode 1 + return -1; // don't support hash mode 1 } - tblEntryAddr = - (u32 *) (&gp->hash_table[((u32) hashResult & 0x7ff) << 3]); + dbg(3, __FUNCTION__ ": hashResult=%x\n", hashResult); - for (i = 0; i < HASH_HOP_NUMBER; i++) { - if ((*tblEntryAddr & hteValid) - && !(*tblEntryAddr & hteSkip)) { + tblEntryAddr = + (u32 *)(&gp->hash_table[((u32)hashResult & 0x7ff) << 3]); + + dbg(3, __FUNCTION__ ": tblEntryAddr=%p\n", tblEntryAddr); + + for (i=0; i> 5) & 0x07; - tblEntry |= (u32) addr[1] << 3; - tblEntry |= (u32) addr[0] << 11; - *tblEntryAddr = cpu_to_dma32(tblEntry); + tblEntryAddr[1] = cpu_to_dma32(tblEntry1); + tblEntryAddr[0] = cpu_to_dma32(tblEntry0); break; } } if (i >= HASH_HOP_NUMBER) { - printk(KERN_ERR "%s: gt96100_add_hash_entry expired!\n", - dev->name); - return -1; // Couldn't find an unused entry + err(__FUNCTION__ ": expired!\n"); + return -1; // Couldn't find an unused entry + } + +#else + + tblEntryAddr = (u32 *)gp->hash_table; + for (i=0; imib; + u32* mib_regs = (u32*)&gp->mib; int i; - - for (i = 0; i < sizeof(mib_counters_t) / sizeof(u32); i++) - mib_regs[i] = - GT96100ETH_READ(gp, - GT96100_ETH_MIB_COUNT_BASE + - i * sizeof(u32)); + + for (i=0; imib; struct net_device_stats *stats = &gp->stats; - + read_mib_counters(gp); - + stats->rx_packets = mib->totalFramesReceived; stats->tx_packets = mib->framesSent; stats->rx_bytes = mib->totalByteReceived; @@ -329,8 +548,7 @@ //rx_dropped incremented by gt96100_rx //tx_dropped incremented by gt96100_tx stats->multicast = mib->multicastFramesReceived; - // Tx collisions incremented by ISR, so add in MIB Rx collisions - stats->collisions += mib->collision + mib->lateCollision; + // collisions incremented by gt96100_tx_complete stats->rx_length_errors = mib->oversizeFrames + mib->fragments; // The RxError condition means the Rx DMA encountered a // CPU owned descriptor, which, if things are working as @@ -339,13 +557,13 @@ stats->rx_crc_errors = mib->cRCError; } -static void abort(struct net_device *dev, u32 abort_bits) +static void +abort(struct net_device *dev, u32 abort_bits) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; - int timedout = 100; // wait up to 100 msec for hard stop to complete + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + int timedout = 100; // wait up to 100 msec for hard stop to complete - if (gt96100_debug > 2) - printk(KERN_INFO "%s: abort\n", dev->name); + dbg(3, __FUNCTION__ "\n"); // Return if neither Rx or Tx abort bits are set if (!(abort_bits & (sdcmrAR | sdcmrAT))) @@ -353,48 +571,36 @@ // make sure only the Rx/Tx abort bits are set abort_bits &= (sdcmrAR | sdcmrAT); - + spin_lock(&gp->lock); // abort any Rx/Tx DMA immediately GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, abort_bits); - if (gt96100_debug > 2) - printk(KERN_INFO "%s: abort: SDMA comm = %x\n", - dev->name, GT96100ETH_READ(gp, - GT96100_ETH_SDMA_COMM)); + dbg(3, __FUNCTION__ ": SDMA comm = %x\n", + GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM)); // wait for abort to complete while (GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM) & abort_bits) { // snooze for 20 msec and check again -#if 0 - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(10 * HZ / 10000); -#else - mdelay(1); -#endif - + gt96100_delay(1); + if (--timedout == 0) { - printk(KERN_ERR "%s: abort timeout!!\n", - dev->name); + err(__FUNCTION__ ": timeout!!\n"); break; } } - if (gt96100_debug > 2) - printk(KERN_INFO "%s: abort: timedout=%d\n", dev->name, - timedout); - spin_unlock(&gp->lock); } -static void hard_stop(struct net_device *dev) +static void +hard_stop(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; - if (gt96100_debug > 2) - printk(KERN_INFO "%s: hard stop\n", dev->name); + dbg(3, __FUNCTION__ "\n"); disable_ether_irq(dev); @@ -405,207 +611,236 @@ } -static void enable_ether_irq(struct net_device *dev) +static void +enable_ether_irq(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; u32 intMask; - + /* + * route ethernet interrupt to GT_SERINT0 for port 0, + * GT_INT0 for port 1. + */ + int intr_mask_reg = (gp->port_num == 0) ? + GT96100_SERINT0_MASK : GT96100_INT0_HIGH_MASK; + + if (gp->chip_rev >= REV_GT96100A_1) { + intMask = icrTxBufferLow | icrTxEndLow | + icrTxErrorLow | icrRxOVR | icrTxUdr | + icrRxBufferQ0 | icrRxErrorQ0 | + icrMIIPhySTC | icrEtherIntSum; + } + else { + intMask = icrTxBufferLow | icrTxEndLow | + icrTxErrorLow | icrRxOVR | icrTxUdr | + icrRxBuffer | icrRxError | + icrMIIPhySTC | icrEtherIntSum; + } + // unmask interrupts - GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, - icrRxBuffer | icrTxBufferLow | icrTxEndLow | - icrRxError | icrTxErrorLow | icrRxOVR | - icrTxUdr | icrRxBufferQ0 | icrRxErrorQ0 | - icrMIIPhySTC); - - // now route ethernet interrupts to GT Int0 (eth0 and eth1 will be - // sharing it). - // FIX! The kernel's irq code should do this - intMask = GT96100_READ(GT96100_INT0_HIGH_MASK); - intMask |= 1 << gp->port_num; - GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask); + GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, intMask); + + intMask = GT96100_READ(intr_mask_reg); + intMask |= 1<port_num; + GT96100_WRITE(intr_mask_reg, intMask); } -static void disable_ether_irq(struct net_device *dev) +static void +disable_ether_irq(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; u32 intMask; + int intr_mask_reg = (gp->port_num == 0) ? + GT96100_SERINT0_MASK : GT96100_INT0_HIGH_MASK; - // FIX! The kernel's irq code should do this - intMask = GT96100_READ(GT96100_INT0_HIGH_MASK); - intMask &= ~(1 << gp->port_num); - GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask); - + intMask = GT96100_READ(intr_mask_reg); + intMask &= ~(1<port_num); + GT96100_WRITE(intr_mask_reg, intMask); + GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, 0); } /* - * Probe for a GT96100 ethernet controller. + * Init GT96100 ethernet controller driver */ -int __init gt96100_probe(struct net_device *dev) +int gt96100_init_module(void) { - unsigned int base_addr = dev ? dev->base_addr : 0; - int i; + int i, retval=0; + u16 vendor_id, device_id; + u32 cpuConfig; #ifndef CONFIG_MIPS_GT96100ETH return -ENODEV; #endif - if (gt96100_debug > 2) - printk(KERN_INFO "%s: gt96100_probe\n", dev->name); + // probe for GT96100 by reading PCI0 vendor/device ID register + pcibios_read_config_word(0, 0, PCI_VENDOR_ID, &vendor_id); + pcibios_read_config_word(0, 0, PCI_DEVICE_ID, &device_id); + + if (vendor_id != PCI_VENDOR_ID_GALILEO || + (device_id != PCI_DEVICE_ID_GALILEO_GT96100 && + device_id != PCI_DEVICE_ID_GALILEO_GT96100A)) { + printk(KERN_ERR __FILE__ ": GT96100 not found!\n"); + return -ENODEV; + } - if (base_addr >= KSEG0) /* Check a single specified location. */ - return gt96100_probe1(dev, base_addr, dev->irq, 0); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - -// for (i = 0; i= 0; i--) { - int base_addr = gt96100_iflist[i].port; -#if 0 - if (check_region(base_addr, GT96100_ETH_IO_SIZE)) { - printk(KERN_ERR - "%s: gt96100_probe: ioaddr 0x%lx taken?\n", - dev->name, base_addr); - continue; - } -#endif - if (gt96100_probe1 - (dev, base_addr, gt96100_iflist[i].irq, i) == 0) - return 0; + cpuConfig = GT96100_READ(GT96100_CPU_INTERF_CONFIG); + if (cpuConfig & (1<<12)) { + printk(KERN_ERR __FILE__ + ": must be in Big Endian mode!\n"); + return -ENODEV; } - return -ENODEV; + + for (i=0; i < NUM_INTERFACES; i++) { + retval |= gt96100_probe1(i); + } + + return retval; } static int __init -gt96100_probe1(struct net_device *dev, long ioaddr, int irq, int port_num) +gt96100_probe1(int port_num) { - static unsigned version_printed = 0; struct gt96100_private *gp = NULL; - int i, retval; - u32 cpuConfig; - - // FIX! probe for GT96100 by reading a suitable register - - if (gt96100_debug > 2) - printk(KERN_INFO "gt96100_probe1: ioaddr 0x%lx, irq %d\n", - ioaddr, irq); - - request_region(ioaddr, GT96100_ETH_IO_SIZE, "GT96100ETH"); - - cpuConfig = GT96100_READ(GT96100_CPU_INTERF_CONFIG); - if (cpuConfig & (1 << 12)) { - printk(KERN_ERR - "gt96100_probe1: must be in Big Endian mode!\n"); - retval = -ENODEV; - goto free_region; - } - - if (gt96100_debug > 2) - printk(KERN_INFO - "gt96100_probe1: chip in Big Endian mode - cool\n"); - - /* Allocate a new 'dev' if needed. */ - if (dev == NULL) - dev = init_etherdev(0, sizeof(struct gt96100_private)); - - if (gt96100_debug && version_printed++ == 0) - printk(version); - - if (irq < 0) { - printk(KERN_ERR - "gt96100_probe1: irq unknown - probing not supported\n"); - retval = -ENODEV; - goto free_region; - } - - printk(KERN_INFO "%s: GT-96100 ethernet found at 0x%lx, irq %d\n", - dev->name, ioaddr, irq); - + struct gt96100_if_t *gtif = >96100_iflist[port_num]; + int phy_addr, phy_id1, phy_id2; + u32 phyAD; + int retval; + unsigned char chip_rev; + struct net_device *dev = NULL; + + if (gtif->irq < 0) { + printk(KERN_ERR __FUNCTION__ + ": irq unknown - probing not supported\n"); + return -ENODEV; + } + + pcibios_read_config_byte(0, 0, PCI_REVISION_ID, &chip_rev); + + if (chip_rev >= REV_GT96100A_1) { + phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG); + phy_addr = (phyAD >> (5*port_num)) & 0x1f; + } else { + /* + * not sure what's this about -- probably + * a gt bug + */ + phy_addr = port_num; + phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG); + phyAD &= ~(0x1f << (port_num*5)); + phyAD |= phy_addr << (port_num*5); + GT96100_WRITE(GT96100_ETH_PHY_ADDR_REG, phyAD); + } + + // probe for the external PHY + if ((phy_id1 = read_MII(phy_addr, 2)) <= 0 || + (phy_id2 = read_MII(phy_addr, 3)) <= 0) { + printk(KERN_ERR __FUNCTION__ + ": no PHY found on MII%d\n", port_num); + return -ENODEV; + } + + if (!request_region(gtif->iobase, GT96100_ETH_IO_SIZE, "GT96100ETH")) { + printk(KERN_ERR __FUNCTION__ ": request_region failed\n"); + return -EBUSY; + } + + dev = init_etherdev(0, sizeof(struct gt96100_private)); + gtif->dev = dev; + /* private struct aligned and zeroed by init_etherdev */ /* Fill in the 'dev' fields. */ - dev->base_addr = ioaddr; - dev->irq = irq; - memcpy(dev->dev_addr, gt96100_station_addr[port_num], - sizeof(dev->dev_addr)); - - printk(KERN_INFO "%s: HW Address ", dev->name); - for (i = 0; i < sizeof(dev->dev_addr); i++) { - printk("%2.2x", dev->dev_addr[i]); - printk(i < 5 ? ":" : "\n"); + dev->base_addr = gtif->iobase; + dev->irq = gtif->irq; + + if ((retval = parse_mac_addr(dev, gtif->mac_str))) { + err(__FUNCTION__ ": MAC address parse failed\n"); + retval = -EINVAL; + goto free_region; } /* Initialize our private structure. */ if (dev->priv == NULL) { - gp = - (struct gt96100_private *) kmalloc(sizeof(*gp), + gp = (struct gt96100_private *)kmalloc(sizeof(*gp), GFP_KERNEL); if (gp == NULL) { retval = -ENOMEM; goto free_region; } - + dev->priv = gp; } gp = dev->priv; - memset(gp, 0, sizeof(*gp)); // clear it + memset(gp, 0, sizeof(*gp)); // clear it gp->port_num = port_num; gp->io_size = GT96100_ETH_IO_SIZE; gp->port_offset = port_num * GT96100_ETH_IO_SIZE; - gp->phy_addr = port_num + 1; + gp->phy_addr = phy_addr; + gp->chip_rev = chip_rev; - if (gt96100_debug > 2) - printk(KERN_INFO "%s: gt96100_probe1, port %d\n", - dev->name, gp->port_num); + info("%s found at 0x%x, irq %d\n", + chip_name(gp->chip_rev), gtif->iobase, gtif->irq); + dump_hw_addr(0, dev, "HW Address ", dev->dev_addr); + info("%s chip revision=%d\n", chip_name(gp->chip_rev), gp->chip_rev); + info("%s ethernet port %d\n", chip_name(gp->chip_rev), gp->port_num); + info("external PHY ID1=0x%04x, ID2=0x%04x\n", phy_id1, phy_id2); // Allocate Rx and Tx descriptor rings if (gp->rx_ring == NULL) { // All descriptors in ring must be 16-byte aligned gp->rx_ring = dmaalloc(sizeof(gt96100_rd_t) * RX_RING_SIZE - + - sizeof(gt96100_td_t) * TX_RING_SIZE, + + sizeof(gt96100_td_t) * TX_RING_SIZE, &gp->rx_ring_dma); if (gp->rx_ring == NULL) { retval = -ENOMEM; goto free_region; } - - gp->tx_ring = - (gt96100_td_t *) (gp->rx_ring + RX_RING_SIZE); + + gp->tx_ring = (gt96100_td_t *)(gp->rx_ring + RX_RING_SIZE); gp->tx_ring_dma = - gp->rx_ring_dma + sizeof(gt96100_rd_t) * RX_RING_SIZE; + gp->rx_ring_dma + sizeof(gt96100_rd_t) * RX_RING_SIZE; } - - if (gt96100_debug > 2) - printk(KERN_INFO - "%s: gt96100_probe1, rx_ring=%p, tx_ring=%p\n", - dev->name, gp->rx_ring, gp->tx_ring); + + // Allocate the Rx Data Buffers + if (gp->rx_buff == NULL) { + gp->rx_buff = dmaalloc(PKT_BUF_SZ*RX_RING_SIZE, + &gp->rx_buff_dma); + if (gp->rx_buff == NULL) { + dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE + + sizeof(gt96100_td_t) * TX_RING_SIZE, + gp->rx_ring); + retval = -ENOMEM; + goto free_region; + } + } + + dbg(3, __FUNCTION__ ": rx_ring=%p, tx_ring=%p\n", + gp->rx_ring, gp->tx_ring); // Allocate Rx Hash Table if (gp->hash_table == NULL) { - gp->hash_table = (char *) dmaalloc(RX_HASH_TABLE_SIZE, - &gp->hash_table_dma); + gp->hash_table = (char*)dmaalloc(RX_HASH_TABLE_SIZE, + &gp->hash_table_dma); if (gp->hash_table == NULL) { dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE + sizeof(gt96100_td_t) * TX_RING_SIZE, gp->rx_ring); + dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff); retval = -ENOMEM; goto free_region; } } - - if (gt96100_debug > 2) - printk(KERN_INFO "%s: gt96100_probe1, hash=%p\n", - dev->name, gp->hash_table); + + dbg(3, __FUNCTION__ ": hash=%p\n", gp->hash_table); spin_lock_init(&gp->lock); - + dev->open = gt96100_open; dev->hard_start_xmit = gt96100_tx; dev->stop = gt96100_close; @@ -619,317 +854,358 @@ ether_setup(dev); return 0; - free_region: - release_region(ioaddr, gp->io_size); + free_region: + release_region(gtif->iobase, GT96100_ETH_IO_SIZE); unregister_netdev(dev); if (dev->priv != NULL) - kfree(dev->priv); - kfree(dev); - printk(KERN_ERR "%s: gt96100_probe1 failed. Returns %d\n", - dev->name, retval); + kfree (dev->priv); + kfree (dev); + err(__FUNCTION__ " failed. Returns %d\n", retval); return retval; } -static int gt96100_init(struct net_device *dev) +static void +reset_tx(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; - unsigned long flags; - u32 phyAD, ciu; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; int i; - if (gt96100_debug > 2) - printk("%s: gt96100_init: dev=%p\n", dev->name, dev); + abort(dev, sdcmrAT); - // Stop and disable Port - hard_stop(dev); - - spin_lock_irqsave(&gp->lock, flags); + for (i=0; itx_skbuff[i]) { + if (in_interrupt()) + dev_kfree_skb_irq(gp->tx_skbuff[i]); + else + dev_kfree_skb(gp->tx_skbuff[i]); + gp->tx_skbuff[i] = NULL; + } - // First things first, set-up hash table - memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear it - gp->hash_mode = 0; - // Add a single entry to hash table - our ethernet address - gt96100_add_hash_entry(dev, dev->dev_addr); - // Set-up DMA ptr to hash table - GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma); - if (gt96100_debug > 2) - printk("%s: gt96100_init: Hash Tbl Ptr=%x\n", dev->name, - GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR)); - - // Setup Tx descriptor ring - for (i = 0; i < TX_RING_SIZE; i++) { - gp->tx_ring[i].cmdstat = 0; // CPU owns + gp->tx_ring[i].cmdstat = 0; // CPU owns gp->tx_ring[i].byte_cnt = 0; gp->tx_ring[i].buff_ptr = 0; gp->tx_ring[i].next = - cpu_to_dma32(gp->tx_ring_dma + - sizeof(gt96100_td_t) * (i + 1)); + cpu_to_dma32(gp->tx_ring_dma + + sizeof(gt96100_td_t) * (i+1)); + dump_tx_desc(4, dev, i); } /* Wrap the ring. */ - gp->tx_ring[i - 1].next = cpu_to_dma32(gp->tx_ring_dma); - + gp->tx_ring[i-1].next = cpu_to_dma32(gp->tx_ring_dma); + // setup only the lowest priority TxCDP reg - GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR0, - gp->tx_ring_dma); + GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR0, gp->tx_ring_dma); GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR1, 0); - if (gt96100_debug > 2) - printk("%s: gt96100_init: Curr Tx Desc Ptr0=%x\n", - dev->name, GT96100ETH_READ(gp, - GT96100_ETH_CURR_TX_DESC_PTR0)); - - // Setup Rx descriptor ring - for (i = 0; i < RX_RING_SIZE; i++) { - dma_addr_t rx_buff_dma; + + // init Tx indeces and pkt counter + gp->tx_next_in = gp->tx_next_out = 0; + gp->tx_count = 0; + +} + +static void +reset_rx(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + int i; + + abort(dev, sdcmrAR); + + for (i=0; irx_ring[i].next = - cpu_to_dma32(gp->rx_ring_dma + - sizeof(gt96100_rd_t) * (i + 1)); - if (gp->rx_buff[i] == NULL) - gp->rx_buff[i] = - dmaalloc(PKT_BUF_SZ, &rx_buff_dma); - else - rx_buff_dma = virt_to_phys(gp->rx_buff[i]); - if (gp->rx_buff[i] == NULL) - break; - gp->rx_ring[i].buff_ptr = cpu_to_dma32(rx_buff_dma); - gp->rx_ring[i].buff_cnt_sz = - cpu_to_dma32(PKT_BUF_SZ << rdBuffSzBit); - // Give ownership to device, enable interrupt + cpu_to_dma32(gp->rx_ring_dma + + sizeof(gt96100_rd_t) * (i+1)); + gp->rx_ring[i].buff_ptr = + cpu_to_dma32(gp->rx_buff_dma + i*PKT_BUF_SZ); + gp->rx_ring[i].buff_sz = cpu_to_dma16(PKT_BUF_SZ); + // Give ownership to device, set first and last, enable intr gp->rx_ring[i].cmdstat = - cpu_to_dma32((u32) (rxOwn | rxEI)); + cpu_to_dma32((u32)(rxFirst | rxLast | rxOwn | rxEI)); + dump_rx_desc(4, dev, i); } + /* Wrap the ring. */ + gp->rx_ring[i-1].next = cpu_to_dma32(gp->rx_ring_dma); - if (i != RX_RING_SIZE) { - int j; - for (j = 0; j < RX_RING_SIZE; j++) { - if (gp->rx_buff[j]) { - dmafree(PKT_BUF_SZ, gp->rx_buff[j]); - gp->rx_buff[j] = NULL; - } + // Setup only the lowest priority RxFDP and RxCDP regs + for (i=0; i<4; i++) { + if (i == 0) { + GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0, + gp->rx_ring_dma); + GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0, + gp->rx_ring_dma); + } else { + GT96100ETH_WRITE(gp, + GT96100_ETH_1ST_RX_DESC_PTR0 + i*4, + 0); + GT96100ETH_WRITE(gp, + GT96100_ETH_CURR_RX_DESC_PTR0 + i*4, + 0); } - printk(KERN_ERR "%s: Rx ring allocation failed.\n", - dev->name); - spin_unlock_irqrestore(&gp->lock, flags); - return -ENOMEM; } - /* Wrap the ring. */ - gp->rx_ring[i - 1].next = cpu_to_dma32(gp->rx_ring_dma); + // init Rx NextOut index + gp->rx_next_out = 0; +} - // Set our MII PHY device address - phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG); - phyAD &= ~(0x1f << (gp->port_num * 5)); - phyAD |= gp->phy_addr << (gp->port_num * 5); - GT96100_WRITE(GT96100_ETH_PHY_ADDR_REG, phyAD); - - if (gt96100_debug > 2) - printk("%s: gt96100_init: PhyAD=%x\n", dev->name, - GT96100_READ(GT96100_ETH_PHY_ADDR_REG)); - - // Clear all the RxFDP and RXCDP regs... - for (i = 0; i < 4; i++) { - GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0 + i * 4, - 0); - GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0 + i * 4, - 0); - } - // and setup only the lowest priority RxFDP and RxCDP regs - GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0, - gp->rx_ring_dma); - GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0, - gp->rx_ring_dma); - if (gt96100_debug > 2) - printk("%s: gt96100_init: 1st/Curr Rx Desc Ptr0=%x/%x\n", - dev->name, GT96100ETH_READ(gp, - GT96100_ETH_1ST_RX_DESC_PTR0), - GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0)); - // init Rx/Tx indeces and pkt counters - gp->rx_next_out = gp->tx_next_in = gp->tx_next_out = 0; - gp->tx_count = 0; +// Returns 1 if the Tx counter and indeces don't gel +static int +gt96100_check_tx_consistent(struct gt96100_private *gp) +{ + int diff = gp->tx_next_in - gp->tx_next_out; - // setup DMA + diff = diff<0 ? TX_RING_SIZE + diff : diff; + diff = gp->tx_count == TX_RING_SIZE ? diff + TX_RING_SIZE : diff; + + return (diff != gp->tx_count); +} + +static int +gt96100_init(struct net_device *dev) +{ + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + u32 tmp; + u16 mii_reg; + + dbg(3, __FUNCTION__ ": dev=%p\n", dev); + dbg(3, __FUNCTION__ ": scs10_lo=%4x, scs10_hi=%4x\n", + GT96100_READ(0x8), GT96100_READ(0x10)); + dbg(3, __FUNCTION__ ": scs32_lo=%4x, scs32_hi=%4x\n", + GT96100_READ(0x18), GT96100_READ(0x20)); + + // Stop and disable Port + hard_stop(dev); + + // Setup CIU Arbiter + tmp = GT96100_READ(GT96100_CIU_ARBITER_CONFIG); + tmp |= (0x0c << (gp->port_num*2)); // set Ether DMA req priority to hi +#ifndef DESC_BE + tmp &= ~(1<<31); // set desc endianess to little +#else + tmp |= (1<<31); +#endif + GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, tmp); + dbg(3, __FUNCTION__ ": CIU Config=%x/%x\n", + tmp, GT96100_READ(GT96100_CIU_ARBITER_CONFIG)); + + // Set routing. + tmp = GT96100_READ(GT96100_ROUTE_MAIN) & (0x3f << 18); + tmp |= (0x07 << (18 + gp->port_num*3)); + GT96100_WRITE(GT96100_ROUTE_MAIN, tmp); + + /* set MII as peripheral func */ + tmp = GT96100_READ(GT96100_GPP_CONFIG2); + tmp |= 0x7fff << (gp->port_num*16); + GT96100_WRITE(GT96100_GPP_CONFIG2, tmp); + + /* Set up MII port pin directions */ + tmp = GT96100_READ(GT96100_GPP_IO2); + tmp |= 0x003d << (gp->port_num*16); + GT96100_WRITE(GT96100_GPP_IO2, tmp); + + // Set-up hash table + memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear it + gp->hash_mode = 0; + // Add a single entry to hash table - our ethernet address + gt96100_add_hash_entry(dev, dev->dev_addr); + // Set-up DMA ptr to hash table + GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma); + dbg(3, __FUNCTION__ ": Hash Tbl Ptr=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR)); + + // Setup Tx + reset_tx(dev); - // FIX! this should be done by Kernel setup code - ciu = GT96100_READ(GT96100_CIU_ARBITER_CONFIG); - ciu |= (0x0c << (gp->port_num * 2)); // set Ether DMA req priority to high - // FIX! setting the following bit causes the EV96100 board to hang!!! - //ciu |= (1 << (24+gp->port_num)); // pull Ethernet port out of Reset??? - // FIX! endian mode??? - ciu &= ~(1 << 31); // set desc endianess to Big - GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, ciu); - if (gt96100_debug > 2) - printk("%s: gt96100_init: CIU Config=%x/%x\n", dev->name, - ciu, GT96100_READ(GT96100_CIU_ARBITER_CONFIG)); + dbg(3, __FUNCTION__ ": Curr Tx Desc Ptr0=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0)); + + // Setup Rx + reset_rx(dev); + + dbg(3, __FUNCTION__ ": 1st/Curr Rx Desc Ptr0=%x/%x\n", + GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0), + GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0)); + + // eth port config register + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT, + pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrDPLXen); + + mii_reg = read_MII(gp->phy_addr, 0x11); /* int enable register */ + mii_reg |= 2; /* enable mii interrupt */ + write_MII(gp->phy_addr, 0x11, mii_reg); + + dbg(3, __FUNCTION__ ": PhyAD=%x\n", + GT96100_READ(GT96100_ETH_PHY_ADDR_REG)); + + // setup DMA // We want the Rx/Tx DMA to write/read data to/from memory in // Big Endian mode. Also set DMA Burst Size to 8 64Bit words. - // FIX! endian mode??? +#ifdef DESC_DATA_BE + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_CONFIG, + (0xf< 2) - printk("%s: gt96100_init: SDMA Config=%x\n", dev->name, - GT96100ETH_READ(gp, GT96100_ETH_SDMA_CONFIG)); + sdcrBLMR | sdcrBLMT | + (0xf< 2) - printk("%s: gt96100_init: SDMA Comm=%x\n", dev->name, - GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM)); - - // enable interrupts - enable_ether_irq(dev); - + dbg(3, __FUNCTION__ ": SDMA Comm=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM)); + + // enable this port (set hash size to 1/2K) + GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS); + dbg(3, __FUNCTION__ ": Port Config=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG)); + /* * Disable all Type-of-Service queueing. All Rx packets will be * treated normally and will be sent to the lowest priority * queue. * - * Disable flow-control for now. FIX! support flow control? + * Disable flow-control for now. FIXME: support flow control? */ + // clear all the MIB ctr regs - // Enable reg clear on read. FIX! desc of this bit is inconsistent - // in the GT-96100A datasheet. GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT, - pcxrFCTL | pcxrFCTLen | pcxrFLP); + pcxrFCTL | pcxrFCTLen | pcxrFLP | + pcxrPRIOrxOverride); read_mib_counters(gp); GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT, - pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrMIBclrMode); + pcxrFCTL | pcxrFCTLen | pcxrFLP | + pcxrPRIOrxOverride | pcxrMIBclrMode); + + dbg(3, __FUNCTION__ ": Port Config Ext=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT)); - if (gt96100_debug > 2) - printk("%s: gt96100_init: Port Config Ext=%x\n", dev->name, - GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT)); + netif_start_queue(dev); - // enable this port (set hash size to 1/2K) - GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS); - if (gt96100_debug > 2) - printk("%s: gt96100_init: Port Config=%x\n", dev->name, - GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG)); + dump_MII(4, dev); - // we should now be receiving frames - if (gt96100_debug > 2) - dump_MII(dev); + // enable interrupts + enable_ether_irq(dev); - spin_unlock_irqrestore(&gp->lock, flags); + // we should now be receiving frames return 0; } -static int gt96100_open(struct net_device *dev) +static int +gt96100_open(struct net_device *dev) { int retval; - + MOD_INC_USE_COUNT; - if (gt96100_debug > 2) - printk("%s: gt96100_open: dev=%p\n", dev->name, dev); + dbg(2, __FUNCTION__ ": dev=%p\n", dev); - if ((retval = request_irq(dev->irq, >96100_interrupt, - SA_SHIRQ, dev->name, dev))) { - printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, - dev->irq); - MOD_DEC_USE_COUNT; - return retval; - } // Initialize and startup the GT-96100 ethernet port if ((retval = gt96100_init(dev))) { - printk(KERN_ERR "%s: error in gt96100_init\n", dev->name); + err("error in gt96100_init\n"); free_irq(dev->irq, dev); MOD_DEC_USE_COUNT; return retval; } - netif_start_queue(dev); - - if (gt96100_debug > 2) - printk("%s: gt96100_open: Initialization done.\n", - dev->name); + if ((retval = request_irq(dev->irq, >96100_interrupt, + SA_SHIRQ, dev->name, dev))) { + err("unable to get IRQ %d\n", dev->irq); + MOD_DEC_USE_COUNT; + return retval; + } + + dbg(2, __FUNCTION__ ": Initialization done.\n"); return 0; } -static int gt96100_close(struct net_device *dev) +static int +gt96100_close(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; - int i; - - if (gt96100_debug > 2) - printk("%s: gt96100_close: dev=%p\n", dev->name, dev); + dbg(3, __FUNCTION__ ": dev=%p\n", dev); // stop the device if (netif_device_present(dev)) { netif_stop_queue(dev); hard_stop(dev); } - // free the Rx DMA buffers - for (i = 0; i < RX_RING_SIZE; i++) { - if (gp->rx_buff[i]) { - dmafree(PKT_BUF_SZ, gp->rx_buff[i]); - gp->rx_buff[i] = NULL; - } - } free_irq(dev->irq, dev); - + MOD_DEC_USE_COUNT; return 0; } -static int gt96100_tx(struct sk_buff *skb, struct net_device *dev) +static int +gt96100_tx(struct sk_buff *skb, struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; unsigned long flags; int nextIn; - if (gt96100_debug > 2) - printk("%s: gt96100_tx: skb->len=%d, skb->data=%p\n", - dev->name, skb->len, skb->data); - spin_lock_irqsave(&gp->lock, flags); + nextIn = gp->tx_next_in; + + dbg(3, __FUNCTION__ ": nextIn=%d\n", nextIn); + if (gp->tx_count >= TX_RING_SIZE) { - printk(KERN_WARNING - "%s: Tx Ring full, refusing to send buffer.\n", - dev->name); + warn("Tx Ring full, pkt dropped.\n"); gp->stats.tx_dropped++; spin_unlock_irqrestore(&gp->lock, flags); return 1; } - // Prepare the Descriptor at tx_next_in - nextIn = gp->tx_next_in; - + + if (!(gp->last_psr & psrLink)) { + err(__FUNCTION__ ": Link down, pkt dropped.\n"); + gp->stats.tx_dropped++; + spin_unlock_irqrestore(&gp->lock, flags); + return 1; + } + if (dma32_to_cpu(gp->tx_ring[nextIn].cmdstat) & txOwn) { - printk(KERN_ERR "%s: gt96100_tx: TxOwn bit wrong!!\n", - dev->name); + err(__FUNCTION__ ": device owns descriptor, pkt dropped.\n"); + gp->stats.tx_dropped++; + // stop the queue, so Tx timeout can fix it + netif_stop_queue(dev); + spin_unlock_irqrestore(&gp->lock, flags); + return 1; } - + + // Prepare the Descriptor at tx_next_in gp->tx_skbuff[nextIn] = skb; - gp->tx_ring[nextIn].byte_cnt = - cpu_to_dma32(skb->len << tdByteCntBit); - gp->tx_ring[nextIn].buff_ptr = - cpu_to_dma32(virt_to_phys(skb->data)); + gp->tx_ring[nextIn].byte_cnt = cpu_to_dma16(skb->len); + gp->tx_ring[nextIn].buff_ptr = cpu_to_dma32(virt_to_phys(skb->data)); + // make sure packet gets written back to memory + dma_cache_wback_inv((unsigned long)(skb->data), skb->len); // Give ownership to device, set first and last desc, enable interrupt // Setting of ownership bit must be *last*! gp->tx_ring[nextIn].cmdstat = - cpu_to_dma32((u32) (txOwn | txEI | txFirst | txLast)); + cpu_to_dma32((u32)(txOwn | txGenCRC | txEI | + txPad | txFirst | txLast)); + + dump_tx_desc(4, dev, nextIn); + dump_skb(4, dev, skb); // increment tx_next_in with wrap gp->tx_next_in = (nextIn + 1) % TX_RING_SIZE; - // If count is zero, DMA should be stopped, so restart - if (gp->tx_count == 0) { - if (GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS) & - psrTxLow) printk(KERN_WARNING - "%s: Tx count zero but Tx queue running!\n", - dev->name); + // If DMA is stopped, restart + if (!(GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS) & psrTxLow)) GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD | sdcmrTXDL); - } + // increment count and stop queue if full - if (++gp->tx_count == TX_RING_SIZE) + if (++gp->tx_count == TX_RING_SIZE) { + gp->tx_full = 1; netif_stop_queue(dev); - + dbg(2, "Tx Ring now full, queue stopped.\n"); + } + dev->trans_start = jiffies; spin_unlock_irqrestore(&gp->lock, flags); @@ -937,317 +1213,438 @@ } -static int gt96100_rx(struct net_device *dev, u32 status) +static int +gt96100_rx(struct net_device *dev, u32 status) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; struct sk_buff *skb; - int pkt_len, nextOut; + int pkt_len, nextOut, cdp; gt96100_rd_t *rd; u32 cmdstat; + + dbg(3, __FUNCTION__ ": dev=%p, status=%x\n", dev, status); - if (gt96100_debug > 2) - printk("%s: gt96100_rx: dev=%p, status = %x\n", - dev->name, dev, status); + cdp = (GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0) + - gp->rx_ring_dma) / sizeof(gt96100_rd_t); - // Continue until we reach the current descriptor pointer - for (nextOut = gp->rx_next_out; - nextOut != - (GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0) - - gp->rx_ring_dma) / sizeof(gt96100_rd_t); + // Continue until we reach 1st descriptor pointer + for (nextOut = gp->rx_next_out; nextOut != cdp; nextOut = (nextOut + 1) % RX_RING_SIZE) { + + if (--gp->intr_work_done == 0) + break; rd = &gp->rx_ring[nextOut]; cmdstat = dma32_to_cpu(rd->cmdstat); + + dbg(4, __FUNCTION__ ": Rx desc cmdstat=%x, nextOut=%d\n", + cmdstat, nextOut); + + if (cmdstat & (u32)rxOwn) { + //err(__FUNCTION__ ": device owns descriptor!\n"); + // DMA is not finished updating descriptor??? + // Leave and come back later to pick-up where + // we left off. + break; + } - if (cmdstat & (u32) rxOwn) { - cmdstat &= ~((u32) rxOwn); + // Drop this received pkt if there were any errors + if (((cmdstat & (u32)(rxErrorSummary)) && + (cmdstat & (u32)(rxFirst))) || (status & icrRxError)) { + // update the detailed rx error counters that + // are not covered by the MIB counters. + if (cmdstat & (u32)rxOverrun) + gp->stats.rx_fifo_errors++; + cmdstat |= (u32)rxOwn; rd->cmdstat = cpu_to_dma32(cmdstat); - printk(KERN_ERR - "%s: gt96100_rx: ownership bit wrong!\n", - dev->name); - } - // must be first and last (ie only) buffer of packet - if (!(cmdstat & (u32) rxFirst) - || !(cmdstat & (u32) rxLast)) { - printk(KERN_ERR - "%s: gt96100_rx: desc not first and last!\n", - dev->name); continue; } - // drop this received pkt if there were any errors - if ((cmdstat & (u32) rxErrorSummary) - || (status & icrRxErrorQ0)) { - // update the detailed rx error counters that are not covered - // by the MIB counters. - if (cmdstat & (u32) rxOverrun) - gp->stats.rx_fifo_errors++; + + /* + * Must be first and last (ie only) descriptor of packet. We + * ignore (drop) any packets that do not fit in one descriptor. + * Every descriptor's receive buffer is large enough to hold + * the maximum 802.3 frame size, so a multi-descriptor packet + * indicates an error. Most if not all corrupted packets will + * have already been dropped by the above check for the + * rxErrorSummary status bit. + */ + if (!(cmdstat & (u32)rxFirst) || !(cmdstat & (u32)rxLast)) { + if (cmdstat & (u32)rxFirst) { + /* + * This is the first descriptor of a + * multi-descriptor packet. It isn't corrupted + * because the above check for rxErrorSummary + * would have dropped it already, so what's + * the deal with this packet? Good question, + * let's dump it out. + */ + err(__FUNCTION__ + ": desc not first and last!\n"); + dump_rx_desc(0, dev, nextOut); + } + cmdstat |= (u32)rxOwn; + rd->cmdstat = cpu_to_dma32(cmdstat); + // continue to drop every descriptor of this packet continue; } - - pkt_len = dma32_to_cpu(rd->buff_cnt_sz) & rdByteCntMask; - + + pkt_len = dma16_to_cpu(rd->byte_cnt); + /* Create new skb. */ - skb = dev_alloc_skb(pkt_len + 2); + skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { - printk(KERN_ERR - "%s: Memory squeeze, dropping packet.\n", - dev->name); + err(__FUNCTION__ + ": Memory squeeze, dropping packet.\n"); gp->stats.rx_dropped++; + cmdstat |= (u32)rxOwn; + rd->cmdstat = cpu_to_dma32(cmdstat); continue; } skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte IP header align */ - skb_put(skb, pkt_len); /* Make room */ - eth_copy_and_sum(skb, gp->rx_buff[nextOut], pkt_len, 0); + skb_reserve(skb, 2); /* 16 byte IP header align */ + memcpy(skb_put(skb, pkt_len), + &gp->rx_buff[nextOut*PKT_BUF_SZ], pkt_len); skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); /* pass the packet to upper layers */ + dump_skb(4, dev, skb); + + netif_rx(skb); /* pass the packet to upper layers */ + dev->last_rx = jiffies; // now we can release ownership of this desc back to device - cmdstat |= (u32) rxOwn; + cmdstat |= (u32)rxOwn; rd->cmdstat = cpu_to_dma32(cmdstat); - - dev->last_rx = jiffies; } + + if (nextOut == gp->rx_next_out) + dbg(3, __FUNCTION__ ": RxCDP did not increment?\n"); gp->rx_next_out = nextOut; return 0; } -static void gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void +gt96100_tx_complete(struct net_device *dev, u32 status) { - struct net_device *dev = (struct net_device *) dev_id; - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; - u32 status; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + int nextOut, cdp; + gt96100_td_t *td; + u32 cmdstat; - if (dev == NULL) { - printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name); - return; + cdp = (GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0) + - gp->tx_ring_dma) / sizeof(gt96100_td_t); + + // Continue until we reach the current descriptor pointer + for (nextOut = gp->tx_next_out; nextOut != cdp; + nextOut = (nextOut + 1) % TX_RING_SIZE) { + + if (--gp->intr_work_done == 0) + break; + + td = &gp->tx_ring[nextOut]; + cmdstat = dma32_to_cpu(td->cmdstat); + + dbg(3, __FUNCTION__ ": Tx desc cmdstat=%x, nextOut=%d\n", + cmdstat, nextOut); + + if (cmdstat & (u32)txOwn) { + //dump_tx_ring(dev); + // DMA is not finished writing descriptor??? + // Leave and come back later to pick-up where + // we left off. + break; + } + + // increment Tx error stats + if (cmdstat & (u32)txErrorSummary) { + dbg(2, __FUNCTION__ ": Tx error, cmdstat = %x\n", + cmdstat); + gp->stats.tx_errors++; + if (cmdstat & (u32)txReTxLimit) + gp->stats.tx_aborted_errors++; + if (cmdstat & (u32)txUnderrun) + gp->stats.tx_fifo_errors++; + if (cmdstat & (u32)txLateCollision) + gp->stats.tx_window_errors++; + } + + if (cmdstat & (u32)txCollision) + gp->stats.collisions += + (u32)((cmdstat & txReTxCntMask) >> + txReTxCntBit); + + // Wake the queue if the ring was full + if (gp->tx_full) { + gp->tx_full = 0; + if (gp->last_psr & psrLink) { + netif_wake_queue(dev); + dbg(2, __FUNCTION__ + ": Tx Ring was full, queue waked\n"); + } + } + + // decrement tx ring buffer count + if (gp->tx_count) gp->tx_count--; + + // free the skb + if (gp->tx_skbuff[nextOut]) { + dbg(3, __FUNCTION__ ": good Tx, skb=%p\n", + gp->tx_skbuff[nextOut]); + dev_kfree_skb_irq(gp->tx_skbuff[nextOut]); + gp->tx_skbuff[nextOut] = NULL; + } else { + err(__FUNCTION__ ": no skb!\n"); + } } - status = GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE); - // ACK interrupts -#if 0 - GT96100ETH_CLRBIT(gp, GT96100_ETH_INT_CAUSE, - icrEtherIntSum | icrRxBufferQ1 | icrRxBufferQ2 | - icrRxBufferQ3 | icrRxBufferQ0 | icrTxBufferHigh | - icrTxEndHigh | icrTxBufferLow | icrTxEndLow | - icrTxErrorHigh | icrTxErrorLow | icrTxUdr); -#else - GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, 0); -#endif + gp->tx_next_out = nextOut; + + if (gt96100_check_tx_consistent(gp)) { + err(__FUNCTION__ ": Tx queue inconsistent!\n"); + } + + if ((status & icrTxEndLow) && gp->tx_count != 0) { + // we must restart the DMA + dbg(3, __FUNCTION__ ": Restarting Tx DMA\n"); + GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, + sdcmrERD | sdcmrTXDL); + } +} + - if ((status & icrEtherIntSum) == 0) { - // not our interrupt - //printk("%s: isr: no ints? icr=%x,cp0_cause=%x\n", - // dev->name, status, read_32bit_cp0_register(CP0_CAUSE)); +static void +gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + u32 status; + + if (dev == NULL) { + err(__FUNCTION__ ": null dev ptr\n"); return; } - if (gt96100_debug > 3) - printk("%s: isr: entry, icr=%x\n", dev->name, status); + dbg(3, __FUNCTION__ ": entry, icr=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE)); - if (status & (icrRxBufferQ1 | icrRxBufferQ2 | icrRxBufferQ3)) { - printk(KERN_ERR "%s: isr: Rx intr in unused queues!?\n", - dev->name); - } - - if (status & icrRxBufferQ0) { - gt96100_rx(dev, status); - } - - if (status & (icrTxBufferHigh | icrTxEndHigh)) { - printk(KERN_ERR "%s: isr: Tx intr in unused queue!?\n", - dev->name); - } - - if (status & icrMIIPhySTC) { - u32 psr = GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS); - printk("%s: port status:\n", dev->name); - printk - ("%s: %s MBit/s, %s-duplex, flow-control %s, link is %s,\n", - dev->name, psr & psrSpeed ? "100" : "10", - psr & psrDuplex ? "full" : "half", - psr & psrFctl ? "disabled" : "enabled", - psr & psrLink ? "up" : "down"); - printk - ("%s: TxLowQ is %s, TxHighQ is %s, Transmitter is %s\n", - dev->name, psr & psrTxLow ? "running" : "stopped", - psr & psrTxHigh ? "running" : "stopped", - psr & psrTxInProg ? "on" : "off"); - gp->last_psr = psr; - } - - if (status & (icrTxBufferLow | icrTxEndLow)) { - int nextOut; - gt96100_td_t *td; - u32 cmdstat; - - // Continue until we reach the current descriptor pointer - for (nextOut = gp->tx_next_out; - nextOut != - (GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0) - - gp->tx_ring_dma) / sizeof(gt96100_td_t); - nextOut = (nextOut + 1) % TX_RING_SIZE) { - - td = &gp->tx_ring[nextOut]; - cmdstat = dma32_to_cpu(td->cmdstat); - - if (gt96100_debug > 2) - printk("%s: isr: Tx desc cmdstat=%x\n", - dev->name, cmdstat); - - if (cmdstat & (u32) txOwn) { - cmdstat &= ~((u32) txOwn); - td->cmdstat = cpu_to_dma32(cmdstat); - printk(KERN_ERR - "%s: isr: Tx ownership bit wrong!\n", - dev->name); - } - // increment Tx error stats - if (cmdstat & (u32) txErrorSummary) { - if (gt96100_debug > 2) - printk - ("%s: gt96100_interrupt: Tx error, cmdstat = %x\n", - dev->name, cmdstat); - gp->stats.tx_errors++; - if (cmdstat & (u32) txReTxLimit) - gp->stats.collisions++; - if (cmdstat & (u32) txUnderrun) - gp->stats.tx_fifo_errors++; - if (cmdstat & (u32) txLateCollision) - gp->stats.tx_window_errors++; - } - // Wake the queue if the ring was full - if (gp->tx_count == TX_RING_SIZE) - netif_wake_queue(dev); + spin_lock(&gp->lock); - // decrement tx ring buffer count - if (gp->tx_count) - gp->tx_count--; - - // free the skb - if (gp->tx_skbuff[nextOut]) { - if (gt96100_debug > 2) - printk - ("%s: isr: good Tx, skb=%p\n", - dev->name, - gp->tx_skbuff[nextOut]); - dev_kfree_skb_irq(gp->tx_skbuff[nextOut]); - gp->tx_skbuff[nextOut] = NULL; - } else { - printk(KERN_ERR "%s: isr: no skb!\n", - dev->name); - } - } + gp->intr_work_done = max_interrupt_work; - if (gp->tx_count == 0 && nextOut != gp->tx_next_in) { - // FIX! this should probably be a panic - printk(KERN_ERR - "%s: isr: warning! Tx queue inconsistent\n", - dev->name); - } + while (gp->intr_work_done > 0) { - gp->tx_next_out = nextOut; + status = GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE); + // ACK interrupts + GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, ~status); - if ((status & icrTxEndLow) && gp->tx_count != 0) { - // we must restart the DMA - if (gt96100_debug > 2) - printk("%s: isr: Restarting Tx DMA\n", - dev->name); - GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, - sdcmrERD | sdcmrTXDL); - } - } - // Now check TX errors (RX errors were handled in gt96100_rx) + if ((status & icrEtherIntSum) == 0 && + !(status & (icrTxBufferLow|icrTxBufferHigh|icrRxBuffer))) + break; + + if (status & icrMIIPhySTC) { + u32 psr = GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS); + if (gp->last_psr != psr) { + dbg(0, "port status:\n"); + dbg(0, " %s MBit/s, %s-duplex, " + "flow-control %s, link is %s,\n", + psr & psrSpeed ? "100":"10", + psr & psrDuplex ? "full":"half", + psr & psrFctl ? "disabled":"enabled", + psr & psrLink ? "up":"down"); + dbg(0, " TxLowQ is %s, TxHighQ is %s, " + "Transmitter is %s\n", + psr & psrTxLow ? "running":"stopped", + psr & psrTxHigh ? "running":"stopped", + psr & psrTxInProg ? "on":"off"); + + if ((psr & psrLink) && !gp->tx_full && + netif_queue_stopped(dev)) { + dbg(0, __FUNCTION__ + ": Link up, waking queue.\n"); + netif_wake_queue(dev); + } else if (!(psr & psrLink) && + !netif_queue_stopped(dev)) { + dbg(0, __FUNCTION__ + "Link down, stopping queue.\n"); + netif_stop_queue(dev); + } - if (status & icrTxErrorHigh) { - printk(KERN_ERR - "%s: isr: Tx resource error in unused queue!?\n", - dev->name); - } + gp->last_psr = psr; + } - if (status & icrTxErrorLow) { - printk(KERN_ERR "%s: isr: Tx resource error\n", dev->name); - } + if (--gp->intr_work_done == 0) + break; + } + + if (status & (icrTxBufferLow | icrTxEndLow)) + gt96100_tx_complete(dev, status); - if (status & icrTxUdr) { - printk(KERN_ERR "%s: isr: Tx underrun error\n", dev->name); + if (status & (icrRxBuffer | icrRxError)) { + gt96100_rx(dev, status); + } + + // Now check TX errors (RX errors were handled in gt96100_rx) + if (status & icrTxErrorLow) { + err(__FUNCTION__ ": Tx resource error\n"); + if (--gp->intr_work_done == 0) + break; + } + + if (status & icrTxUdr) { + err(__FUNCTION__ ": Tx underrun error\n"); + if (--gp->intr_work_done == 0) + break; + } } - if (gt96100_debug > 3) - printk("%s: isr: exit, icr=%x\n", - dev->name, GT96100ETH_READ(gp, - GT96100_ETH_INT_CAUSE)); + if (gp->intr_work_done == 0) { + // ACK any remaining pending interrupts + GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, 0); + dbg(3, __FUNCTION__ ": hit max work\n"); + } + + dbg(3, __FUNCTION__ ": exit, icr=%x\n", + GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE)); + + spin_unlock(&gp->lock); } -/* - * The Tx ring has been full longer than the watchdog timeout - * value, meaning that the interrupt routine has not been freeing - * up space in the Tx ring buffer. - */ -static void gt96100_tx_timeout(struct net_device *dev) +static void +gt96100_tx_timeout(struct net_device *dev) { -// struct gt96100_private *gp = (struct gt96100_private *)dev->priv; - - printk(KERN_ERR "%s: gt96100_tx_timeout: dev=%p\n", dev->name, - dev); + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + unsigned long flags; + + spin_lock_irqsave(&gp->lock, flags); + + if (!(gp->last_psr & psrLink)) { + err("tx_timeout: link down.\n"); + spin_unlock_irqrestore(&gp->lock, flags); + } else { + if (gt96100_check_tx_consistent(gp)) + err("tx_timeout: Tx ring error.\n"); - // FIX! do something, like reset the device + disable_ether_irq(dev); + spin_unlock_irqrestore(&gp->lock, flags); + reset_tx(dev); + enable_ether_irq(dev); + + netif_wake_queue(dev); + } } -static void gt96100_set_rx_mode(struct net_device *dev) +static void +gt96100_set_rx_mode(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; unsigned long flags; - struct dev_mc_list *mcptr; - - if (gt96100_debug > 2) - printk("%s: gt96100_set_rx_mode: dev=%p, flags=%x\n", - dev->name, dev, dev->flags); + //struct dev_mc_list *mcptr; + + dbg(3, __FUNCTION__ ": dev=%p, flags=%x\n", dev, dev->flags); // stop the Receiver DMA abort(dev, sdcmrAR); spin_lock_irqsave(&gp->lock, flags); - if (dev->flags & IFF_PROMISC) + if (dev->flags & IFF_PROMISC) { GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS | pcrPM); + } - memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear hash table - // Add our ethernet address - gt96100_add_hash_entry(dev, dev->dev_addr); - +#if 0 + /* + FIXME: currently multicast doesn't work - need to get hash table + working first. + */ if (dev->mc_count) { + // clear hash table + memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); + // Add our ethernet address + gt96100_add_hash_entry(dev, dev->dev_addr); + for (mcptr = dev->mc_list; mcptr; mcptr = mcptr->next) { + dump_hw_addr(2, dev, __FUNCTION__ ": addr=", + mcptr->dmi_addr); gt96100_add_hash_entry(dev, mcptr->dmi_addr); } } +#endif + // restart Rx DMA GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD); spin_unlock_irqrestore(&gp->lock, flags); } -static struct net_device_stats *gt96100_get_stats(struct net_device *dev) +static struct net_device_stats * +gt96100_get_stats(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *) dev->priv; + struct gt96100_private *gp = (struct gt96100_private *)dev->priv; unsigned long flags; - if (gt96100_debug > 2) - printk("%s: gt96100_get_stats: dev=%p\n", dev->name, dev); + dbg(3, __FUNCTION__ ": dev=%p\n", dev); if (netif_device_present(dev)) { - spin_lock_irqsave(&gp->lock, flags); + spin_lock_irqsave (&gp->lock, flags); update_stats(gp); - spin_unlock_irqrestore(&gp->lock, flags); + spin_unlock_irqrestore (&gp->lock, flags); } return &gp->stats; } -module_init(gt96100_probe); -MODULE_LICENSE("GPL"); +static void gt96100_cleanup_module(void) +{ + int i; + for (i=0; idev != NULL) { + struct gt96100_private *gp = + (struct gt96100_private *)gtif->dev->priv; + release_region(gtif->iobase, gp->io_size); + unregister_netdev(gtif->dev); + if (gtif->dev->priv != NULL) + kfree (gtif->dev->priv); + kfree (gtif->dev); + } + } +} + + +#ifndef MODULE + +static int __init gt96100_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + for(this_opt=strtok(options, ","); + this_opt; this_opt=strtok(NULL, ",")) { + if (!strncmp(this_opt, "mac0:", 5)) { + memcpy(mac0, this_opt+5, 17); + mac0[17]= '\0'; + } else if (!strncmp(this_opt, "mac1:", 5)) { + memcpy(mac1, this_opt+5, 17); + mac1[17]= '\0'; + } + } + + return 1; +} + +__setup("gt96100eth=", gt96100_setup); + +#endif /* !MODULE */ + + +module_init(gt96100_init_module); +module_exit(gt96100_cleanup_module); + +MODULE_AUTHOR("Steve Longerbeam "); +MODULE_DESCRIPTION("GT96100 Ethernet driver"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/gt96100eth.h linux-2.5/drivers/net/gt96100eth.h --- linux-2.5.5/drivers/net/gt96100eth.h Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/net/gt96100eth.h Sun Mar 3 17:54:35 2002 @@ -29,29 +29,43 @@ #include +#define dbg(lvl, format, arg...) \ + if (lvl <= GT96100_DEBUG) \ + printk(KERN_DEBUG "%s: " format, dev->name , ## arg) +#define err(format, arg...) \ + printk(KERN_ERR "%s: " format, dev->name , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO "%s: " format, dev->name , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING "%s: " format, dev->name , ## arg) + /* Keep the ring sizes a power of two for efficiency. */ #define TX_RING_SIZE 16 #define RX_RING_SIZE 32 -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ #define RX_HASH_TABLE_SIZE 16384 #define HASH_HOP_NUMBER 12 #define NUM_INTERFACES 2 -#define GT96100ETH_TX_TIMEOUT HZ +#define GT96100ETH_TX_TIMEOUT HZ/4 #define GT96100_ETH0_BASE (MIPS_GT96100_BASE + GT96100_ETH_PORT_CONFIG) #define GT96100_ETH1_BASE (GT96100_ETH0_BASE + GT96100_ETH_IO_SIZE) #ifdef CONFIG_MIPS_EV96100 -#define GT96100_ETHER0_IRQ 4 +#define GT96100_ETHER0_IRQ 3 #define GT96100_ETHER1_IRQ 4 #else #define GT96100_ETHER0_IRQ -1 #define GT96100_ETHER1_IRQ -1 #endif +#define REV_GT96100 1 +#define REV_GT96100A_1 2 +#define REV_GT96100A 3 + #define GT96100ETH_READ(gp, offset) \ GT96100_READ((gp->port_offset + offset)) @@ -70,13 +84,13 @@ /* Bit definitions of the SMI Reg */ enum { smirDataMask = 0xffff, - smirPhyAdMask = 0x1f << 16, + smirPhyAdMask = 0x1f<<16, smirPhyAdBit = 16, - smirRegAdMask = 0x1f << 21, + smirRegAdMask = 0x1f<<21, smirRegAdBit = 21, - smirOpCode = 1 << 26, - smirReadValid = 1 << 27, - smirBusy = 1 << 28 + smirOpCode = 1<<26, + smirReadValid = 1<<27, + smirBusy = 1<<28 }; /* Bit definitions of the Port Config Reg */ @@ -84,17 +98,17 @@ pcrPM = 1, pcrRBM = 2, pcrPBF = 4, - pcrEN = 1 << 7, - pcrLPBKMask = 0x3 << 8, + pcrEN = 1<<7, + pcrLPBKMask = 0x3<<8, pcrLPBKBit = 8, - pcrFC = 1 << 10, - pcrHS = 1 << 12, - pcrHM = 1 << 13, - pcrHDM = 1 << 14, - pcrHD = 1 << 15, - pcrISLMask = 0x7 << 28, + pcrFC = 1<<10, + pcrHS = 1<<12, + pcrHM = 1<<13, + pcrHDM = 1<<14, + pcrHD = 1<<15, + pcrISLMask = 0x7<<28, pcrISLBit = 28, - pcrACCS = 1 << 31 + pcrACCS = 1<<31 }; /* Bit definitions of the Port Config Extend Reg */ @@ -102,27 +116,27 @@ pcxrIGMP = 1, pcxrSPAN = 2, pcxrPAR = 4, - pcxrPRIOtxMask = 0x7 << 3, + pcxrPRIOtxMask = 0x7<<3, pcxrPRIOtxBit = 3, - pcxrPRIOrxMask = 0x3 << 6, + pcxrPRIOrxMask = 0x3<<6, pcxrPRIOrxBit = 6, - pcxrPRIOrxOverride = 1 << 8, - pcxrDPLXen = 1 << 9, - pcxrFCTLen = 1 << 10, - pcxrFLP = 1 << 11, - pcxrFCTL = 1 << 12, - pcxrMFLMask = 0x3 << 14, + pcxrPRIOrxOverride = 1<<8, + pcxrDPLXen = 1<<9, + pcxrFCTLen = 1<<10, + pcxrFLP = 1<<11, + pcxrFCTL = 1<<12, + pcxrMFLMask = 0x3<<14, pcxrMFLBit = 14, - pcxrMIBclrMode = 1 << 16, - pcxrSpeed = 1 << 18, - pcxrSpeeden = 1 << 19, - pcxrRMIIen = 1 << 20, - pcxrDSCPen = 1 << 21 + pcxrMIBclrMode = 1<<16, + pcxrSpeed = 1<<18, + pcxrSpeeden = 1<<19, + pcxrRMIIen = 1<<20, + pcxrDSCPen = 1<<21 }; /* Bit definitions of the Port Command Reg */ enum pcmr_bits { - pcmrFJ = 1 << 15 + pcmrFJ = 1<<15 }; @@ -132,119 +146,124 @@ psrDuplex = 2, psrFctl = 4, psrLink = 8, - psrPause = 1 << 4, - psrTxLow = 1 << 5, - psrTxHigh = 1 << 6, - psrTxInProg = 1 << 7 + psrPause = 1<<4, + psrTxLow = 1<<5, + psrTxHigh = 1<<6, + psrTxInProg = 1<<7 }; /* Bit definitions of the SDMA Config Reg */ enum sdcr_bits { - sdcrRCMask = 0xf << 2, + sdcrRCMask = 0xf<<2, sdcrRCBit = 2, - sdcrBLMR = 1 << 6, - sdcrBLMT = 1 << 7, - sdcrPOVR = 1 << 8, - sdcrRIFB = 1 << 9, - sdcrBSZMask = 0x3 << 12, + sdcrBLMR = 1<<6, + sdcrBLMT = 1<<7, + sdcrPOVR = 1<<8, + sdcrRIFB = 1<<9, + sdcrBSZMask = 0x3<<12, sdcrBSZBit = 12 }; /* Bit definitions of the SDMA Command Reg */ enum sdcmr_bits { - sdcmrERD = 1 << 7, - sdcmrAR = 1 << 15, - sdcmrSTDH = 1 << 16, - sdcmrSTDL = 1 << 17, - sdcmrTXDH = 1 << 23, - sdcmrTXDL = 1 << 24, - sdcmrAT = 1 << 31 + sdcmrERD = 1<<7, + sdcmrAR = 1<<15, + sdcmrSTDH = 1<<16, + sdcmrSTDL = 1<<17, + sdcmrTXDH = 1<<23, + sdcmrTXDL = 1<<24, + sdcmrAT = 1<<31 }; /* Bit definitions of the Interrupt Cause Reg */ enum icr_bits { icrRxBuffer = 1, - icrTxBufferHigh = 1 << 2, - icrTxBufferLow = 1 << 3, - icrTxEndHigh = 1 << 6, - icrTxEndLow = 1 << 7, - icrRxError = 1 << 8, - icrTxErrorHigh = 1 << 10, - icrTxErrorLow = 1 << 11, - icrRxOVR = 1 << 12, - icrTxUdr = 1 << 13, - icrRxBufferQ0 = 1 << 16, - icrRxBufferQ1 = 1 << 17, - icrRxBufferQ2 = 1 << 18, - icrRxBufferQ3 = 1 << 19, - icrRxErrorQ0 = 1 << 20, - icrRxErrorQ1 = 1 << 21, - icrRxErrorQ2 = 1 << 22, - icrRxErrorQ3 = 1 << 23, - icrMIIPhySTC = 1 << 28, - icrSMIdone = 1 << 29, - icrEtherIntSum = 1 << 31 + icrTxBufferHigh = 1<<2, + icrTxBufferLow = 1<<3, + icrTxEndHigh = 1<<6, + icrTxEndLow = 1<<7, + icrRxError = 1<<8, + icrTxErrorHigh = 1<<10, + icrTxErrorLow = 1<<11, + icrRxOVR = 1<<12, + icrTxUdr = 1<<13, + icrRxBufferQ0 = 1<<16, + icrRxBufferQ1 = 1<<17, + icrRxBufferQ2 = 1<<18, + icrRxBufferQ3 = 1<<19, + icrRxErrorQ0 = 1<<20, + icrRxErrorQ1 = 1<<21, + icrRxErrorQ2 = 1<<22, + icrRxErrorQ3 = 1<<23, + icrMIIPhySTC = 1<<28, + icrSMIdone = 1<<29, + icrEtherIntSum = 1<<31 }; /* The Rx and Tx descriptor lists. */ - typedef struct { +#ifdef DESC_BE + u16 byte_cnt; + u16 reserved; +#else + u16 reserved; + u16 byte_cnt; +#endif u32 cmdstat; - u32 byte_cnt; - u32 buff_ptr; u32 next; -} gt96100_td_t; - -#define tdByteCntBit 16 + u32 buff_ptr; +} gt96100_td_t __attribute__ ((packed)); typedef struct { +#ifdef DESC_BE + u16 buff_sz; + u16 byte_cnt; +#else + u16 byte_cnt; + u16 buff_sz; +#endif u32 cmdstat; - u32 buff_cnt_sz; - u32 buff_ptr; u32 next; -} gt96100_rd_t; - -#define rdBuffSzBit 16 -#define rdByteCntMask 0xffff + u32 buff_ptr; +} gt96100_rd_t __attribute__ ((packed)); /* Values for the Tx command-status descriptor entry. */ enum td_cmdstat { - txOwn = 1 << 31, - txAutoMode = 1 << 30, - txEI = 1 << 23, - txGenCRC = 1 << 22, - txPad = 1 << 18, - txFirst = 1 << 17, - txLast = 1 << 16, - txErrorSummary = 1 << 15, - txReTxCntMask = 0x0f << 10, + txOwn = 1<<31, + txAutoMode = 1<<30, + txEI = 1<<23, + txGenCRC = 1<<22, + txPad = 1<<18, + txFirst = 1<<17, + txLast = 1<<16, + txErrorSummary = 1<<15, + txReTxCntMask = 0x0f<<10, txReTxCntBit = 10, - txCollision = 1 << 9, - txReTxLimit = 1 << 8, - txUnderrun = 1 << 6, - txLateCollision = 1 << 5 + txCollision = 1<<9, + txReTxLimit = 1<<8, + txUnderrun = 1<<6, + txLateCollision = 1<<5 }; -#define TxReTxCntBit 10 /* Values for the Rx command-status descriptor entry. */ enum rd_cmdstat { - rxOwn = 1 << 31, - rxAutoMode = 1 << 30, - rxEI = 1 << 23, - rxFirst = 1 << 17, - rxLast = 1 << 16, - rxErrorSummary = 1 << 15, - rxIGMP = 1 << 14, - rxHashExpired = 1 << 13, - rxMissedFrame = 1 << 12, - rxFrameType = 1 << 11, - rxShortFrame = 1 << 8, - rxMaxFrameLen = 1 << 7, - rxOverrun = 1 << 6, - rxCollision = 1 << 4, + rxOwn = 1<<31, + rxAutoMode = 1<<30, + rxEI = 1<<23, + rxFirst = 1<<17, + rxLast = 1<<16, + rxErrorSummary = 1<<15, + rxIGMP = 1<<14, + rxHashExpired = 1<<13, + rxMissedFrame = 1<<12, + rxFrameType = 1<<11, + rxShortFrame = 1<<8, + rxMaxFrameLen = 1<<7, + rxOverrun = 1<<6, + rxCollision = 1<<4, rxCRCError = 1 }; @@ -286,40 +305,44 @@ struct gt96100_private { - gt96100_rd_t *rx_ring; - gt96100_td_t *tx_ring; + gt96100_rd_t* rx_ring; + gt96100_td_t* tx_ring; // The Rx and Tx rings must be 16-byte aligned dma_addr_t rx_ring_dma; dma_addr_t tx_ring_dma; - char *hash_table; + char* hash_table; // The Hash Table must be 8-byte aligned dma_addr_t hash_table_dma; int hash_mode; - + // The Rx buffers must be 8-byte aligned - char *rx_buff[RX_RING_SIZE]; + char* rx_buff; + dma_addr_t rx_buff_dma; // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes // of payload must be 8-byte aligned - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - int rx_next_out; /* The next free ring entry to receive */ - int tx_next_in; /* The next free ring entry to send */ - int tx_next_out; /* The last ring entry the ISR processed */ - int tx_count; /* current # of pkts waiting to be sent in Tx ring */ - + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + int rx_next_out; /* The next free ring entry to receive */ + int tx_next_in; /* The next free ring entry to send */ + int tx_next_out; /* The last ring entry the ISR processed */ + int tx_count; /* current # of pkts waiting to be sent in Tx ring */ + int intr_work_done; /* number of Rx and Tx pkts processed in the isr */ + int tx_full; /* Tx ring is full */ + mib_counters_t mib; struct net_device_stats stats; int io_size; - int port_num; // 0 or 1 + int port_num; // 0 or 1 + int chip_rev; u32 port_offset; + + int phy_addr; // PHY address + u32 last_psr; // last value of the port status register - int phy_addr; // PHY address - u32 last_psr; // last value of the port status register - - int options; /* User-settable misc. driver options. */ + int options; /* User-settable misc. driver options. */ int drv_flags; - unsigned char phys[2]; /* MII device addresses. */ - spinlock_t lock; /* Serialise access to device */ + struct timer_list timer; + spinlock_t lock; /* Serialise access to device */ }; #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hamachi.c linux-2.5/drivers/net/hamachi.c --- linux-2.5.5/drivers/net/hamachi.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/net/hamachi.c Sun Feb 17 23:08:54 2002 @@ -1978,7 +1978,7 @@ } -static void __exit hamachi_remove_one (struct pci_dev *pdev) +static void __devexit hamachi_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -2008,7 +2008,7 @@ name: DRV_NAME, id_table: hamachi_pci_tbl, probe: hamachi_init_one, - remove: hamachi_remove_one, + remove: __devexit_p(hamachi_remove_one), }; static int __init hamachi_init (void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hamradio/6pack.c linux-2.5/drivers/net/hamradio/6pack.c --- linux-2.5.5/drivers/net/hamradio/6pack.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/net/hamradio/6pack.c Sun Mar 3 20:15:15 2002 @@ -256,6 +256,7 @@ skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_AX25); netif_rx(skb); + sp->dev->last_rx = jiffies; sp->stats.rx_packets++; } @@ -700,7 +701,6 @@ /* Initialize 6pack control device -- register 6pack line discipline */ static char msg_banner[] __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION " (dynamic channels, max=%d)\n"; -static char msg_invparm[] __initdata = KERN_ERR "6pack: sixpack_maxdev parameter too large.\n"; static char msg_nomem[] __initdata = KERN_ERR "6pack: can't allocate sixpack_ctrls[] array! No 6pack available.\n"; static char msg_regfail[] __initdata = KERN_ERR "6pack: can't register line discipline (err = %d)\n"; @@ -1063,6 +1063,7 @@ MODULE_AUTHOR("Andreas Könsgen "); MODULE_DESCRIPTION("6pack driver for AX.25"); +MODULE_LICENSE("GPL"); module_init(sixpack_init_driver); module_exit(sixpack_exit_driver); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hamradio/Makefile linux-2.5/drivers/net/hamradio/Makefile --- linux-2.5.5/drivers/net/hamradio/Makefile Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/net/hamradio/Makefile Mon Feb 4 22:15:16 2002 @@ -7,7 +7,7 @@ # Joerg Reuter DL1BKE # # 20000806 Rewritten to use lists instead of if-statements. -# Christoph Hellwig +# Christoph Hellwig # diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hamradio/baycom_epp.c linux-2.5/drivers/net/hamradio/baycom_epp.c --- linux-2.5.5/drivers/net/hamradio/baycom_epp.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/net/hamradio/baycom_epp.c Sun Mar 3 20:15:15 2002 @@ -706,6 +706,7 @@ skb->protocol = htons(ETH_P_AX25); skb->mac.raw = skb->data; netif_rx(skb); + dev->last = jiffies; bc->stats.rx_packets++; } @@ -1415,6 +1416,7 @@ MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); MODULE_DESCRIPTION("Baycom epp amateur radio modem driver"); +MODULE_LICENSE("GPL"); /* --------------------------------------------------------------------- */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hamradio/baycom_par.c linux-2.5/drivers/net/hamradio/baycom_par.c --- linux-2.5.5/drivers/net/hamradio/baycom_par.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/net/hamradio/baycom_par.c Fri Feb 8 15:46:33 2002 @@ -493,6 +493,7 @@ MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); MODULE_DESCRIPTION("Baycom par96 and picpar amateur radio modem driver"); +MODULE_LICENSE("GPL"); /* --------------------------------------------------------------------- */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hamradio/baycom_ser_fdx.c linux-2.5/drivers/net/hamradio/baycom_ser_fdx.c --- linux-2.5.5/drivers/net/hamradio/baycom_ser_fdx.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/net/hamradio/baycom_ser_fdx.c Fri Feb 8 15:46:33 2002 @@ -609,6 +609,7 @@ MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); MODULE_DESCRIPTION("Baycom ser12 full duplex amateur radio modem driver"); +MODULE_LICENSE("GPL"); /* --------------------------------------------------------------------- */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hamradio/baycom_ser_hdx.c linux-2.5/drivers/net/hamradio/baycom_ser_hdx.c --- linux-2.5.5/drivers/net/hamradio/baycom_ser_hdx.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/net/hamradio/baycom_ser_hdx.c Fri Feb 8 15:46:33 2002 @@ -649,6 +649,7 @@ MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); MODULE_DESCRIPTION("Baycom ser12 half duplex amateur radio modem driver"); +MODULE_LICENSE("GPL"); /* --------------------------------------------------------------------- */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hamradio/bpqether.c linux-2.5/drivers/net/hamradio/bpqether.c --- linux-2.5.5/drivers/net/hamradio/bpqether.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/net/hamradio/bpqether.c Sun Mar 3 20:15:15 2002 @@ -254,6 +254,7 @@ skb->pkt_type = PACKET_HOST; netif_rx(skb); + dev->last_rx = jiffies; return 0; } @@ -644,5 +645,6 @@ MODULE_AUTHOR("Joerg Reuter DL1BKE "); MODULE_DESCRIPTION("Transmit and receive AX.25 packets over Ethernet"); +MODULE_LICENSE("GPL"); module_init(bpq_init_driver); module_exit(bpq_cleanup_driver); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hamradio/dmascc.c linux-2.5/drivers/net/hamradio/dmascc.c --- linux-2.5.5/drivers/net/hamradio/dmascc.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/net/hamradio/dmascc.c Sun Mar 3 20:15:15 2002 @@ -305,6 +305,7 @@ MODULE_AUTHOR("Klaus Kudielka"); MODULE_DESCRIPTION("Driver for high-speed SCC boards"); MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i"); +MODULE_LICENSE("GPL"); int init_module(void) { @@ -1121,6 +1122,7 @@ skb->protocol = ntohs(ETH_P_AX25); skb->mac.raw = skb->data; netif_rx(skb); + priv->dev->last_rx = jiffies; priv->stats.rx_packets++; priv->stats.rx_bytes += cb; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hamradio/hdlcdrv.c linux-2.5/drivers/net/hamradio/hdlcdrv.c --- linux-2.5.5/drivers/net/hamradio/hdlcdrv.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/net/hamradio/hdlcdrv.c Sun Mar 3 20:15:15 2002 @@ -223,6 +223,7 @@ skb->protocol = htons(ETH_P_AX25); skb->mac.raw = skb->data; netif_rx(skb); + dev->last_rx = jiffies; s->stats.rx_packets++; } @@ -901,6 +902,7 @@ MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder"); +MODULE_LICENSE("GPL"); module_init(hdlcdrv_init_driver); module_exit(hdlcdrv_cleanup_driver); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hamradio/mkiss.c linux-2.5/drivers/net/hamradio/mkiss.c --- linux-2.5.5/drivers/net/hamradio/mkiss.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/net/hamradio/mkiss.c Sun Mar 3 20:15:15 2002 @@ -345,6 +345,7 @@ skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_AX25); netif_rx(skb); + tmp_ax->dev->last_rx = jiffies; tmp_ax->rx_packets++; } @@ -1007,6 +1008,7 @@ MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); MODULE_PARM(ax25_maxdev, "i"); MODULE_PARM_DESC(ax25_maxdev, "number of MKISS devices"); +MODULE_LICENSE("GPL"); module_init(mkiss_init_driver); module_exit(mkiss_exit_driver); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hamradio/scc.c linux-2.5/drivers/net/hamradio/scc.c --- linux-2.5.5/drivers/net/hamradio/scc.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/net/hamradio/scc.c Sun Mar 3 20:15:15 2002 @@ -1661,6 +1661,7 @@ skb->pkt_type = PACKET_HOST; netif_rx(skb); + scc->dev->last_rx = jiffies; return; } @@ -2179,5 +2180,6 @@ MODULE_AUTHOR("Joerg Reuter "); MODULE_DESCRIPTION("AX.25 Device Driver for Z8530 based HDLC cards"); MODULE_SUPPORTED_DEVICE("Z8530 based SCC cards for Amateur Radio"); +MODULE_LICENSE("GPL"); module_init(scc_init_driver); module_exit(scc_cleanup_driver); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hamradio/yam.c linux-2.5/drivers/net/hamradio/yam.c --- linux-2.5.5/drivers/net/hamradio/yam.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/net/hamradio/yam.c Sun Mar 3 20:15:15 2002 @@ -308,7 +308,8 @@ static void delay(int ms) { unsigned long timeout = jiffies + ((ms * HZ) / 1000); - while (jiffies < timeout); + while (time_before(jiffies, timeout)) + cpu_relax(); } /* @@ -528,6 +529,7 @@ skb->protocol = htons(ETH_P_AX25); skb->mac.raw = skb->data; netif_rx(skb); + dev->last_rx = jiffies; ++yp->stats.rx_packets; } } @@ -1177,6 +1179,7 @@ MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr"); MODULE_DESCRIPTION("Yam amateur radio modem driver"); +MODULE_LICENSE("GPL"); module_init(yam_init_driver); module_exit(yam_cleanup_driver); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/hp100.c linux-2.5/drivers/net/hp100.c --- linux-2.5.5/drivers/net/hp100.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/net/hp100.c Mon Feb 18 22:56:49 2002 @@ -83,7 +83,10 @@ ** */ +#include // Kill me. +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #define HP100_DEFAULT_PRIORITY_TX 0 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/i82586.h linux-2.5/drivers/net/i82586.h --- linux-2.5.5/drivers/net/i82586.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/i82586.h Tue Jan 22 17:43:48 2002 @@ -0,0 +1,413 @@ +/* + * Intel 82586 IEEE 802.3 Ethernet LAN Coprocessor. + * + * See: + * Intel Microcommunications 1991 + * p1-1 to p1-37 + * Intel order No. 231658 + * ISBN 1-55512-119-5 + * + * Unfortunately, the above chapter mentions neither + * the System Configuration Pointer (SCP) nor the + * Intermediate System Configuration Pointer (ISCP), + * so we probably need to look elsewhere for the + * whole story -- some recommend the "Intel LAN + * Components manual" but I have neither a copy + * nor a full reference. But "elsewhere" may be + * in the same publication... + * The description of a later device, the + * "82596CA High-Performance 32-Bit Local Area Network + * Coprocessor", (ibid. p1-38 to p1-109) does mention + * the SCP and ISCP and also has an i82586 compatibility + * mode. Even more useful is "AP-235 An 82586 Data Link + * Driver" (ibid. p1-337 to p1-417). + */ + +#define I82586_MEMZ (64 * 1024) + +#define I82586_SCP_ADDR (I82586_MEMZ - sizeof(scp_t)) + +#define ADDR_LEN 6 +#define I82586NULL 0xFFFF + +#define toff(t,p,f) (unsigned short)((void *)(&((t *)((void *)0 + (p)))->f) - (void *)0) + +/* + * System Configuration Pointer (SCP). + */ +typedef struct scp_t scp_t; +struct scp_t +{ + unsigned short scp_sysbus; /* 82586 bus width: */ +#define SCP_SY_16BBUS (0x0 << 0) /* 16 bits */ +#define SCP_SY_8BBUS (0x1 << 0) /* 8 bits. */ + unsigned short scp_junk[2]; /* Unused */ + unsigned short scp_iscpl; /* lower 16 bits of ISCP_ADDR */ + unsigned short scp_iscph; /* upper 16 bits of ISCP_ADDR */ +}; + +/* + * Intermediate System Configuration Pointer (ISCP). + */ +typedef struct iscp_t iscp_t; +struct iscp_t +{ + unsigned short iscp_busy; /* set by CPU before first CA, */ + /* cleared by 82586 after read. */ + unsigned short iscp_offset; /* offset of SCB */ + unsigned short iscp_basel; /* base of SCB */ + unsigned short iscp_baseh; /* " */ +}; + +/* + * System Control Block (SCB). + * The 82586 writes its status to scb_status and then + * raises an interrupt to alert the CPU. + * The CPU writes a command to scb_command and + * then issues a Channel Attention (CA) to alert the 82586. + */ +typedef struct scb_t scb_t; +struct scb_t +{ + unsigned short scb_status; /* Status of 82586 */ +#define SCB_ST_INT (0xF << 12) /* Some of: */ +#define SCB_ST_CX (0x1 << 15) /* Cmd completed */ +#define SCB_ST_FR (0x1 << 14) /* Frame received */ +#define SCB_ST_CNA (0x1 << 13) /* Cmd unit not active */ +#define SCB_ST_RNR (0x1 << 12) /* Rcv unit not ready */ +#define SCB_ST_JUNK0 (0x1 << 11) /* 0 */ +#define SCB_ST_CUS (0x7 << 8) /* Cmd unit status */ +#define SCB_ST_CUS_IDLE (0 << 8) /* Idle */ +#define SCB_ST_CUS_SUSP (1 << 8) /* Suspended */ +#define SCB_ST_CUS_ACTV (2 << 8) /* Active */ +#define SCB_ST_JUNK1 (0x1 << 7) /* 0 */ +#define SCB_ST_RUS (0x7 << 4) /* Rcv unit status */ +#define SCB_ST_RUS_IDLE (0 << 4) /* Idle */ +#define SCB_ST_RUS_SUSP (1 << 4) /* Suspended */ +#define SCB_ST_RUS_NRES (2 << 4) /* No resources */ +#define SCB_ST_RUS_RDY (4 << 4) /* Ready */ + unsigned short scb_command; /* Next command */ +#define SCB_CMD_ACK_CX (0x1 << 15) /* Ack cmd completion */ +#define SCB_CMD_ACK_FR (0x1 << 14) /* Ack frame received */ +#define SCB_CMD_ACK_CNA (0x1 << 13) /* Ack CU not active */ +#define SCB_CMD_ACK_RNR (0x1 << 12) /* Ack RU not ready */ +#define SCB_CMD_JUNKX (0x1 << 11) /* Unused */ +#define SCB_CMD_CUC (0x7 << 8) /* Command Unit command */ +#define SCB_CMD_CUC_NOP (0 << 8) /* Nop */ +#define SCB_CMD_CUC_GO (1 << 8) /* Start cbl_offset */ +#define SCB_CMD_CUC_RES (2 << 8) /* Resume execution */ +#define SCB_CMD_CUC_SUS (3 << 8) /* Suspend " */ +#define SCB_CMD_CUC_ABT (4 << 8) /* Abort " */ +#define SCB_CMD_RESET (0x1 << 7) /* Reset chip (hardware) */ +#define SCB_CMD_RUC (0x7 << 4) /* Receive Unit command */ +#define SCB_CMD_RUC_NOP (0 << 4) /* Nop */ +#define SCB_CMD_RUC_GO (1 << 4) /* Start rfa_offset */ +#define SCB_CMD_RUC_RES (2 << 4) /* Resume reception */ +#define SCB_CMD_RUC_SUS (3 << 4) /* Suspend " */ +#define SCB_CMD_RUC_ABT (4 << 4) /* Abort " */ + unsigned short scb_cbl_offset; /* Offset of first command unit */ + /* Action Command */ + unsigned short scb_rfa_offset; /* Offset of first Receive */ + /* Frame Descriptor in the */ + /* Receive Frame Area */ + unsigned short scb_crcerrs; /* Properly aligned frames */ + /* received with a CRC error */ + unsigned short scb_alnerrs; /* Misaligned frames received */ + /* with a CRC error */ + unsigned short scb_rscerrs; /* Frames lost due to no space */ + unsigned short scb_ovrnerrs; /* Frames lost due to slow bus */ +}; + +#define scboff(p,f) toff(scb_t, p, f) + +/* + * The eight Action Commands. + */ +typedef enum acmd_e acmd_e; +enum acmd_e +{ + acmd_nop = 0, /* Do nothing */ + acmd_ia_setup = 1, /* Load an (ethernet) address into the */ + /* 82586 */ + acmd_configure = 2, /* Update the 82586 operating parameters */ + acmd_mc_setup = 3, /* Load a list of (ethernet) multicast */ + /* addresses into the 82586 */ + acmd_transmit = 4, /* Transmit a frame */ + acmd_tdr = 5, /* Perform a Time Domain Reflectometer */ + /* test on the serial link */ + acmd_dump = 6, /* Copy 82586 registers to memory */ + acmd_diagnose = 7, /* Run an internal self test */ +}; + +/* + * Generic Action Command header. + */ +typedef struct ach_t ach_t; +struct ach_t +{ + unsigned short ac_status; /* Command status: */ +#define AC_SFLD_C (0x1 << 15) /* Command completed */ +#define AC_SFLD_B (0x1 << 14) /* Busy executing */ +#define AC_SFLD_OK (0x1 << 13) /* Completed error free */ +#define AC_SFLD_A (0x1 << 12) /* Command aborted */ +#define AC_SFLD_FAIL (0x1 << 11) /* Selftest failed */ +#define AC_SFLD_S10 (0x1 << 10) /* No carrier sense */ + /* during transmission */ +#define AC_SFLD_S9 (0x1 << 9) /* Tx unsuccessful: */ + /* (stopped) lost CTS */ +#define AC_SFLD_S8 (0x1 << 8) /* Tx unsuccessful: */ + /* (stopped) slow DMA */ +#define AC_SFLD_S7 (0x1 << 7) /* Tx deferred: */ + /* other link traffic */ +#define AC_SFLD_S6 (0x1 << 6) /* Heart Beat: collision */ + /* detect after last tx */ +#define AC_SFLD_S5 (0x1 << 5) /* Tx stopped: */ + /* excessive collisions */ +#define AC_SFLD_MAXCOL (0xF << 0) /* Collision count */ + unsigned short ac_command; /* Command specifier: */ +#define AC_CFLD_EL (0x1 << 15) /* End of command list */ +#define AC_CFLD_S (0x1 << 14) /* Suspend on completion */ +#define AC_CFLD_I (0x1 << 13) /* Interrupt on completion */ +#define AC_CFLD_CMD (0x7 << 0) /* acmd_e */ + unsigned short ac_link; /* Next Action Command */ +}; + +#define acoff(p,f) toff(ach_t, p, f) + +/* + * The Nop Action Command. + */ +typedef struct ac_nop_t ac_nop_t; +struct ac_nop_t +{ + ach_t nop_h; +}; + +/* + * The IA-Setup Action Command. + */ +typedef struct ac_ias_t ac_ias_t; +struct ac_ias_t +{ + ach_t ias_h; + unsigned char ias_addr[ADDR_LEN]; /* The (ethernet) address */ +}; + +/* + * The Configure Action Command. + */ +typedef struct ac_cfg_t ac_cfg_t; +struct ac_cfg_t +{ + ach_t cfg_h; + unsigned char cfg_byte_cnt; /* Size foll data: 4-12 */ +#define AC_CFG_BYTE_CNT(v) (((v) & 0xF) << 0) + unsigned char cfg_fifolim; /* FIFO threshold */ +#define AC_CFG_FIFOLIM(v) (((v) & 0xF) << 0) + unsigned char cfg_byte8; +#define AC_CFG_SAV_BF(v) (((v) & 0x1) << 7) /* Save rxd bad frames */ +#define AC_CFG_SRDY(v) (((v) & 0x1) << 6) /* SRDY/ARDY pin means */ + /* external sync. */ + unsigned char cfg_byte9; +#define AC_CFG_ELPBCK(v) (((v) & 0x1) << 7) /* External loopback */ +#define AC_CFG_ILPBCK(v) (((v) & 0x1) << 6) /* Internal loopback */ +#define AC_CFG_PRELEN(v) (((v) & 0x3) << 4) /* Preamble length */ +#define AC_CFG_PLEN_2 0 /* 2 bytes */ +#define AC_CFG_PLEN_4 1 /* 4 bytes */ +#define AC_CFG_PLEN_8 2 /* 8 bytes */ +#define AC_CFG_PLEN_16 3 /* 16 bytes */ +#define AC_CFG_ALOC(v) (((v) & 0x1) << 3) /* Addr/len data is */ + /* explicit in buffers */ +#define AC_CFG_ADDRLEN(v) (((v) & 0x7) << 0) /* Bytes per address */ + unsigned char cfg_byte10; +#define AC_CFG_BOFMET(v) (((v) & 0x1) << 7) /* Use alternate expo. */ + /* backoff method */ +#define AC_CFG_ACR(v) (((v) & 0x7) << 4) /* Accelerated cont. res. */ +#define AC_CFG_LINPRIO(v) (((v) & 0x7) << 0) /* Linear priority */ + unsigned char cfg_ifs; /* Interframe spacing */ + unsigned char cfg_slotl; /* Slot time (low byte) */ + unsigned char cfg_byte13; +#define AC_CFG_RETRYNUM(v) (((v) & 0xF) << 4) /* Max. collision retry */ +#define AC_CFG_SLTTMHI(v) (((v) & 0x7) << 0) /* Slot time (high bits) */ + unsigned char cfg_byte14; +#define AC_CFG_FLGPAD(v) (((v) & 0x1) << 7) /* Pad with HDLC flags */ +#define AC_CFG_BTSTF(v) (((v) & 0x1) << 6) /* Do HDLC bitstuffing */ +#define AC_CFG_CRC16(v) (((v) & 0x1) << 5) /* 16 bit CCITT CRC */ +#define AC_CFG_NCRC(v) (((v) & 0x1) << 4) /* Insert no CRC */ +#define AC_CFG_TNCRS(v) (((v) & 0x1) << 3) /* Tx even if no carrier */ +#define AC_CFG_MANCH(v) (((v) & 0x1) << 2) /* Manchester coding */ +#define AC_CFG_BCDIS(v) (((v) & 0x1) << 1) /* Disable broadcast */ +#define AC_CFG_PRM(v) (((v) & 0x1) << 0) /* Promiscuous mode */ + unsigned char cfg_byte15; +#define AC_CFG_ICDS(v) (((v) & 0x1) << 7) /* Internal collision */ + /* detect source */ +#define AC_CFG_CDTF(v) (((v) & 0x7) << 4) /* Collision detect */ + /* filter in bit times */ +#define AC_CFG_ICSS(v) (((v) & 0x1) << 3) /* Internal carrier */ + /* sense source */ +#define AC_CFG_CSTF(v) (((v) & 0x7) << 0) /* Carrier sense */ + /* filter in bit times */ + unsigned short cfg_min_frm_len; +#define AC_CFG_MNFRM(v) (((v) & 0xFF) << 0) /* Min. bytes/frame (<= 255) */ +}; + +/* + * The MC-Setup Action Command. + */ +typedef struct ac_mcs_t ac_mcs_t; +struct ac_mcs_t +{ + ach_t mcs_h; + unsigned short mcs_cnt; /* No. of bytes of MC addresses */ +#if 0 + unsigned char mcs_data[ADDR_LEN]; /* The first MC address .. */ + ... +#endif +}; + +#define I82586_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ + +/* + * The Transmit Action Command. + */ +typedef struct ac_tx_t ac_tx_t; +struct ac_tx_t +{ + ach_t tx_h; + unsigned short tx_tbd_offset; /* Address of list of buffers. */ +#if 0 +Linux packets are passed down with the destination MAC address +and length/type field already prepended to the data, +so we do not need to insert it. Consistent with this +we must also set the AC_CFG_ALOC(..) flag during the +ac_cfg_t action command. + unsigned char tx_addr[ADDR_LEN]; /* The frame dest. address */ + unsigned short tx_length; /* The frame length */ +#endif /* 0 */ +}; + +/* + * The Time Domain Reflectometer Action Command. + */ +typedef struct ac_tdr_t ac_tdr_t; +struct ac_tdr_t +{ + ach_t tdr_h; + unsigned short tdr_result; /* Result. */ +#define AC_TDR_LNK_OK (0x1 << 15) /* No link problem */ +#define AC_TDR_XCVR_PRB (0x1 << 14) /* Txcvr cable problem */ +#define AC_TDR_ET_OPN (0x1 << 13) /* Open on the link */ +#define AC_TDR_ET_SRT (0x1 << 12) /* Short on the link */ +#define AC_TDR_TIME (0x7FF << 0) /* Distance to problem */ + /* site in transmit */ + /* clock cycles */ +}; + +/* + * The Dump Action Command. + */ +typedef struct ac_dmp_t ac_dmp_t; +struct ac_dmp_t +{ + ach_t dmp_h; + unsigned short dmp_offset; /* Result. */ +}; + +/* + * Size of the result of the dump command. + */ +#define DUMPBYTES 170 + +/* + * The Diagnose Action Command. + */ +typedef struct ac_dgn_t ac_dgn_t; +struct ac_dgn_t +{ + ach_t dgn_h; +}; + +/* + * Transmit Buffer Descriptor (TBD). + */ +typedef struct tbd_t tbd_t; +struct tbd_t +{ + unsigned short tbd_status; /* Written by the CPU */ +#define TBD_STATUS_EOF (0x1 << 15) /* This TBD is the */ + /* last for this frame */ +#define TBD_STATUS_ACNT (0x3FFF << 0) /* Actual count of data */ + /* bytes in this buffer */ + unsigned short tbd_next_bd_offset; /* Next in list */ + unsigned short tbd_bufl; /* Buffer address (low) */ + unsigned short tbd_bufh; /* " " (high) */ +}; + +/* + * Receive Buffer Descriptor (RBD). + */ +typedef struct rbd_t rbd_t; +struct rbd_t +{ + unsigned short rbd_status; /* Written by the 82586 */ +#define RBD_STATUS_EOF (0x1 << 15) /* This RBD is the */ + /* last for this frame */ +#define RBD_STATUS_F (0x1 << 14) /* ACNT field is valid */ +#define RBD_STATUS_ACNT (0x3FFF << 0) /* Actual no. of data */ + /* bytes in this buffer */ + unsigned short rbd_next_rbd_offset; /* Next rbd in list */ + unsigned short rbd_bufl; /* Data pointer (low) */ + unsigned short rbd_bufh; /* " " (high) */ + unsigned short rbd_el_size; /* EL+Data buf. size */ +#define RBD_EL (0x1 << 15) /* This BD is the */ + /* last in the list */ +#define RBD_SIZE (0x3FFF << 0) /* No. of bytes the */ + /* buffer can hold */ +}; + +#define rbdoff(p,f) toff(rbd_t, p, f) + +/* + * Frame Descriptor (FD). + */ +typedef struct fd_t fd_t; +struct fd_t +{ + unsigned short fd_status; /* Written by the 82586 */ +#define FD_STATUS_C (0x1 << 15) /* Completed storing frame */ +#define FD_STATUS_B (0x1 << 14) /* FD was consumed by RU */ +#define FD_STATUS_OK (0x1 << 13) /* Frame rxd successfully */ +#define FD_STATUS_S11 (0x1 << 11) /* CRC error */ +#define FD_STATUS_S10 (0x1 << 10) /* Alignment error */ +#define FD_STATUS_S9 (0x1 << 9) /* Ran out of resources */ +#define FD_STATUS_S8 (0x1 << 8) /* Rx DMA overrun */ +#define FD_STATUS_S7 (0x1 << 7) /* Frame too short */ +#define FD_STATUS_S6 (0x1 << 6) /* No EOF flag */ + unsigned short fd_command; /* Command */ +#define FD_COMMAND_EL (0x1 << 15) /* Last FD in list */ +#define FD_COMMAND_S (0x1 << 14) /* Suspend RU after rx */ + unsigned short fd_link_offset; /* Next FD */ + unsigned short fd_rbd_offset; /* First RBD (data) */ + /* Prepared by CPU, */ + /* updated by 82586 */ +#if 0 +I think the rest is unused since we +have set AC_CFG_ALOC(..). However, just +in case, we leave the space. +#endif /* 0 */ + unsigned char fd_dest[ADDR_LEN]; /* Destination address */ + /* Written by 82586 */ + unsigned char fd_src[ADDR_LEN]; /* Source address */ + /* Written by 82586 */ + unsigned short fd_length; /* Frame length or type */ + /* Written by 82586 */ +}; + +#define fdoff(p,f) toff(fd_t, p, f) + +/* + * This software may only be used and distributed + * according to the terms of the GNU General Public License. + * + * For more details, see wavelan.c. + */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/ioc3-eth.c linux-2.5/drivers/net/ioc3-eth.c --- linux-2.5.5/drivers/net/ioc3-eth.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/net/ioc3-eth.c Sun Mar 3 17:54:35 2002 @@ -341,14 +341,15 @@ } /* - * Read the NIC (Number-In-a-Can) device. + * Read the NIC (Number-In-a-Can) device used to store the MAC address on + * SN0 / SN00 nodeboards and PCI cards. */ -static void ioc3_get_eaddr(struct ioc3_private *ip) +static void ioc3_get_eaddr_nic(struct ioc3_private *ip) { struct ioc3 *ioc3 = ip->regs; u8 nic[14]; - int i; int tries = 2; /* There may be some problem with the battery? */ + int i; ioc3_w(gpcr_s, (1 << 21)); @@ -371,16 +372,123 @@ for (i = 13; i >= 0; i--) nic[i] = nic_read_byte(ioc3); - printk("Ethernet address is "); - for (i = 2; i < 8; i++) { + for (i = 2; i < 8; i++) ip->dev->dev_addr[i - 2] = nic[i]; - printk("%02x", nic[i]); +} + +#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_SGI_SN2) +/* + * Get the ether-address on SN1 nodes + */ +static void ioc3_get_eaddr_sn(struct ioc3_private *ip) +{ + int ibrick_mac_addr_get(nasid_t, char *); + struct ioc3 *ioc3 = ip->regs; + nasid_t nasid_of_ioc3; + char io7eaddr[20]; + long mac; + int err_val; + + /* + * err_val = ibrick_mac_addr_get(get_nasid(), io7eaddr ); + * + * BAD!! The above call uses get_nasid() and assumes that + * the ioc3 pointed to by struct ioc3 is hooked up to the + * cbrick that we're running on. The proper way to make this call + * is to figure out which nasid the ioc3 is connected to + * and use that to call ibrick_mac_addr_get. Below is + * a hack to do just that. + */ + + /* + * Get the nasid of the ioc3 from the ioc3's base addr. + * FIXME: the 8 at the end assumes we're in memory mode, + * not node mode (for that, we'd change it to a 9). + * Is there a call to extract this info from a physical + * addr somewhere in an sn header file already? If so, + * we should probably use that, or restructure this routine + * to use pci_dev and generic numa nodeid getting stuff. + */ + nasid_of_ioc3 = (((unsigned long)ioc3 >> 33) & ~(-1 << 8)); + err_val = ibrick_mac_addr_get(nasid_of_ioc3, io7eaddr ); + + + if (err_val) { + /* Couldn't read the eeprom; try OSLoadOptions. */ + printk("WARNING: ibrick_mac_addr_get failed: %d\n", err_val); + + /* this is where we hardwire the mac address + * 1st ibrick had 08:00:69:11:34:75 + * 2nd ibrick had 08:00:69:11:35:35 + * + * Eagan Machines: + * mankato1 08:00:69:11:BE:95 + * warroad 08:00:69:11:bd:60 + * duron 08:00:69:11:34:60 + * + * an easy way to get the mac address is to hook + * up an ip35, then from L1 do 'cti serial' + * and then look for MAC line XXX THIS DOESN"T QUITE WORK!! + */ + printk("ioc3_get_eaddr: setting ethernet address to:\n -----> "); + ip->dev->dev_addr[0] = 0x8; + ip->dev->dev_addr[1] = 0x0; + ip->dev->dev_addr[2] = 0x69; + ip->dev->dev_addr[3] = 0x11; + ip->dev->dev_addr[4] = 0x34; + ip->dev->dev_addr[5] = 0x60; + } + else { + long simple_strtol(const char *,char **,unsigned int); + + mac = simple_strtol(io7eaddr, (char **)0, 16); + ip->dev->dev_addr[0] = (mac >> 40) & 0xff; + ip->dev->dev_addr[1] = (mac >> 32) & 0xff; + ip->dev->dev_addr[2] = (mac >> 24) & 0xff; + ip->dev->dev_addr[3] = (mac >> 16) & 0xff; + ip->dev->dev_addr[4] = (mac >> 8) & 0xff; + ip->dev->dev_addr[5] = mac & 0xff; + } +} +#endif + +/* + * Ok, this is hosed by design. It's necessary to know what machine the + * NIC is in in order to know how to read the NIC address. We also have + * to know if it's a PCI card or a NIC in on the node board ... + */ +static void ioc3_get_eaddr(struct ioc3_private *ip) +{ + void (*do_get_eaddr)(struct ioc3_private *ip) = NULL; + int i; + + /* + * We should also use this code for PCI cards, no matter what host + * machine but how to know that we're a PCI card? + */ +#ifdef CONFIG_SGI_IP27 + do_get_eaddr = ioc3_get_eaddr_nic; +#endif +#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_SGI_SN2) + do_get_eaddr = ioc3_get_eaddr_sn; +#endif + + if (!do_get_eaddr) { + printk(KERN_ERR "Don't know how to read MAC address of this " + "IOC3 NIC\n"); + return; + } + + printk("Ethernet address is "); + for (i = 0; i < 6; i++) { + printk("%02x", ip->dev->dev_addr[i]); if (i < 7) printk(":"); } printk(".\n"); } + /* * Caller must hold the ioc3_lock ever for MII readers. This is also * used to protect the transmitter side but it's low contention. @@ -435,10 +543,10 @@ skb = ip->rx_skbs[rx_entry]; rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET); - w0 = rxb->w0; + w0 = be32_to_cpu(rxb->w0); while (w0 & ERXBUF_V) { - err = rxb->err; /* It's valid ... */ + err = be32_to_cpu(rxb->err); /* It's valid ... */ if (err & ERXBUF_GOODPKT) { len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4; skb_trim(skb, len); @@ -479,8 +587,8 @@ ip->stats.rx_frame_errors++; next: ip->rx_skbs[n_entry] = new_skb; - rxr[n_entry] = (0xa5UL << 56) | - ((unsigned long) rxb & TO_PHYS_MASK); + rxr[n_entry] = cpu_to_be32((0xa5UL << 56) | + ((unsigned long) rxb & TO_PHYS_MASK)); rxb->w0 = 0; /* Clear valid flag */ n_entry = (n_entry + 1) & 511; /* Update erpir */ @@ -488,7 +596,7 @@ rx_entry = (rx_entry + 1) & 511; skb = ip->rx_skbs[rx_entry]; rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET); - w0 = rxb->w0; + w0 = be32_to_cpu(rxb->w0); } ioc3->erpir = (n_entry << 3) | ERPIR_ARM; ip->rx_pi = n_entry; @@ -1190,8 +1298,8 @@ /* Because we reserve afterwards. */ skb_put(skb, (1664 + RX_OFFSET)); rxb = (struct ioc3_erxbuf *) skb->data; - rxr[i] = (0xa5UL << 56) - | ((unsigned long) rxb & TO_PHYS_MASK); + rxr[i] = cpu_to_be64((0xa5UL << 56) | + ((unsigned long) rxb & TO_PHYS_MASK)); skb_reserve(skb, RX_OFFSET); } ip->rx_ci = 0; @@ -1516,7 +1624,7 @@ name: "ioc3-eth", id_table: ioc3_pci_tbl, probe: ioc3_probe, - remove: ioc3_remove_one, + remove: __devexit_p(ioc3_remove_one), }; static int __init ioc3_init_module(void) @@ -1555,8 +1663,8 @@ memset(desc->data + len, 0, ETH_ZLEN - len); len = ETH_ZLEN; } - desc->cmd = len | ETXD_INTWHENDONE | ETXD_D0V; - desc->bufcnt = len; + desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_D0V); + desc->bufcnt = cpu_to_be32(len); } else if ((data ^ (data + len)) & 0x4000) { unsigned long b2, s1, s2; @@ -1564,16 +1672,20 @@ s1 = b2 - data; s2 = data + len - b2; - desc->cmd = len | ETXD_INTWHENDONE | ETXD_B1V | ETXD_B2V; - desc->bufcnt = (s1 << ETXD_B1CNT_SHIFT) | - (s2 << ETXD_B2CNT_SHIFT); - desc->p1 = (0xa5UL << 56) | (data & TO_PHYS_MASK); - desc->p2 = (0xa5UL << 56) | (data & TO_PHYS_MASK); + desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | + ETXD_B1V | ETXD_B2V); + desc->bufcnt = cpu_to_be32((s1 << ETXD_B1CNT_SHIFT) + | (s2 << ETXD_B2CNT_SHIFT)); + desc->p1 = cpu_to_be64((0xa5UL << 56) | + (data & TO_PHYS_MASK)); + desc->p2 = cpu_to_be64((0xa5UL << 56) | + (data & TO_PHYS_MASK)); } else { /* Normal sized packet that doesn't cross a page boundary. */ - desc->cmd = len | ETXD_INTWHENDONE | ETXD_B1V; - desc->bufcnt = len << ETXD_B1CNT_SHIFT; - desc->p1 = (0xa5UL << 56) | (data & TO_PHYS_MASK); + desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_B1V); + desc->bufcnt = cpu_to_be32(len << ETXD_B1CNT_SHIFT); + desc->p1 = cpu_to_be64((0xa5UL << 56) | + (data & TO_PHYS_MASK)); } BARRIER(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/irda/Config.help linux-2.5/drivers/net/irda/Config.help --- linux-2.5.5/drivers/net/irda/Config.help Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/net/irda/Config.help Thu Feb 14 00:56:54 2002 @@ -88,6 +88,18 @@ If you want to compile it as a module, say M here and read . The module will be called vlsi_ir.o. +CONFIG_EP7211_IR + Say Y here if you wish to use the infrared port on the EP7211. Note + that you can't use the first UART and the infrared port at the same + time, and that the EP7211 only supports SIR mode, at speeds up to + 115.2 kbps. To use the I/R port, you will need to get the source to + irda-utils and apply the patch at + . + +CONFIG_SA1100_FIR + Say Y here to enable the on-board IRDA device on a Intel(R) + StrongARM(R) SA-1110 based microporocessor. + CONFIG_DONGLE Say Y here if you have an infrared device that connects to your computer's serial port. These devices are called dongles. Then say Y diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/irda/Config.in linux-2.5/drivers/net/irda/Config.in --- linux-2.5.5/drivers/net/irda/Config.in Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/net/irda/Config.in Sun Mar 3 17:54:35 2002 @@ -24,6 +24,7 @@ dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR $CONFIG_IRDA dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA +dep_tristate 'Alchemy Au1000 SIR/FIR' CONFIG_AU1000_FIR $CONFIG_IRDA if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA dep_tristate 'ALi M5123 FIR (Experimental)' CONFIG_ALI_FIR $CONFIG_IRDA diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/irda/Makefile linux-2.5/drivers/net/irda/Makefile --- linux-2.5.5/drivers/net/irda/Makefile Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/net/irda/Makefile Sun Mar 3 17:54:35 2002 @@ -2,7 +2,7 @@ # # Makefile for the Linux IrDA infrared port device drivers. # -# 9 Aug 2000, Christoph Hellwig +# 9 Aug 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # @@ -28,5 +28,6 @@ obj-$(CONFIG_LITELINK_DONGLE) += litelink.o obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin.o obj-$(CONFIG_EP7211_IR) += ep7211_ir.o +obj-$(CONFIG_AU1000_FIR) += au1k_ir.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/irda/ali-ircc.c linux-2.5/drivers/net/irda/ali-ircc.c --- linux-2.5.5/drivers/net/irda/ali-ircc.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/net/irda/ali-ircc.c Mon Mar 4 01:32:06 2002 @@ -258,7 +258,6 @@ struct ali_ircc_cb *self; struct pm_dev *pmdev; int dongle_id; - int ret; int err; IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); @@ -291,15 +290,13 @@ self->io.fifo_size = 16; /* SIR: 16, FIR: 32 Benjamin 2000/11/1 */ /* Reserve the ioports that we need */ - ret = check_region(self->io.fir_base, self->io.fir_ext); - if (ret < 0) { + if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) { WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n", self->io.fir_base); dev_self[i] = NULL; kfree(self); return -ENODEV; } - request_region(self->io.fir_base, self->io.fir_ext, driver_name); /* Initialize QoS for this device */ irda_init_max_qos_capabilies(&self->qos); @@ -1941,6 +1938,7 @@ skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); + self->netdev->last_rx = jiffies; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/irda/au1k_ir.c linux-2.5/drivers/net/irda/au1k_ir.c --- linux-2.5.5/drivers/net/irda/au1k_ir.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/irda/au1k_ir.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,867 @@ +/* + * + * Alchemy Semi Au1000 IrDA driver + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * + */ + +#ifndef __mips__ +#error This driver only works with MIPS architectures! +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "net/irda/au1000_ircc.h" + +static int au1k_irda_net_init(struct net_device *); +static int au1k_irda_start(struct net_device *); +static int au1k_irda_stop(struct net_device *dev); +static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *); +static int au1k_irda_rx(struct net_device *); +static void au1k_irda_interrupt(int, void *, struct pt_regs *); +static void au1k_tx_timeout(struct net_device *); +static struct net_device_stats *au1k_irda_stats(struct net_device *); +static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int); +static int au1k_irda_set_speed(struct net_device *dev, int speed); + +static void *dma_alloc(size_t, dma_addr_t *); +static void dma_free(void *, size_t); + +static int qos_mtt_bits = 0x07; /* 1 ms or more */ +static struct net_device *ir_devs[NUM_IR_IFF]; +static char version[] __devinitdata = + "au1k_ircc:1.0 ppopov@mvista.com\n"; + +#define RUN_AT(x) (jiffies + (x)) + +/* + * IrDA peripheral bug. You have to read the register + * twice to get the right value. + */ +u32 read_ir_reg(u32 addr) +{ + readl(addr); + return readl(addr); +} + + +/* + * Buffer allocation/deallocation routines. The buffer descriptor returned + * has the virtual and dma address of a buffer suitable for + * both, receive and transmit operations. + */ +static db_dest_t *GetFreeDB(struct au1k_private *aup) +{ + db_dest_t *pDB; + pDB = aup->pDBfree; + + if (pDB) { + aup->pDBfree = pDB->pnext; + } + return pDB; +} + +static void ReleaseDB(struct au1k_private *aup, db_dest_t *pDB) +{ + db_dest_t *pDBfree = aup->pDBfree; + if (pDBfree) + pDBfree->pnext = pDB; + aup->pDBfree = pDB; +} + + +/* + DMA memory allocation, derived from pci_alloc_consistent. + However, the Au1000 data cache is coherent (when programmed + so), therefore we return KSEG0 address, not KSEG1. +*/ +static void *dma_alloc(size_t size, dma_addr_t * dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC | GFP_DMA; + + ret = (void *) __get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + ret = KSEG0ADDR(ret); + } + return ret; +} + + +static void dma_free(void *vaddr, size_t size) +{ + vaddr = KSEG0ADDR(vaddr); + free_pages((unsigned long) vaddr, get_order(size)); +} + + +static void +setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base) +{ + int i; + for (i=0; irx_ring[i] = (volatile ring_dest_t *) + (rx_base + sizeof(ring_dest_t)*i); + } + for (i=0; itx_ring[i] = (volatile ring_dest_t *) + (tx_base + sizeof(ring_dest_t)*i); + } +} + + +/* + * Device has already been stopped at this point. + */ +static void au1k_irda_net_uninit(struct net_device *dev) +{ + dev->hard_start_xmit = NULL; + dev->open = NULL; + dev->stop = NULL; + dev->do_ioctl = NULL; + dev->get_stats = NULL; + dev->priv = NULL; +} + + +static int au1k_irda_init(void) +{ + static unsigned version_printed = 0; + struct net_device *dev; + int err; + + if (version_printed++ == 0) printk(version); + + rtnl_lock(); + dev = dev_alloc("irda%d", &err); + if (dev) { + dev->irq = AU1000_IRDA_RX_INT; /* TX has its own interrupt */ + dev->init = au1k_irda_net_init; + dev->uninit = au1k_irda_net_uninit; + err = register_netdevice(dev); + + if (err) + kfree(dev); + else + ir_devs[0] = dev; + printk(KERN_INFO "IrDA: Registered device %s\n", dev->name); + } + rtnl_unlock(); + return err; +} + +static int au1k_irda_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL); + if (io->head != NULL) { + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + } + return io->head ? 0 : -ENOMEM; +} + +static int au1k_irda_net_init(struct net_device *dev) +{ + struct au1k_private *aup = NULL; + int i, retval = 0, err; + db_dest_t *pDB, *pDBfree; + unsigned long temp; + + dev->priv = kmalloc(sizeof(struct au1k_private), GFP_KERNEL); + if (dev->priv == NULL) { + retval = -ENOMEM; + goto out; + } + memset(dev->priv, 0, sizeof(struct au1k_private)); + aup = dev->priv; + + err = au1k_irda_init_iobuf(&aup->rx_buff, 14384); + if (err) + goto out; + + dev->open = au1k_irda_start; + dev->hard_start_xmit = au1k_irda_hard_xmit; + dev->stop = au1k_irda_stop; + dev->get_stats = au1k_irda_stats; + dev->do_ioctl = au1k_irda_ioctl; + dev->tx_timeout = au1k_tx_timeout; + + irda_device_setup(dev); + irda_init_max_qos_capabilies(&aup->qos); + + /* The only value we must override it the baudrate */ + aup->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + IR_115200|IR_576000 |(IR_4000000 << 8); + + aup->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&aup->qos); + + + /* Tx ring follows rx ring + 512 bytes */ + /* we need a 1k aligned buffer */ + aup->rx_ring[0] = (ring_dest_t *) + dma_alloc(2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t)), &temp); + + /* allocate the data buffers */ + aup->db[0].vaddr = + (void *)dma_alloc(MAX_BUF_SIZE * 2*NUM_IR_DESC, &temp); + if (!aup->db[0].vaddr || !aup->rx_ring[0]) { + retval = -ENOMEM; + goto out; + } + + setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512); + + pDBfree = NULL; + pDB = aup->db; + for (i=0; i<(2*NUM_IR_DESC); i++) { + pDB->pnext = pDBfree; + pDBfree = pDB; + pDB->vaddr = + (u32 *)((unsigned)aup->db[0].vaddr + MAX_BUF_SIZE*i); + pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr); + pDB++; + } + aup->pDBfree = pDBfree; + + /* attach a data buffer to each descriptor */ + for (i=0; irx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); + aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff); + aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff); + aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff); + aup->rx_db_inuse[i] = pDB; + } + for (i=0; itx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); + aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff); + aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff); + aup->tx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff); + aup->tx_ring[i]->count_0 = 0; + aup->tx_ring[i]->count_1 = 0; + aup->tx_ring[i]->flags = 0; + aup->tx_db_inuse[i] = pDB; + } + return 0; + +out: + if (aup->db[0].vaddr) + dma_free((void *)aup->db[0].vaddr, + MAX_BUF_SIZE * 2*NUM_IR_DESC); + if (aup->rx_ring[0]) + kfree((void *)aup->rx_ring[0]); + if (aup->rx_buff.head) + kfree(aup->rx_buff.head); + if (dev->priv != NULL) + kfree(dev->priv); + unregister_netdevice(dev); + printk(KERN_ERR "%s: au1k_init_module failed. Returns %d\n", + dev->name, retval); + return retval; +} + + +static int au1k_init(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + int i; + u32 control; + u32 ring_address; + + /* bring the device out of reset */ + control = 0xe; /* coherent, clock enable, one half system clock */ + +#ifndef CONFIG_CPU_LITTLE_ENDIAN + control |= 1; +#endif + aup->tx_head = 0; + aup->tx_tail = 0; + aup->rx_head = 0; + + for (i=0; irx_ring[i]->flags = AU_OWN; + } + + writel(control, IR_INTERFACE_CONFIG); + au_sync_delay(10); + + writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE); /* disable PHY */ + au_sync_delay(1); + + writel(MAX_BUF_SIZE, IR_MAX_PKT_LEN); + + ring_address = (u32)virt_to_phys((void *)aup->rx_ring[0]); + writel(ring_address >> 26, IR_RING_BASE_ADDR_H); + writel((ring_address >> 10) & 0xffff, IR_RING_BASE_ADDR_L); + + writel(RING_SIZE_64<<8 | RING_SIZE_64<<12, IR_RING_SIZE); + + writel(1<<2 | IR_ONE_PIN, IR_CONFIG_2); /* 48MHz */ + writel(0, IR_RING_ADDR_CMPR); + + au1k_irda_set_speed(dev, 9600); + return 0; +} + +static int au1k_irda_start(struct net_device *dev) +{ + int retval; + char hwname[32]; + struct au1k_private *aup = (struct au1k_private *) dev->priv; + + MOD_INC_USE_COUNT; + + if ((retval = au1k_init(dev))) { + printk(KERN_ERR "%s: error in au1k_init\n", dev->name); + MOD_DEC_USE_COUNT; + return retval; + } + + if ((retval = request_irq(AU1000_IRDA_TX_INT, &au1k_irda_interrupt, + 0, dev->name, dev))) { + printk(KERN_ERR "%s: unable to get IRQ %d\n", + dev->name, dev->irq); + MOD_DEC_USE_COUNT; + return retval; + } + if ((retval = request_irq(AU1000_IRDA_RX_INT, &au1k_irda_interrupt, + 0, dev->name, dev))) { + free_irq(AU1000_IRDA_TX_INT, dev); + printk(KERN_ERR "%s: unable to get IRQ %d\n", + dev->name, dev->irq); + MOD_DEC_USE_COUNT; + return retval; + } + + /* Give self a hardware name */ + sprintf(hwname, "Au1000 SIR/FIR"); + aup->irlap = irlap_open(dev, &aup->qos, hwname); + netif_start_queue(dev); + + writel(read_ir_reg(IR_CONFIG_2) | 1<<8, IR_CONFIG_2); /* int enable */ + + aup->timer.expires = RUN_AT((3*HZ)); + aup->timer.data = (unsigned long)dev; + return 0; +} + +static int au1k_irda_stop(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + + /* disable interrupts */ + writel(read_ir_reg(IR_CONFIG_2) & ~(1<<8), IR_CONFIG_2); + writel(0, IR_CONFIG_1); + writel(0, IR_INTERFACE_CONFIG); /* disable clock */ + au_sync(); + + if (aup->irlap) { + irlap_close(aup->irlap); + aup->irlap = NULL; + } + + netif_stop_queue(dev); + del_timer(&aup->timer); + + /* disable the interrupt */ + free_irq(AU1000_IRDA_TX_INT, dev); + free_irq(AU1000_IRDA_RX_INT, dev); + MOD_DEC_USE_COUNT; + return 0; +} + +static void __exit au1k_irda_exit(void) +{ + struct net_device *dev = ir_devs[0]; + struct au1k_private *aup = (struct au1k_private *) dev->priv; + + if (!dev) { + printk(KERN_ERR "au1k_ircc no dev found\n"); + return; + } + if (aup->db[0].vaddr) { + dma_free((void *)aup->db[0].vaddr, + MAX_BUF_SIZE * 2*NUM_IR_DESC); + aup->db[0].vaddr = 0; + } + if (aup->rx_ring[0]) { + dma_free((void *)aup->rx_ring[0], + 2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t))); + aup->rx_ring[0] = 0; + } + rtnl_lock(); + unregister_netdevice(dev); + rtnl_unlock(); + ir_devs[0] = 0; +} + + +static inline void +update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct net_device_stats *ps = &aup->stats; + + ps->tx_packets++; + ps->tx_bytes += pkt_len; + + if (status & IR_TX_ERROR) { + ps->tx_errors++; + ps->tx_aborted_errors++; + } +} + + +static void au1k_tx_ack(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + volatile ring_dest_t *ptxd; + + ptxd = aup->tx_ring[aup->tx_tail]; + while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) { + update_tx_stats(dev, ptxd->flags, + ptxd->count_1<<8 | ptxd->count_0); + ptxd->count_0 = 0; + ptxd->count_1 = 0; + au_sync(); + + aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1); + ptxd = aup->tx_ring[aup->tx_tail]; + + if (aup->tx_full) { + aup->tx_full = 0; + netif_wake_queue(dev); + } + } + + if (aup->tx_tail == aup->tx_head) { + if (aup->newspeed) { + au1k_irda_set_speed(dev, aup->newspeed); + aup->newspeed = 0; + } + else { + writel(read_ir_reg(IR_CONFIG_1) & ~IR_TX_ENABLE, + IR_CONFIG_1); + au_sync(); + writel(read_ir_reg(IR_CONFIG_1) | IR_RX_ENABLE, + IR_CONFIG_1); + writel(0, IR_RING_PROMPT); + au_sync(); + } + } +} + + +/* + * Au1000 transmit routine. + */ +static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + int speed = irda_get_next_speed(skb); + volatile ring_dest_t *ptxd; + u32 len; + + u32 flags; + db_dest_t *pDB; + + if (speed != aup->speed && speed != -1) { + aup->newspeed = speed; + } + + if ((skb->len == 0) && (aup->newspeed)) { + if (aup->tx_tail == aup->tx_head) { + au1k_irda_set_speed(dev, speed); + aup->newspeed = 0; + } + dev_kfree_skb(skb); + return 0; + } + + ptxd = aup->tx_ring[aup->tx_head]; + flags = ptxd->flags; + + if (flags & AU_OWN) { + printk(KERN_INFO "%s: tx_full\n", dev->name); + netif_stop_queue(dev); + aup->tx_full = 1; + return 1; + } + else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) { + printk(KERN_INFO "%s: tx_full\n", dev->name); + netif_stop_queue(dev); + aup->tx_full = 1; + return 1; + } + + pDB = aup->tx_db_inuse[aup->tx_head]; + +#if 0 + if (read_ir_reg(IR_RX_BYTE_CNT) != 0) { + printk("tx warning: rx byte cnt %x\n", + read_ir_reg(IR_RX_BYTE_CNT)); + } +#endif + + if (aup->speed == 4000000) { + /* FIR */ + memcpy((void *)pDB->vaddr, skb->data, skb->len); + ptxd->count_0 = skb->len & 0xff; + ptxd->count_1 = (skb->len >> 8) & 0xff; + } + else { + /* SIR */ + len = async_wrap_skb(skb, (u8 *)pDB->vaddr, MAX_BUF_SIZE); + ptxd->count_0 = len & 0xff; + ptxd->count_1 = (len >> 8) & 0xff; + ptxd->flags |= IR_DIS_CRC; + } + ptxd->flags |= AU_OWN; + au_sync(); + + writel(read_ir_reg(IR_CONFIG_1) | IR_TX_ENABLE, IR_CONFIG_1); + writel(0, IR_RING_PROMPT); + au_sync(); + + dev_kfree_skb(skb); + aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1); + dev->trans_start = jiffies; + return 0; +} + + +static inline void +update_rx_stats(struct net_device *dev, u32 status, u32 count) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct net_device_stats *ps = &aup->stats; + + ps->rx_packets++; + + if (status & IR_RX_ERROR) { + ps->rx_errors++; + if (status & (IR_PHY_ERROR|IR_FIFO_OVER)) + ps->rx_missed_errors++; + if (status & IR_MAX_LEN) + ps->rx_length_errors++; + if (status & IR_CRC_ERROR) + ps->rx_crc_errors++; + } + else + ps->rx_bytes += count; +} + +/* + * Au1000 receive routine. + */ +static int au1k_irda_rx(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + struct sk_buff *skb; + volatile ring_dest_t *prxd; + u32 flags, count; + db_dest_t *pDB; + + prxd = aup->rx_ring[aup->rx_head]; + flags = prxd->flags; + + while (!(flags & AU_OWN)) { + pDB = aup->rx_db_inuse[aup->rx_head]; + count = prxd->count_1<<8 | prxd->count_0; + if (!(flags & IR_RX_ERROR)) { + /* good frame */ + update_rx_stats(dev, flags, count); + skb=alloc_skb(count+1,GFP_ATOMIC); + if (skb == NULL) { + aup->stats.rx_dropped++; + continue; + } + skb_reserve(skb, 1); + if (aup->speed == 4000000) + skb_put(skb, count); + else + skb_put(skb, count-2); + memcpy(skb->data, (void *)pDB->vaddr, count-2); + skb->dev = dev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + prxd->count_0 = 0; + prxd->count_1 = 0; + } + prxd->flags |= AU_OWN; + aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1); + writel(0, IR_RING_PROMPT); + au_sync(); + + /* next descriptor */ + prxd = aup->rx_ring[aup->rx_head]; + flags = prxd->flags; + dev->last_rx = jiffies; + + } + return 0; +} + + +void au1k_irda_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + + if (dev == NULL) { + printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name); + return; + } + + writel(0, IR_INT_CLEAR); /* ack irda interrupts */ + + au1k_irda_rx(dev); + au1k_tx_ack(dev); +} + + +/* + * The Tx ring has been full longer than the watchdog timeout + * value. The transmitter must be hung? + */ +static void au1k_tx_timeout(struct net_device *dev) +{ + u32 speed; + struct au1k_private *aup = (struct au1k_private *) dev->priv; + + printk(KERN_ERR "%s: tx timeout\n", dev->name); + speed = aup->speed; + aup->speed = 0; + au1k_irda_set_speed(dev, speed); + aup->tx_full = 0; + netif_wake_queue(dev); +} + + +/* + * Set the IrDA communications speed. + */ +static int +au1k_irda_set_speed(struct net_device *dev, int speed) +{ + unsigned long flags; + struct au1k_private *aup = (struct au1k_private *) dev->priv; + u32 control; + int ret = 0, timeout = 10, i; + volatile ring_dest_t *ptxd; + + if (speed == aup->speed) + return ret; + + save_flags(flags); + cli(); + + /* disable PHY first */ + writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE); + + /* disable RX/TX */ + writel(read_ir_reg(IR_CONFIG_1) & ~(IR_RX_ENABLE|IR_TX_ENABLE), + IR_CONFIG_1); + au_sync_delay(1); + while (read_ir_reg(IR_ENABLE) & (IR_RX_STATUS | IR_TX_STATUS)) { + mdelay(1); + if (!timeout--) { + printk(KERN_ERR "%s: rx/tx disable timeout\n", + dev->name); + break; + } + } + + /* disable DMA */ + writel(read_ir_reg(IR_CONFIG_1) & ~IR_DMA_ENABLE, IR_CONFIG_1); + au_sync_delay(1); + + /* + * After we disable tx/rx. the index pointers + * go back to zero. + */ + aup->tx_head = aup->tx_tail = aup->rx_head = 0; + for (i=0; itx_ring[i]; + ptxd->flags = 0; + ptxd->count_0 = 0; + ptxd->count_1 = 0; + } + + for (i=0; irx_ring[i]; + ptxd->count_0 = 0; + ptxd->count_1 = 0; + ptxd->flags = AU_OWN; + } + + if (speed == 4000000) + writel(1<<13, CPLD_AUX1); + else + writel(readl(CPLD_AUX1) & ~(1<<13), CPLD_AUX1); + + switch (speed) { + case 9600: + writel(11<<10 | 12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 19200: + writel(5<<10 | 12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 38400: + writel(2<<10 | 12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 57600: + writel(1<<10 | 12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 115200: + writel(12<<5, IR_WRITE_PHY_CONFIG); + writel(IR_SIR_MODE, IR_CONFIG_1); + break; + case 4000000: + writel(0xF, IR_WRITE_PHY_CONFIG); + writel(IR_FIR|IR_DMA_ENABLE|IR_RX_ENABLE, IR_CONFIG_1); + break; + default: + printk(KERN_ERR "%s unsupported speed %x\n", dev->name, speed); + ret = -EINVAL; + break; + } + + aup->speed = speed; + writel(read_ir_reg(IR_ENABLE) | 0x8000, IR_ENABLE); + au_sync(); + + control = read_ir_reg(IR_ENABLE); + writel(0, IR_RING_PROMPT); + au_sync(); + + if (control & (1<<14)) { + printk(KERN_ERR "%s: configuration error\n", dev->name); + } + else { + if (control & (1<<11)) + printk(KERN_INFO "%s Valid SIR config\n", dev->name); + if (control & (1<<12)) + printk(KERN_INFO "%s Valid MIR config\n", dev->name); + if (control & (1<<13)) + printk(KERN_INFO "%s Valid FIR config\n", dev->name); + if (control & (1<<10)) + printk(KERN_INFO "%s TX enabled\n", dev->name); + if (control & (1<<9)) + printk(KERN_INFO "%s RX enabled\n", dev->name); + } + + restore_flags(flags); + return ret; +} + +static int +au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct au1k_private *aup = dev->priv; + int ret = -EOPNOTSUPP; + + switch (cmd) { + case SIOCSBANDWIDTH: + if (capable(CAP_NET_ADMIN)) { + /* + * We are unable to set the speed if the + * device is not running. + */ + if (aup->open) + ret = au1k_irda_set_speed(dev, + rq->ifr_baudrate); + else { + printk(KERN_ERR "%s ioctl: !netif_running\n", + dev->name); + ret = 0; + } + } + break; + + case SIOCSMEDIABUSY: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + irda_device_set_media_busy(dev, TRUE); + ret = 0; + } + break; + + case SIOCGRECEIVING: + rq->ifr_receiving = 0; + break; + default: + break; + } + return ret; +} + + +static struct net_device_stats *au1k_irda_stats(struct net_device *dev) +{ + struct au1k_private *aup = (struct au1k_private *) dev->priv; + return &aup->stats; +} + +#ifdef MODULE +MODULE_AUTHOR("Pete Popov "); +MODULE_DESCRIPTION("Au1000 IrDA Device Driver"); + +module_init(au1k_irda_init); +module_exit(au1k_irda_exit); +#endif /* MODULE */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/irda/irda-usb.c linux-2.5/drivers/net/irda/irda-usb.c --- linux-2.5.5/drivers/net/irda/irda-usb.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/net/irda/irda-usb.c Sun Mar 3 20:15:15 2002 @@ -832,6 +832,7 @@ new->mac.raw = new->data; new->protocol = htons(ETH_P_IRDA); netif_rx(new); + self->netdev->last_rx = jiffies; done: /* Note : at this point, the URB we've just received (urb) @@ -1582,3 +1583,4 @@ MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); MODULE_AUTHOR("Roman Weissgaerber , Dag Brattli and Jean Tourrilhes "); MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/irda/nsc-ircc.c linux-2.5/drivers/net/irda/nsc-ircc.c --- linux-2.5.5/drivers/net/irda/nsc-ircc.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/net/irda/nsc-ircc.c Sun Mar 3 20:15:15 2002 @@ -1570,6 +1570,7 @@ skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); + self->netdev->last_rx = jiffies; } } /* Restore bank register */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/irda/sa1100_ir.c linux-2.5/drivers/net/irda/sa1100_ir.c --- linux-2.5.5/drivers/net/irda/sa1100_ir.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/net/irda/sa1100_ir.c Sun Mar 3 20:15:15 2002 @@ -132,7 +132,7 @@ Ser2HSCR0 = si->hscr0 | HSCR0_HSSP; /* - * Enable the DMA, receiver and recieve interrupt. + * Enable the DMA, receiver and receive interrupt. */ sa1100_dma_flush_all(si->rxdma); sa1100_dma_queue_buffer(si->rxdma, NULL, si->rxbuf_dma, HPSIR_MAX_RXLEN); @@ -597,6 +597,7 @@ sa1100_irda_rx_alloc(si); netif_rx(skb); + dev->last_rx = jiffies; } else { /* * Remap the buffer. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/irda/smc-ircc.c linux-2.5/drivers/net/irda/smc-ircc.c --- linux-2.5.5/drivers/net/irda/smc-ircc.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/net/irda/smc-ircc.c Sun Mar 3 20:15:15 2002 @@ -957,6 +957,7 @@ skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); + self->netdev->last_rx = jiffies; } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/irda/toshoboe.c linux-2.5/drivers/net/irda/toshoboe.c --- linux-2.5.5/drivers/net/irda/toshoboe.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/net/irda/toshoboe.c Sun Mar 3 20:15:15 2002 @@ -433,8 +433,10 @@ self->rxs++; self->rxs %= RX_SLOTS; - if (skb) + if (skb) { netif_rx (skb); + self->netdev->last_rx = jiffies; + } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/irda/vlsi_ir.c linux-2.5/drivers/net/irda/vlsi_ir.c --- linux-2.5.5/drivers/net/irda/vlsi_ir.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/net/irda/vlsi_ir.c Sun Mar 3 20:15:15 2002 @@ -636,7 +636,8 @@ idev->stats.rx_bytes += len; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); + netif_rx(skb); + ndev->last_rx = jiffies; } else { idev->stats.rx_dropped++; @@ -1291,7 +1292,7 @@ name: drivername, id_table: vlsi_irda_table, probe: vlsi_irda_probe, - remove: vlsi_irda_remove, + remove: __devexit_p(vlsi_irda_remove), suspend: vlsi_irda_suspend, resume: vlsi_irda_resume, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/irda/w83977af_ir.c linux-2.5/drivers/net/irda/w83977af_ir.c --- linux-2.5.5/drivers/net/irda/w83977af_ir.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/net/irda/w83977af_ir.c Sun Mar 3 20:15:15 2002 @@ -923,6 +923,7 @@ skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); + self->netdev->last_rx = jiffies; } } /* Restore set register */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/lance.c linux-2.5/drivers/net/lance.c --- linux-2.5.5/drivers/net/lance.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/net/lance.c Thu Feb 14 00:47:46 2002 @@ -383,7 +383,7 @@ return 0; } } - release_resource(r); + release_region(ioaddr, LANCE_TOTAL_SIZE); } } return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/lp486e.c linux-2.5/drivers/net/lp486e.c --- linux-2.5.5/drivers/net/lp486e.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/lp486e.c Sun Mar 3 20:15:15 2002 @@ -676,6 +676,7 @@ skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); + dev->last_rx = jiffies; lp->stats.rx_packets++; } else { #if 0 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/meth.c linux-2.5/drivers/net/meth.c --- linux-2.5.5/drivers/net/meth.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/meth.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,673 @@ +/* + * meth.c -- O2 Builtin 10/100 Ethernet driver, that doesn't work at the moment + * + * Copyright (C) 2001 Ilya Volynets + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef __KERNEL__ +# define __KERNEL__ +#endif + +#ifndef MFE_DEBUG +#define MFE_DEBUG 0 +#endif + +#if MFE_DEBUG>=1 +#define DPRINTK(str,args...) printk (KERN_DEBUG "meth: %s: " str, __FUNCTION__ , ## args) +#define MFE_RX_DEBUG 2 +#else +#define DPRINTK(str,args...) +#define MFE_RX_DEBUG 0 +#endif + + +#include +#include +#include + +#include +#include /* printk() */ +#include +#include /* kmalloc() */ +#include /* error codes */ +#include /* size_t */ +#include /* mark_bh */ +#include + +#include +#include /* struct device, and other headers */ +#include /* eth_type_trans */ +#include /* struct iphdr */ +#include /* struct tcphdr */ +#include +#include /*MII definitions */ + +#include +#include +#include + +#include "meth.h" + +#include +#include + +static const char *version="meth.c: Ilya Volynets (ilya@theIlya.com)"; +static const char *meth_str="SGI O2 Fast Ethernet"; +MODULE_AUTHOR("Ilya Volynets"); +MODULE_DESCRIPTION("SGI O2 Builtin Fast Ethernet driver"); + +/* This is a load-time options */ +/*static int eth = 0; +MODULE_PARM(eth, "i");*/ +/* +#ifdef HAVE_TX_TIMEOUT +static int timeout = 0; +MODULE_PARM(timeout, "i"); +#endif +*/ +int meth_eth; + + +/* + * This structure is private to each device. It is used to pass + * packets in and out, so there is place for a packet + */ + +typedef struct meth_private { + struct net_device_stats stats; + volatile struct meth_regs *regs; + u64 mode; /* in-memory copy of MAC control register */ + int phy_addr; /* address of phy, used by mdio_* functions, initialized in mdio_probe*/ + tx_packet *tx_ring; + dma_addr_t tx_ring_dma; + int free_space; + struct sk_buff *tx_skbs[TX_RING_ENTRIES]; + dma_addr_t tx_skb_dmas[TX_RING_ENTRIES]; + int tx_read,tx_write; + + rx_packet *rx_ring[RX_RING_ENTRIES]; + dma_addr_t rx_ring_dmas[RX_RING_ENTRIES]; + int rx_write; + + spinlock_t meth_lock; +} meth_private; + +extern struct net_device meth_devs[]; +void meth_tx_timeout (struct net_device *dev); +void meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs); + +/* global, initialized in ip32-setup.c */ +char o2meth_eaddr[8]={0,0,0,0,0,0,0,0}; + +static inline void load_eaddr(struct net_device *dev, + volatile struct meth_regs *regs) +{ + int i; + DPRINTK("Loading MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", + (int)o2meth_eaddr[0]&0xFF,(int)o2meth_eaddr[1]&0xFF,(int)o2meth_eaddr[2]&0xFF, + (int)o2meth_eaddr[3]&0xFF,(int)o2meth_eaddr[4]&0xFF,(int)o2meth_eaddr[5]&0xFF); + //memcpy(dev->dev_addr,o2meth_eaddr+2,6); + for (i=0; i<6; i++) + dev->dev_addr[i]=o2meth_eaddr[i]; + regs->mac_addr= //dev->dev_addr[0]|(dev->dev_addr[1]<<8)| + //dev->dev_addr[2]<<16|(dev->dev_addr[3]<<24)| + //dev->dev_addr[4]<<32|(dev->dev_addr[5]<<40); + (*(u64*)o2meth_eaddr)>>16; + DPRINTK("MAC, finally is %0lx\n",regs->mac_addr); +} + +/* + *Waits for BUSY status of mdio bus to clear + */ +#define WAIT_FOR_PHY(___regs, ___rval) \ + while((___rval=___regs->phy_data)&MDIO_BUSY){ \ + udelay(25); \ + } +/*read phy register, return value read */ +static int mdio_read(meth_private *priv,int phyreg) +{ + volatile meth_regs* regs=priv->regs; + volatile u32 rval; + WAIT_FOR_PHY(regs,rval) + regs->phy_registers=(priv->phy_addr<<5)|(phyreg&0x1f); + udelay(25); + regs->phy_trans_go=1; + udelay(25); + WAIT_FOR_PHY(regs,rval) + return rval&MDIO_DATA_MASK; +} + +/*write phy register */ +static void mdio_write(meth_private* priv,int pfyreg,int val) +{ + volatile meth_regs* regs=priv->regs; + int rval; +/// DPRINTK("Trying to write value %i to reguster %i\n",val, pfyreg); +/// spin_lock_irq(&priv->meth_lock); + WAIT_FOR_PHY(regs,rval) + regs->phy_registers=(priv->phy_addr<<5)|(pfyreg&0x1f); + regs->phy_data=val; + udelay(25); + WAIT_FOR_PHY(regs,rval) +/// spin_unlock_irq(&priv->meth_lock); +} + +/* Modify phy register using given mask and value */ +static void mdio_update(meth_private* priv,int phyreg, int val, int mask) +{ + int rval; + DPRINTK("RMW value %i to PHY register %i with mask %i\n",val,phyreg,mask); + rval=mdio_read(priv,phyreg); + rval=(rval&~mask)|(val&mask); + mdio_write(priv,phyreg,rval); +} + +/* handle errata data on MDIO bus */ +//static void mdio_errata(meth_private *priv) +//{ + /* Hmmm... what the hell is phyerrata? does it come from sys init parameters in IRIX */ +//} +static int mdio_probe(meth_private *priv) +{ + int i, p2, p3; + DPRINTK("Detecting PHY kind\n"); + /* check if phy is detected already */ + if(priv->phy_addr>=0&&priv->phy_addr<32) + return 0; + spin_lock_irq(priv->meth_lock); + for (i=0;i<32;++i){ + priv->phy_addr=(char)i; + p2=mdio_read(priv,2); +#ifdef MFE_DEBUG + p3=mdio_read(priv,3); + switch ((p2<<12)|(p3>>4)){ + case PHY_QS6612X: + DPRINTK("PHY is QS6612X\n"); + break; + case PHY_ICS1889: + DPRINTK("PHY is ICS1889\n"); + break; + case PHY_ICS1890: + DPRINTK("PHY is ICS1890\n"); + break; + case PHY_DP83840: + DPRINTK("PHY is DP83840\n"); + break; + } +#endif + if(p2!=0xffff&&p2!=0x0000){ + DPRINTK("PHY code: %x\n",(p2<<12)|(p3>>4)); + break; + } + } + spin_unlock_irq(priv->meth_lock); + if(priv->phy_addr<32) { + return 0; + } + DPRINTK("Oopsie! PHY is not known!\n"); + priv->phy_addr=-1; + return -ENODEV; +} + +static int meth_init_tx_ring(meth_private *priv) +{ + /* Init TX ring */ + DPRINTK("Initializing TX ring\n"); + priv->tx_ring=(tx_packet*)pci_alloc_consistent(NULL,TX_RING_BUFFER_SIZE,&(priv->tx_ring_dma)); + if(!priv->tx_ring) + return -ENOMEM; + memset(priv->tx_ring,0,TX_RING_BUFFER_SIZE); + priv->regs->tx_ring_base=priv->tx_ring_dma; + priv->free_space=TX_RING_ENTRIES; + /* Now init ksb save area */ + memset(priv->tx_skbs,0,sizeof(priv->tx_skbs)); + memset(priv->tx_skb_dmas,0,sizeof(priv->tx_skb_dmas)); + DPRINTK("Done with TX ring init\n"); + return 0; +} + +static int meth_init_rx_ring(meth_private *priv) +{ + int i; + DPRINTK("Initializing RX ring\n"); + for(i=0;irx_ring[i]=get_free_page(GFP_KERNEL))) + return -ENOMEM; + DPRINTK("\t2:\t%i\n",i);*/ + priv->rx_ring[i]=(rx_packet*)pci_alloc_consistent(NULL,METH_RX_BUFF_SIZE,&(priv->rx_ring_dmas[i])); + /* I'll need to re-sync it after each RX */ + DPRINTK("\t2:\t%i\n",i); + priv->regs->rx_fifo=priv->rx_ring_dmas[i]; + } + DPRINTK("Done with RX ring\n"); + return 0; +} +static void meth_free_tx_ring(meth_private *priv) +{ + pci_free_consistent(NULL,TX_RING_BUFFER_SIZE,priv->tx_ring,priv->tx_ring_dma); +} +static void meth_free_rx_ring(meth_private *priv) +{ + int i; + for(i=0;irx_ring[i],priv->rx_ring_dmas[i]); +} + +/*============End Helper Routines=====================*/ + +/* + * Open and close + */ + +int meth_open(struct net_device *dev) +{ + meth_private *priv=dev->priv; + volatile meth_regs *regs=priv->regs; + MOD_INC_USE_COUNT; + /* Start DMA */ + regs->dma_ctrl|= + METH_DMA_TX_EN|/*METH_DMA_TX_INT_EN|*/ + METH_DMA_RX_EN|METH_DMA_RX_INT_EN; + + if(request_irq(dev->irq,meth_interrupt,SA_SHIRQ,meth_str,dev)){ + printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq); + return -EAGAIN; + } + netif_start_queue(dev); + DPRINTK("Opened... DMA control=0x%08lx\n", regs->dma_ctrl); + return 0; +} + +int meth_release(struct net_device *dev) +{ + netif_stop_queue(dev); /* can't transmit any more */ + /* shut down dma */ + ((meth_private*)(dev->priv))->regs->dma_ctrl&= + ~(METH_DMA_TX_EN|METH_DMA_TX_INT_EN| + METH_DMA_RX_EN|METH_DMA_RX_INT_EN); + free_irq(dev->irq, dev); + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Configuration changes (passed on by ifconfig) + */ +int meth_config(struct net_device *dev, struct ifmap *map) +{ + if (dev->flags & IFF_UP) /* can't act on a running interface */ + return -EBUSY; + + /* Don't allow changing the I/O address */ + if (map->base_addr != dev->base_addr) { + printk(KERN_WARNING "meth: Can't change I/O address\n"); + return -EOPNOTSUPP; + } + + /* Allow changing the IRQ */ + if (map->irq != dev->irq) { + printk(KERN_WARNING "meth: Can't change IRQ\n"); + return -EOPNOTSUPP; + } + DPRINTK("Configured\n"); + + /* ignore other fields */ + return 0; +} + +/* + * Receive a packet: retrieve, encapsulate and pass over to upper levels + */ +void meth_rx(struct net_device* dev) +{ + struct sk_buff *skb; + struct meth_private *priv = (struct meth_private *) dev->priv; + rx_packet *rxb; + DPRINTK("RX...\n"); + while((rxb=priv->rx_ring[priv->rx_write])->status.raw&0x8000000000000000){ + int len=rxb->status.parsed.rx_len; + DPRINTK("\tpriv->tx_write=%i\n",priv->rx_write); + if(!(rxb->status.raw&METH_RX_STATUS_ERRORS)){ + DPRINTK("Packet had no errors...\n"); + skb=alloc_skb(len+2,GFP_ATOMIC);/* Should be atomic -- we are in interrupt */ + if(!skb){ + /* Ouch! No memory! Drop packet on the floor */ + DPRINTK("!!!>>>Ouch! Not enough Memory for RX buffer!\n"); + priv->stats.tx_dropped++; + } else { + DPRINTK("And there was no problem getting new skb...\n"); + skb_reserve(skb, 2); /* align IP on 16B boundary */ + memcpy(skb_put(skb, len), rxb->buf, len); + /* Write metadata, and then pass to the receive level */ + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + //skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ + priv->stats.rx_packets++; + DPRINTK("We are about to pass packet up\n"); + netif_rx(skb); + DPRINTK("There we go... Whew...\n"); + } + } + rxb->status.raw=0; + priv->regs->rx_fifo=priv->rx_ring_dmas[priv->rx_write]; + priv->rx_write=(priv->rx_write+1)&(RX_RING_ENTRIES-1); + } +} + +void meth_tx_cleanup(struct net_device* dev, int rptr) +{ + meth_private *priv=dev->priv; + //volatile meth_regs* regs=priv->regs; + tx_packet* status; + struct sk_buff* skb; + DPRINTK("TX...\n"); + spin_lock(&priv->meth_lock); + priv->regs->dma_ctrl&=~(METH_DMA_TX_INT_EN); + while(priv->tx_read!=rptr){ + skb=priv->tx_skbs[priv->tx_read]; + status=&priv->tx_ring[priv->tx_read]; + if(!status->header.res.sent) + break; + if(status->header.raw&METH_TX_STATUS_DONE){ + priv->stats.tx_packets++; + priv->stats.tx_bytes+=skb->len; + } + dev_kfree_skb(skb); + status->header.raw=0; + priv->tx_read=(priv->tx_read+1)&(TX_RING_ENTRIES-1); + } + spin_unlock(priv->meth_lock); + netif_wake_queue(dev); +} + +/* + * The typical interrupt entry point + */ +void meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs) +{ + struct meth_private *priv; + //volatile meth_regs* regs; + union { + u32 reg; /*Whole status register */ + struct { + u32 : 2, + rx_seq : 5, + tx_read : 9, + + rx_read : 8, + int_mask: 8; + } parsed; + } status; + /* + * As usual, check the "device" pointer for shared handlers. + * Then assign "struct device *dev" + */ + struct net_device *dev = (struct net_device *)dev_id; + /* ... and check with hw if it's really ours */ + + if (!dev /*paranoid*/ ) return; + + /* Lock the device */ + priv = (struct meth_private *) dev->priv; + spin_lock(&priv->meth_lock); + + status.reg = priv->regs->int_flags; + priv->regs->int_flags=status.reg&0xff; /* clear interrupts */ + DPRINTK("Interrupt, status %08x...\n",status.reg); + if (status.parsed.int_mask & METH_INT_RX_THRESHOLD) { + /* send it to meth_rx for handling */ + meth_rx(dev); + } + if (status.parsed.int_mask & (METH_INT_TX_EMPTY|METH_INT_TX_PKT)) { + /* a transmission is over: free the skb */ + meth_tx_cleanup(dev,status.parsed.tx_read); + } + /* check for errors too... */ + + DPRINTK("Interrupt handling done...\n"); + /* Unlock the device and we are done */ + spin_unlock(&priv->meth_lock); +} + +/* + * Transmits packets that fit into TX describtor (are <=120B) + */ +static void meth_tx_short_prepare(meth_private* priv, struct sk_buff* skb) +{ + tx_packet *desc=&priv->tx_ring[priv->tx_write]; + int len=(skb->lenlen; + DPRINTK("Short packet... \n"); + /* amybe I should set whole thing to 0 first... */ + memcpy(desc->data.dt+(120-len),skb->data,skb->len); + if(skb->lendata.dt+120-len+skb->len,0,len-skb->len); + desc->header.raw=METH_TX_CMD_INT_EN|(len-1)|((128-len)<<16); + DPRINTK("desc=%016lx\n",desc->header.raw); +} +#define TX_CATBUF1 BIT(25) +static void meth_tx_1page_prepare(meth_private* priv, struct sk_buff* skb) +{ + tx_packet *desc=&priv->tx_ring[priv->tx_write]; + void *data=skb->data; + int len=(u64)data&0x7; + dma_addr_t catbuf; + desc->header.raw=METH_TX_CMD_INT_EN|TX_CATBUF1|(skb->len-1); + if(len){ + memcpy(desc->data.dt+(120-len),data,len); + desc->header.raw|=(128-len)<<16; + } + data+=len; + /* I'll just pretend I know for sure that pci_unmap_single is NOP */ + catbuf=pci_map_single(NULL,data,skb->len-len,PCI_DMA_TODEVICE); + desc->data.cat_buf[0].raw=catbuf|((skb->len-len-1)<<31); +} +#define TX_CATBUF2 BIT(26) +static void meth_tx_2page_prepare(meth_private* priv, struct sk_buff* skb) +{ + tx_packet *desc=&priv->tx_ring[priv->tx_write]; + void *data=skb->data; + int len=(u64)data&0x7; + dma_addr_t catbuf1,catbuf2; + desc->header.raw=METH_TX_CMD_INT_EN|TX_CATBUF1|TX_CATBUF2|(skb->len-1); + if(len){ + memcpy(desc->data.dt+(120-len),data,len); + desc->header.raw|=(128-len)<<16; + } + data+=len; + /* I'll just pretend I know for sure that pci_unmap_single is NOP */ + catbuf1=pci_map_single(NULL,data,skb->len-len,PCI_DMA_TODEVICE); + desc->data.cat_buf[0].raw=catbuf1|((skb->len-len-1)<<31); + len=(u64)data&0xFFF; + data+=len; + catbuf2=pci_map_single(NULL,data,skb->len-((u64)data-(u64)skb->data),PCI_DMA_TODEVICE); + desc->data.cat_buf[1].raw=catbuf2|((skb->len-((u64)data-(u64)skb->data))<<31); +} +/* + * Transmit a packet (called by the kernel) + */ +int meth_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct meth_private *priv = (struct meth_private *) dev->priv; + + spin_lock(&priv->meth_lock); + DPRINTK("Transmitting data...\n"); + if(skb->len<=120) /* Whole thing fits into descriptor */ + meth_tx_short_prepare(priv,skb); + else if(((u64)(skb->data)&0xFFF)len) /* Packet crosses page boundary */ + meth_tx_2page_prepare(priv,skb); + else /* Packet is in one page */ + meth_tx_1page_prepare(priv,skb); + dev->trans_start = jiffies; /* save the timestamp */ + + /* Remember the skb, so we can free it at interrupt time */ + priv->tx_skbs[priv->tx_write] = skb; + priv->regs->tx_info.wptr=priv->tx_write; + priv->tx_write=(priv->tx_write+1)&(TX_RING_ENTRIES-1); + + priv->regs->dma_ctrl|=METH_DMA_TX_INT_EN; + + spin_unlock(&priv->meth_lock); + + return 0; +} + +/* + * Deal with a transmit timeout. + */ + /* +void meth_tx_timeout (struct net_device *dev) +{ + struct meth_private *priv = (struct meth_private *) dev->priv; + + DPRINTK("Transmit timeout at %ld, latency %ld\n", jiffies, + jiffies - dev->trans_start); + priv->status = meth_TX_INTR; + meth_interrupt(0, dev, NULL); + priv->stats.tx_errors++; + netif_wake_queue(dev); + return; +} +*/ +/* + * Ioctl commands + */ +int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + + DPRINTK("ioctl\n"); + return 0; +} + +/* + * Return statistics to the caller + */ +struct net_device_stats *meth_stats(struct net_device *dev) +{ + struct meth_private *priv = (struct meth_private *) dev->priv; + return &priv->stats; +} + +/* + * The init function (sometimes called probe). + * It is invoked by register_netdev() + */ +int meth_init(struct net_device *dev) +{ + meth_private *priv; + volatile meth_regs* regs; + int ret; + /* + * Then, assign other fields in dev, using ether_setup() and some + * hand assignments + */ + ether_setup(dev); /* assign some of the fields */ + + dev->open = meth_open; + dev->stop = meth_release; + dev->set_config = meth_config; + dev->hard_start_xmit = meth_tx; + dev->do_ioctl = meth_ioctl; + dev->get_stats = meth_stats; +/*#ifdef HAVE_TX_TIMEOUT + dev->tx_timeout = meth_tx_timeout; + dev->watchdog_timeo = timeout; +#endif*/ + dev->irq = MACE_ETHERNET_IRQ; + SET_MODULE_OWNER(dev); + + /* + * Then, allocate the priv field. This encloses the statistics + * and a few private fields. + */ + priv = kmalloc(sizeof(struct meth_private), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + dev->priv=priv; + memset(priv, 0, sizeof(struct meth_private)); + spin_lock_init(& (struct meth_private *) (dev->priv)->meth_lock); + /* + * Make the usual checks: check_region(), probe irq, ... -ENODEV + * should be returned if no device found. No resource should be + * grabbed: this is done on open(). + */ + priv->regs=(meth_regs*)SGI_MFE; + dev->base_addr=SGI_MFE; + + regs=(meth_regs*)SGI_MFE; + + /* Reset card */ + regs->mac_ctrl=SGI_MAC_RESET; + regs->mac_ctrl=0; + udelay(25); + DPRINTK("MAC control after reset: %016lx\n",regs->mac_ctrl); + printk("SGI O2 Fast Ethernet rev. %ld\n",regs->mac_ctrl>>29); + + load_eaddr(dev,regs); + priv->phy_addr=-1; /* No phy is known yet... */ + if(mdio_probe(priv)<0){ + DPRINTK("Unable to find PHY\n"); + return -ENODEV; + } + /* Should load some "errata", but later */ + + /* Initial mode -- 100|Half-duplex|Acept normal packets */ + priv->mode=METH_ACCEPT_MCAST|METH_100MBIT|METH_DEFAULT_IPG; + if(dev->flags|IFF_PROMISC) + priv->mode|=METH_PROMISC; + regs->mac_ctrl=priv->mode; + + if((ret=meth_init_tx_ring(priv))<0||(ret=meth_init_rx_ring(priv))<0){ + meth_free_tx_ring(priv); + meth_free_rx_ring(priv); + return ret; + } + /* Now set dma control, but don't enable DMA, yet */ + priv->regs->dma_ctrl=(4<name); + else device_present++; +#ifndef METH_DEBUG + EXPORT_NO_SYMBOLS; +#endif + + return device_present ? 0 : -ENODEV; +} + +void meth_cleanup(void) +{ + kfree(meth_devs->priv); + unregister_netdev(meth_devs); + return; +} + +module_init(meth_init_module); +module_exit(meth_cleanup); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/natsemi.c linux-2.5/drivers/net/natsemi.c --- linux-2.5.5/drivers/net/natsemi.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/net/natsemi.c Fri Mar 1 01:25:56 2002 @@ -101,19 +101,56 @@ version 1.0.13: * ETHTOOL_[GS]EEPROM support (Tim Hockin) - - version 1.0.13: * crc cleanup (Matt Domsch ) + version 1.0.14: + * Cleanup some messages and autoneg in ethtool (Tim Hockin) + * OOM error handling. + * reinit_ring() instead of {drain,init}_ring(). + * Rx status FIFO overrun bug fixed: + The nic sets that bit instead of IntrRxDone, + just call netdev_rx and hang is gone. + TODO: * big endian support with CFG:BEM instead of cpu_to_le32 * support for an external PHY * flow control */ +#if !defined(__OPTIMIZE__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include +#include + #define DRV_NAME "natsemi" -#define DRV_VERSION "1.07+LK1.0.13" -#define DRV_RELDATE "Nov 12, 2001" +#define DRV_VERSION "1.07+LK1.0.14" +#define DRV_RELDATE "Nov 27, 2001" /* Updated to recommendations in pci-skeleton v2.03. */ @@ -132,7 +169,12 @@ /* The user-configurable values. These may be modified when a driver module is loaded.*/ -static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +#define NATSEMI_DEF_MSG (NETIF_MSG_DRV | \ + NETIF_MSG_LINK | \ + NETIF_MSG_WOL | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR) +static int debug = NATSEMI_DEF_MSG; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; @@ -164,7 +206,7 @@ There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 #define TX_QUEUE_LEN 10 /* Limit ring entries actually used, min 4. */ -#define RX_RING_SIZE 64 +#define RX_RING_SIZE 32 /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -183,37 +225,6 @@ #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ -#if !defined(__OPTIMIZE__) -#warning You must compile this file with the correct options! -#warning See the last lines of the source file. -#error You must compile this driver with "-O". -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* Processor type for cache alignment. */ -#include -#include -#include -#include - /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = KERN_INFO DRV_NAME ".c:v1.07 1/9/2001 Written by Donald Becker \n" @@ -232,7 +243,7 @@ MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(max_interrupt_work, "DP8381x maximum events handled per interrupt"); MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); -MODULE_PARM_DESC(debug, "DP8381x debug level (0-5)"); +MODULE_PARM_DESC(debug, "DP8381x debug bitmask"); MODULE_PARM_DESC(rx_copybreak, "DP8381x copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(options, "DP8381x: Bits 0-3: media type, bit 17: full duplex"); MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)"); @@ -421,6 +432,7 @@ enum ChipConfig_bits { CfgPhyDis = 0x200, CfgPhyRst = 0x400, + CfgExtPhy = 0x1000, CfgAnegEnable = 0x2000, CfgAneg100 = 0x4000, CfgAnegFull = 0x8000, @@ -619,6 +631,7 @@ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int oom; /* These values are keep track of the transceiver/media in use. */ unsigned int full_duplex; /* Rx filter. */ @@ -634,6 +647,7 @@ u16 advertising; /* NWay media advertisement */ unsigned int iosize; spinlock_t lock; + u32 msg_enable; }; static int eeprom_read(long ioaddr, int location); @@ -647,9 +661,12 @@ static void netdev_timer(unsigned long data); static void tx_timeout(struct net_device *dev); static int alloc_ring(struct net_device *dev); +static void refill_rx(struct net_device *dev); static void init_ring(struct net_device *dev); +static void drain_tx(struct net_device *dev); static void drain_ring(struct net_device *dev); static void free_ring(struct net_device *dev); +static void reinit_ring(struct net_device *dev); static void init_registers(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); @@ -753,6 +770,7 @@ pci_set_drvdata(pdev, dev); np->iosize = iosize; spin_lock_init(&np->lock); + np->msg_enable = debug; /* Reset the chip to erase previous misconfiguration. */ natsemi_reload_eeprom(dev); @@ -767,7 +785,8 @@ if (option & 0x200) np->full_duplex = 1; if (option & 15) - printk(KERN_INFO "%s: ignoring user supplied media type %d", + printk(KERN_INFO + "%s: ignoring user supplied media type %d", dev->name, option & 15); } if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) @@ -796,14 +815,17 @@ } netif_carrier_off(dev); - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, natsemi_pci_info[chip_idx].name, ioaddr); - for (i = 0; i < ETH_ALEN-1; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + if (netif_msg_drv(np)) { + printk(KERN_INFO "%s: %s at %#08lx, ", + dev->name, natsemi_pci_info[chip_idx].name, ioaddr); + for (i = 0; i < ETH_ALEN-1; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x, IRQ %d.\n", dev->dev_addr[i], irq); + } np->advertising = mdio_read(dev, 1, MII_ADVERTISE); - if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000) { + if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000 + && netif_msg_probe(np)) { u32 chip_config = readl(ioaddr + ChipConfig); printk(KERN_INFO "%s: Transceiver default autonegotiation %s " "10%s %s duplex.\n", @@ -812,12 +834,18 @@ chip_config & CfgAneg100 ? "0" : "", chip_config & CfgAnegFull ? "full" : "half"); } - printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n", - dev->name, mdio_read(dev, 1, MII_BMSR), - np->advertising); + if (netif_msg_probe(np)) + printk(KERN_INFO + "%s: Transceiver status %#04x advertising %#04x.\n", + dev->name, mdio_read(dev, 1, MII_BMSR), + np->advertising); /* save the silicon revision for later querying */ np->srr = readl(ioaddr + SiliconRev); + if (netif_msg_hw(np)) + printk(KERN_INFO "%s: silicon revision %#04x.\n", + dev->name, np->srr); + return 0; } @@ -914,6 +942,7 @@ u32 rfcr; u16 pmatch[3]; u16 sopass[3]; + struct netdev_private *np = dev->priv; /* * Resetting the chip causes some registers to be lost. @@ -947,10 +976,10 @@ break; udelay(5); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: reset did not complete in %d usec.\n", dev->name, i*5); - } else if (debug > 2) { + } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: reset completed in %d usec.\n", dev->name, i*5); } @@ -979,6 +1008,7 @@ static void natsemi_reload_eeprom(struct net_device *dev) { + struct netdev_private *np = dev->priv; int i; writel(EepromReload, dev->base_addr + PCIBusCfg); @@ -987,10 +1017,10 @@ break; udelay(5); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: EEPROM did not reload in %d usec.\n", dev->name, i*5); - } else if (debug > 2) { + } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: EEPROM reloaded in %d usec.\n", dev->name, i*5); } @@ -999,6 +1029,7 @@ static void natsemi_stop_rxtx(struct net_device *dev) { long ioaddr = dev->base_addr; + struct netdev_private *np = dev->priv; int i; writel(RxOff | TxOff, ioaddr + ChipCmd); @@ -1007,10 +1038,10 @@ break; udelay(5); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) { printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n", dev->name, i*5); - } else if (debug > 2) { + } else if (netif_msg_hw(np)) { printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n", dev->name, i*5); } @@ -1028,7 +1059,7 @@ i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); if (i) return i; - if (debug > 1) + if (netif_msg_ifup(np)) printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", dev->name, dev->irq); i = alloc_ring(dev); @@ -1043,8 +1074,8 @@ netif_start_queue(dev); - if (debug > 2) - printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n", + if (netif_msg_ifup(np)) + printk(KERN_DEBUG "%s: Done netdev_open(), status: %#08x.\n", dev->name, (int)readl(ioaddr + ChipCmd)); /* Set the timer to check for link beat. */ @@ -1064,19 +1095,18 @@ int duplex; int chipcfg = readl(ioaddr + ChipConfig); - if(!(chipcfg & CfgLink)) { + if (!(chipcfg & CfgLink)) { if (netif_carrier_ok(dev)) { - if (debug) - printk(KERN_INFO "%s: no link. Disabling watchdog.\n", + if (netif_msg_link(np)) + printk(KERN_NOTICE "%s: link down.\n", dev->name); netif_carrier_off(dev); } return; } if (!netif_carrier_ok(dev)) { - if (debug) - printk(KERN_INFO "%s: link is back. Enabling watchdog.\n", - dev->name); + if (netif_msg_link(np)) + printk(KERN_NOTICE "%s: link up.\n", dev->name); netif_carrier_on(dev); } @@ -1084,10 +1114,11 @@ /* if duplex is set then bit 28 must be set, too */ if (duplex ^ !!(np->rx_config & RxAcceptTx)) { - if (debug) - printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link" - " capability.\n", dev->name, - duplex ? "full" : "half"); + if (netif_msg_link(np)) + printk(KERN_INFO + "%s: Setting %s-duplex based on negotiated " + "link capability.\n", dev->name, + duplex ? "full" : "half"); if (duplex) { np->rx_config |= RxAcceptTx; np->tx_config |= TxCarrierIgn | TxHeartIgn; @@ -1106,17 +1137,12 @@ long ioaddr = dev->base_addr; int i; - /* save the silicon revision for later */ - if (debug > 4) - printk(KERN_DEBUG "%s: found silicon revision %xh.\n", - dev->name, np->srr); - for (i=0;ibase_addr + ChipConfig) & CfgAnegDone) break; udelay(10); } - if (i==NATSEMI_HW_TIMEOUT && debug) { + if (i==NATSEMI_HW_TIMEOUT && netif_msg_link(np)) { printk(KERN_INFO "%s: autonegotiation did not complete in %d usec.\n", dev->name, i*10); @@ -1181,8 +1207,8 @@ * nothing will be written to memory. */ np->SavedClkRun = readl(ioaddr + ClkRun); writel(np->SavedClkRun & ~PMEEnable, ioaddr + ClkRun); - if (np->SavedClkRun & PMEStatus) { - printk(KERN_NOTICE "%s: Wake-up event %8.8x\n", + if (np->SavedClkRun & PMEStatus && netif_msg_wol(np)) { + printk(KERN_NOTICE "%s: Wake-up event %#08x\n", dev->name, readl(ioaddr + WOLCmd)); } @@ -1198,11 +1224,15 @@ } /* - * The frequency on this has been increased because of a nasty little problem. + * netdev_timer: + * Purpose: + * 1) check for link changes. Usually they are handled by the MII interrupt + * 2) check for sudden death of the NIC: * It seems that a reference set for this chip went out with incorrect info, * and there exist boards that aren't quite right. An unexpected voltage drop * can cause the PHY to get itself in a weird state (basically reset..). * NOTE: this only seems to affect revC chips. + * 3) check of death of the RX path due to OOM. */ static void netdev_timer(unsigned long data) { @@ -1212,7 +1242,7 @@ long ioaddr = dev->base_addr; u16 dspcfg; - if (debug > 3) { + if (netif_msg_timer(np)) { /* DO NOT read the IntrStatus register, * a read clears any pending interrupts. */ @@ -1220,17 +1250,23 @@ dev->name); } + spin_lock_irq(&np->lock); + /* check for a nasty random phy-reset - use dspcfg as a flag */ writew(1, ioaddr+PGSEL); dspcfg = readw(ioaddr+DSPCFG); writew(0, ioaddr+PGSEL); if (dspcfg != DSPCFG_VAL) { if (!netif_queue_stopped(dev)) { - printk(KERN_INFO - "%s: possible phy reset: re-initializing\n", - dev->name); + spin_unlock_irq(&np->lock); + if (netif_msg_hw(np)) + printk(KERN_NOTICE + "%s: possible phy reset: re-initializing\n", + dev->name); disable_irq(dev->irq); spin_lock_irq(&np->lock); + natsemi_reset(dev); + reinit_ring(dev); init_registers(dev); spin_unlock_irq(&np->lock); enable_irq(dev->irq); @@ -1240,9 +1276,19 @@ } } else { /* init_registers() calls check_link() for the above case */ - spin_lock_irq(&np->lock); check_link(dev); - spin_unlock_irq(&np->lock); + } + spin_unlock_irq(&np->lock); + if (np->oom) { + disable_irq(dev->irq); + np->oom = 0; + refill_rx(dev); + enable_irq(dev->irq); + if (!np->oom) { + writel(RxOn, dev->base_addr + ChipCmd); + } else { + next_tick = 1; + } } mod_timer(&np->timer, jiffies + next_tick); } @@ -1251,18 +1297,18 @@ { struct netdev_private *np = dev->priv; - if (debug > 2) { + if (netif_msg_pktdata(np)) { int i; printk(KERN_DEBUG " Tx ring at %p:\n", np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) { - printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n", + printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n", i, np->tx_ring[i].next_desc, np->tx_ring[i].cmd_status, np->tx_ring[i].addr); } printk(KERN_DEBUG " Rx ring %p:\n", np->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) { - printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n", + printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n", i, np->rx_ring[i].next_desc, np->rx_ring[i].cmd_status, np->rx_ring[i].addr); @@ -1278,14 +1324,15 @@ disable_irq(dev->irq); spin_lock_irq(&np->lock); if (netif_device_present(dev)) { - printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," - " resetting...\n", - dev->name, readl(ioaddr + IntrStatus)); + if (netif_msg_tx_err(np)) + printk(KERN_WARNING + "%s: Transmit timed out, status %#08x," + " resetting...\n", + dev->name, readl(ioaddr + IntrStatus)); dump_ring(dev); natsemi_reset(dev); - drain_ring(dev); - init_ring(dev); + reinit_ring(dev); init_registers(dev); } else { printk(KERN_WARNING @@ -1312,15 +1359,53 @@ return 0; } +static void refill_rx(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + + /* Refill the Rx ring buffers. */ + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + int entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_dma[entry] = pci_map_single(np->pci_dev, + skb->data, skb->len, PCI_DMA_FROMDEVICE); + np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]); + } + np->rx_ring[entry].cmd_status = + cpu_to_le32(np->rx_buf_sz); + } + if (np->cur_rx - np->dirty_rx == RX_RING_SIZE) { + if (debug > 2) + printk(KERN_INFO "%s: going OOM.\n", dev->name); + np->oom = 1; + } +} + /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void init_ring(struct net_device *dev) { struct netdev_private *np = dev->priv; int i; - np->cur_rx = np->cur_tx = 0; - np->dirty_rx = np->dirty_tx = 0; + /* 1) TX ring */ + np->dirty_tx = np->cur_tx = 0; + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = NULL; + np->tx_ring[i].next_desc = cpu_to_le32(np->ring_dma + +sizeof(struct netdev_desc) + *((i+1)%TX_RING_SIZE+RX_RING_SIZE)); + np->tx_ring[i].cmd_status = 0; + } + /* 2) RX ring */ + np->dirty_rx = 0; + np->cur_rx = RX_RING_SIZE; np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); np->rx_head_desc = &np->rx_ring[0]; @@ -1335,29 +1420,25 @@ np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn); np->rx_skbuff[i] = NULL; } + refill_rx(dev); + dump_ring(dev); +} - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_dma[i] = pci_map_single(np->pci_dev, - skb->data, skb->len, PCI_DMA_FROMDEVICE); - np->rx_ring[i].addr = cpu_to_le32(np->rx_dma[i]); - np->rx_ring[i].cmd_status = cpu_to_le32(np->rx_buf_sz); - } - np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); +static void drain_tx(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + int i; for (i = 0; i < TX_RING_SIZE; i++) { + if (np->tx_skbuff[i]) { + pci_unmap_single(np->pci_dev, + np->rx_dma[i], + np->rx_skbuff[i]->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(np->tx_skbuff[i]); + } np->tx_skbuff[i] = NULL; - np->tx_ring[i].next_desc = cpu_to_le32(np->ring_dma - +sizeof(struct netdev_desc) - *((i+1)%TX_RING_SIZE+RX_RING_SIZE)); - np->tx_ring[i].cmd_status = 0; } - dump_ring(dev); } static void drain_ring(struct net_device *dev) @@ -1378,16 +1459,29 @@ } np->rx_skbuff[i] = NULL; } - for (i = 0; i < TX_RING_SIZE; i++) { - if (np->tx_skbuff[i]) { - pci_unmap_single(np->pci_dev, - np->rx_dma[i], - np->rx_skbuff[i]->len, - PCI_DMA_TODEVICE); - dev_kfree_skb(np->tx_skbuff[i]); - } - np->tx_skbuff[i] = NULL; - } + drain_tx(dev); +} + +static void reinit_ring(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + int i; + + /* drain TX ring */ + drain_tx(dev); + np->dirty_tx = np->cur_tx = 0; + for (i=0;itx_ring[i].cmd_status = 0; + + /* RX Ring */ + np->dirty_rx = 0; + np->cur_rx = RX_RING_SIZE; + np->rx_head_desc = &np->rx_ring[0]; + /* Initialize all Rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) + np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn); + + refill_rx(dev); } static void free_ring(struct net_device *dev) @@ -1438,7 +1532,7 @@ dev->trans_start = jiffies; - if (debug > 4) { + if (netif_msg_tx_queued(np)) { printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); } @@ -1451,14 +1545,11 @@ for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { int entry = np->dirty_tx % TX_RING_SIZE; - if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn)) { - if (debug > 4) - printk(KERN_DEBUG "%s: tx frame #%d is busy.\n", - dev->name, np->dirty_tx); + if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn)) break; - } - if (debug > 4) - printk(KERN_DEBUG "%s: tx frame #%d finished with status %8.8xh.\n", + if (netif_msg_tx_done(np)) + printk(KERN_DEBUG + "%s: tx frame #%d finished, status %#08x.\n", dev->name, np->dirty_tx, le32_to_cpu(np->tx_ring[entry].cmd_status)); if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescPktOK)) { @@ -1495,21 +1586,18 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = dev_instance; - struct netdev_private *np; - long ioaddr; + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; int boguscnt = max_interrupt_work; - ioaddr = dev->base_addr; - np = dev->priv; - if (!netif_device_present(dev)) return; do { /* Reading automatically acknowledges all int sources. */ u32 intr_status = readl(ioaddr + IntrStatus); - if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", + if (netif_msg_intr(np)) + printk(KERN_DEBUG "%s: Interrupt, status %#08x.\n", dev->name, intr_status); if (intr_status == 0) @@ -1530,13 +1618,13 @@ if (--boguscnt < 0) { printk(KERN_WARNING "%s: Too much work at interrupt, " - "status=0x%4.4x.\n", + "status=%#08x.\n", dev->name, intr_status); break; } } while (1); - if (debug > 4) + if (netif_msg_intr(np)) printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name); } @@ -1552,22 +1640,24 @@ /* If the driver owns the next entry it's a new packet. Send it up. */ while (desc_status < 0) { /* e.g. & DescOwn */ - if (debug > 4) - printk(KERN_DEBUG " In netdev_rx() entry %d status was %8.8x.\n", - entry, desc_status); + if (netif_msg_rx_status(np)) + printk(KERN_DEBUG + " netdev_rx() entry %d status was %#08x.\n", + entry, desc_status); if (--boguscnt < 0) break; - if ((desc_status & (DescMore|DescPktOK|DescRxLong)) != DescPktOK) { + if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){ if (desc_status & DescMore) { - printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned " - "multiple buffers, entry %#x status %x.\n", - dev->name, np->cur_rx, desc_status); + if (netif_msg_rx_err(np)) + printk(KERN_WARNING + "%s: Oversized(?) Ethernet " + "frame spanned multiple " + "buffers, entry %#08x " + "status %#08x.\n", dev->name, + np->cur_rx, desc_status); np->stats.rx_length_errors++; } else { - /* There was a error. */ - if (debug > 2) - printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", - desc_status); + /* There was an error. */ np->stats.rx_errors++; if (desc_status & (DescRxAbort|DescRxOver)) np->stats.rx_over_errors++; @@ -1582,8 +1672,8 @@ struct sk_buff *skb; /* Omit CRC size. */ int pkt_len = (desc_status & DescSizeMask) - 4; - /* Check if the packet is long enough to accept without copying - to a minimally-sized skbuff. */ + /* Check if the packet is long enough to accept + * without copying to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; @@ -1617,26 +1707,14 @@ desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); } - /* Refill the Rx ring buffers. */ - for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { - struct sk_buff *skb; - entry = np->dirty_rx % RX_RING_SIZE; - if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[entry] = skb; - if (skb == NULL) - break; /* Better luck next round. */ - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_dma[entry] = pci_map_single(np->pci_dev, - skb->data, skb->len, PCI_DMA_FROMDEVICE); - np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]); - } - np->rx_ring[entry].cmd_status = - cpu_to_le32(np->rx_buf_sz); - } + refill_rx(dev); /* Restart Rx engine if stopped. */ - writel(RxOn, dev->base_addr + ChipCmd); + if (np->oom) + mod_timer(&np->timer, jiffies + 1); + else + writel(RxOn, dev->base_addr + ChipCmd); + } static void netdev_error(struct net_device *dev, int intr_status) @@ -1646,11 +1724,16 @@ spin_lock(&np->lock); if (intr_status & LinkChange) { - printk(KERN_NOTICE - "%s: Link changed: Autonegotiation advertising" - " %4.4x partner %4.4x.\n", dev->name, - (int)mdio_read(dev, 1, MII_ADVERTISE), - (int)mdio_read(dev, 1, MII_LPA)); + u16 adv = mdio_read(dev, 1, MII_ADVERTISE); + u16 lpa = mdio_read(dev, 1, MII_LPA); + if (mdio_read(dev, 1, MII_BMCR) & BMCR_ANENABLE + && netif_msg_link(np)) { + printk(KERN_INFO + "%s: Autonegotiation advertising" + " %#04x partner %#04x.\n", dev->name, + adv, lpa); + } + /* read MII int status to clear the flag */ readw(ioaddr + MIntrStatus); check_link(dev); @@ -1661,18 +1744,19 @@ if (intr_status & IntrTxUnderrun) { if ((np->tx_config & TxDrthMask) < 62) np->tx_config += 2; - if (debug > 2) - printk(KERN_NOTICE "%s: increasing Tx theshold, new tx cfg %8.8xh.\n", - dev->name, np->tx_config); + if (netif_msg_tx_err(np)) + printk(KERN_NOTICE + "%s: increased Tx theshold, txcfg %#08x.\n", + dev->name, np->tx_config); writel(np->tx_config, ioaddr + TxConfig); } - if (intr_status & WOLPkt) { + if (intr_status & WOLPkt && netif_msg_wol(np)) { int wol_status = readl(ioaddr + WOLCmd); - printk(KERN_NOTICE "%s: Link wake-up event %8.8x\n", + printk(KERN_NOTICE "%s: Link wake-up event %#08x\n", dev->name, wol_status); } if (intr_status & RxStatusFIFOOver) { - if (debug >= 2) { + if (netif_msg_rx_err(np) && netif_msg_intr(np)) { printk(KERN_NOTICE "%s: Rx status FIFO overrun\n", dev->name); } @@ -1680,10 +1764,8 @@ } /* Hmmmmm, it's not clear how to recover from PCI faults. */ if (intr_status & IntrPCIErr) { - if (debug) { - printk(KERN_NOTICE "%s: PCI error %08x\n", dev->name, - intr_status & IntrPCIErr); - } + printk(KERN_NOTICE "%s: PCI error %#08x\n", dev->name, + intr_status & IntrPCIErr); np->stats.tx_fifo_errors++; np->stats.rx_fifo_errors++; } @@ -1761,7 +1843,8 @@ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ /* Unconditionally log net taps. */ - printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", + dev->name); rx_mode = RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys; } else if ((dev->mc_count > multicast_filter_limit) @@ -1896,7 +1979,7 @@ /* get message-level */ case ETHTOOL_GMSGLVL: { struct ethtool_value edata = {ETHTOOL_GMSGLVL}; - edata.data = debug; + edata.data = np->msg_enable; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; @@ -1906,7 +1989,7 @@ struct ethtool_value edata; if (copy_from_user(&edata, useraddr, sizeof(edata))) return -EFAULT; - debug = edata.data; + np->msg_enable = edata.data; return 0; } /* restart autonegotiation */ @@ -1925,6 +2008,8 @@ /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; + /* LSTATUS is latched low until a read - so read twice */ + mdio_read(dev, 1, MII_BMSR); edata.data = (mdio_read(dev, 1, MII_BMSR)&BMSR_LSTATUS) ? 1:0; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; @@ -2094,18 +2179,22 @@ ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | - SUPPORTED_Autoneg | SUPPORTED_TP); + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); - /* only supports twisted-pair */ - ecmd->port = PORT_TP; + /* only supports twisted-pair or MII */ + tmp = readl(dev->base_addr + ChipConfig); + if (tmp & CfgExtPhy) + ecmd->port = PORT_MII; + else + ecmd->port = PORT_TP; /* only supports internal transceiver */ ecmd->transceiver = XCVR_INTERNAL; - /* this isn't fully supported at higher layers */ + /* not sure what this is for */ ecmd->phy_address = readw(dev->base_addr + PhyCtrl) & PhyAddrMask; - ecmd->advertising = ADVERTISED_TP; + ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; tmp = mdio_read(dev, 1, MII_ADVERTISE); if (tmp & ADVERTISE_10HALF) ecmd->advertising |= ADVERTISED_10baseT_Half; @@ -2116,20 +2205,21 @@ if (tmp & ADVERTISE_100FULL) ecmd->advertising |= ADVERTISED_100baseT_Full; - tmp = readl(dev->base_addr + ChipConfig); - if (tmp & CfgAnegEnable) { + tmp = mdio_read(dev, 1, MII_BMCR); + if (tmp & BMCR_ANENABLE) { ecmd->advertising |= ADVERTISED_Autoneg; ecmd->autoneg = AUTONEG_ENABLE; } else { ecmd->autoneg = AUTONEG_DISABLE; } + tmp = readl(dev->base_addr + ChipConfig); if (tmp & CfgSpeed100) { ecmd->speed = SPEED_100; } else { ecmd->speed = SPEED_10; } - + if (tmp & CfgFullDuplex) { ecmd->duplex = DUPLEX_FULL; } else { @@ -2150,7 +2240,7 @@ return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; - if (ecmd->port != PORT_TP) + if (ecmd->port != PORT_TP && ecmd->port != PORT_MII) return -EINVAL; if (ecmd->transceiver != XCVR_INTERNAL) return -EINVAL; @@ -2160,39 +2250,22 @@ /* WHEW! now lets bang some bits */ + tmp = mdio_read(dev, 1, MII_BMCR); if (ecmd->autoneg == AUTONEG_ENABLE) { - /* advertise only what has been requested */ - tmp = readl(dev->base_addr + ChipConfig); - tmp &= ~(CfgAneg100 | CfgAnegFull); - tmp |= CfgAnegEnable; - if (ecmd->advertising & ADVERTISED_100baseT_Half - || ecmd->advertising & ADVERTISED_100baseT_Full) { - tmp |= CfgAneg100; - } - if (ecmd->advertising & ADVERTISED_10baseT_Full - || ecmd->advertising & ADVERTISED_100baseT_Full) { - tmp |= CfgAnegFull; - } - writel(tmp, dev->base_addr + ChipConfig); - /* turn on autonegotiation, and force a renegotiate */ - tmp = mdio_read(dev, 1, MII_BMCR); - tmp |= (BMCR_ANENABLE | BMCR_ANRESTART); - mdio_write(dev, 1, MII_BMCR, tmp); + /* turn on autonegotiation */ + tmp |= BMCR_ANENABLE; np->advertising = mdio_read(dev, 1, MII_ADVERTISE); } else { /* turn off auto negotiation, set speed and duplexity */ - tmp = mdio_read(dev, 1, MII_BMCR); tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); - if (ecmd->speed == SPEED_100) { + if (ecmd->speed == SPEED_100) tmp |= BMCR_SPEED100; - } - if (ecmd->duplex == DUPLEX_FULL) { + if (ecmd->duplex == DUPLEX_FULL) tmp |= BMCR_FULLDPLX; - } else { + else np->full_duplex = 0; - } - mdio_write(dev, 1, MII_BMCR, tmp); } + mdio_write(dev, 1, MII_BMCR, tmp); return 0; } @@ -2227,7 +2300,7 @@ /* the interrupt status is clear-on-read - see if we missed any */ if (rbuf[4] & rbuf[5]) { printk(KERN_WARNING - "%s: shoot, we dropped an interrupt (0x%x)\n", + "%s: shoot, we dropped an interrupt (%#08x)\n", dev->name, rbuf[4] & rbuf[5]); } @@ -2267,18 +2340,15 @@ case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ data->phy_id = 1; /* Fall Through */ case SIOCGMIIREG: /* Read MII PHY register. */ - case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ - case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, @@ -2294,7 +2364,7 @@ long ioaddr = dev->base_addr; struct netdev_private *np = dev->priv; - if (debug > 1) + if (netif_msg_wol(np)) printk(KERN_INFO "%s: remaining active for wake-on-lan\n", dev->name); @@ -2317,7 +2387,8 @@ /* enable the WOL interrupt. * Could be used to send a netlink message. */ - writel(readl(ioaddr + IntrMask) | WOLPkt, ioaddr + IntrMask); + writel(WOLPkt, ioaddr + IntrMask); + writel(1, ioaddr + IntrEnable); } } @@ -2327,22 +2398,28 @@ struct netdev_private *np = dev->priv; netif_stop_queue(dev); - netif_carrier_off(dev); - if (debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", - dev->name, (int)readl(ioaddr + ChipCmd)); - printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", - dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); - } + if (netif_msg_ifdown(np)) + printk(KERN_DEBUG + "%s: Shutting down ethercard, status was %#04x.\n", + dev->name, (int)readl(ioaddr + ChipCmd)); + if (netif_msg_pktdata(np)) + printk(KERN_DEBUG + "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, np->cur_tx, np->dirty_tx, + np->cur_rx, np->dirty_rx); + /* Disable interrupts, and flush posted writes */ + writel(0, ioaddr + IntrEnable); + readl(ioaddr + IntrEnable); + free_irq(dev->irq, dev); del_timer_sync(&np->timer); - - disable_irq(dev->irq); + /* Interrupt disabled, interrupt handler released, + * queue stopped, timer deleted. All async codepaths + * that access the driver are disabled. + */ spin_lock_irq(&np->lock); - /* Disable and clear interrupts */ - writel(0, ioaddr + IntrEnable); readl(ioaddr + IntrMask); readw(ioaddr + MIntrStatus); @@ -2355,17 +2432,6 @@ __get_stats(dev); spin_unlock_irq(&np->lock); - /* race: shared irq and as most nics the DP83815 - * reports _all_ interrupt conditions in IntrStatus, even - * disabled ones. - * packet received after disable_irq, but before stop_rxtx - * --> race. intr_handler would restart the rx process. - * netif_device_{de,a}tach around {enable,free}_irq. - */ - netif_device_detach(dev); - enable_irq(dev->irq); - free_irq(dev->irq, dev); - netif_device_attach(dev); /* clear the carrier last - an interrupt could reenable it otherwise */ netif_carrier_off(dev); @@ -2373,7 +2439,7 @@ drain_ring(dev); free_ring(dev); - { + { u32 wol = readl(ioaddr + WOLCmd) & WakeOptsSummary; if (wol) { /* restart the NIC in WOL mode. @@ -2504,7 +2570,7 @@ name: DRV_NAME, id_table: natsemi_pci_tbl, probe: natsemi_probe1, - remove: natsemi_remove1, + remove: __devexit_p(natsemi_remove1), #ifdef CONFIG_PM suspend: natsemi_suspend, resume: natsemi_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/ne2k-pci.c linux-2.5/drivers/net/ne2k-pci.c --- linux-2.5.5/drivers/net/ne2k-pci.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/net/ne2k-pci.c Fri Jan 18 22:19:46 2002 @@ -642,7 +642,7 @@ static struct pci_driver ne2k_driver = { name: DRV_NAME, probe: ne2k_pci_init_one, - remove: ne2k_pci_remove_one, + remove: __devexit_p(ne2k_pci_remove_one), id_table: ne2k_pci_tbl, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/ns83820.c linux-2.5/drivers/net/ns83820.c --- linux-2.5.5/drivers/net/ns83820.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/net/ns83820.c Sun Mar 3 20:15:15 2002 @@ -848,6 +848,8 @@ skb->protocol = eth_type_trans(skb, &dev->net_dev); if (NET_RX_DROP == netif_rx(skb)) dev->stats.rx_dropped ++; + else + dev->last_rx = jiffies; #if 0 //ndef __i386__ done:; #endif @@ -1637,7 +1639,7 @@ name: "ns83820", id_table: ns83820_pci_tbl, probe: ns83820_init_one, - remove: ns83820_remove_one, + remove: __devexit_p(ns83820_remove_one), #if 0 /* FIXME: implement */ suspend: , resume: , diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pci-skeleton.c linux-2.5/drivers/net/pci-skeleton.c --- linux-2.5.5/drivers/net/pci-skeleton.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/net/pci-skeleton.c Fri Jan 18 22:19:46 2002 @@ -1956,7 +1956,7 @@ name: MODNAME, id_table: netdrv_pci_tbl, probe: netdrv_init_one, - remove: netdrv_remove_one, + remove: __devexit_p(netdrv_remove_one), #ifdef CONFIG_PM suspend: netdrv_suspend, resume: netdrv_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pcmcia/Config.help linux-2.5/drivers/net/pcmcia/Config.help --- linux-2.5.5/drivers/net/pcmcia/Config.help Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/net/pcmcia/Config.help Tue Feb 26 21:24:49 2002 @@ -133,7 +133,7 @@ This driver 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 xircom_tulip_cb.o. If you want to compile + The module will be called xircom_cb.o. If you want to compile it as a module, say M here and read . If unsure, say N. @@ -145,7 +145,7 @@ This driver 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 xircom_tulip_cb.o. If you want to compile + The module will be called xircom_cb.o. If you want to compile it as a module, say M here and read . If unsure, say N. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pcmcia/Config.in linux-2.5/drivers/net/pcmcia/Config.in --- linux-2.5.5/drivers/net/pcmcia/Config.in Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/net/pcmcia/Config.in Tue Jan 22 17:27:18 2002 @@ -11,10 +11,10 @@ dep_tristate ' 3Com 3c574 PCMCIA support' CONFIG_PCMCIA_3C574 $CONFIG_PCMCIA dep_tristate ' Fujitsu FMV-J18x PCMCIA support' CONFIG_PCMCIA_FMVJ18X $CONFIG_PCMCIA dep_tristate ' NE2000 compatible PCMCIA support' CONFIG_PCMCIA_PCNET $CONFIG_PCMCIA + dep_tristate ' Asix AX88190 PCMCIA support' CONFIG_PCMCIA_AXNET $CONFIG_PCMCIA dep_tristate ' New Media PCMCIA support' CONFIG_PCMCIA_NMCLAN $CONFIG_PCMCIA dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA - dep_tristate ' broken NS8390-cards support' CONFIG_PCMCIA_AXNET $CONFIG_PCMCIA dep_tristate ' COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA if [ "$CONFIG_IBMTR" != "y" ]; then dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pcmcia/axnet_cs.c linux-2.5/drivers/net/pcmcia/axnet_cs.c --- linux-2.5.5/drivers/net/pcmcia/axnet_cs.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/net/pcmcia/axnet_cs.c Thu Dec 13 16:32:36 2001 @@ -11,7 +11,7 @@ Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net - axnet_cs.c 1.11 2001/06/12 12:42:40 + axnet_cs.c 1.24 2001/11/18 02:46:51 The network driver code is based on Donald Becker's NE2000 code: @@ -20,7 +20,7 @@ Director, National Security Agency. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov + Donald Becker may be reached at becker@scyld.com ======================================================================*/ @@ -33,12 +33,13 @@ #include #include #include +#include #include #include #include #include -#include "ax8390.h" +#include "../8390.h" #include #include @@ -51,7 +52,6 @@ #define AXNET_CMD 0x00 #define AXNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */ #define AXNET_RESET 0x1f /* Issue a read to reset, a write to clear. */ -#define AXNET_MISC 0x18 /* For IBM CCAE and Socket EA cards */ #define AXNET_MII_EEP 0x14 /* Offset of MII access port */ #define AXNET_START_PG 0x40 /* First page of TX buffer */ @@ -59,26 +59,13 @@ #define AXNET_RDC_TIMEOUT 0x02 /* Max wait in jiffies for Tx RDC */ -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"axnet_cs.c 1.11 2001/06/12 12:42:40 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - -#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb); -#define skb_tx_check(dev, skb) -#define add_rx_bytes(stats, n) (stats)->rx_bytes += n; -#define add_tx_bytes(stats, n) (stats)->tx_bytes += n; -#define netif_mark_up(dev) do { } while (0) -#define netif_mark_down(dev) do { } while (0) - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds "); +MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver"); +MODULE_LICENSE("GPL"); #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") @@ -87,9 +74,14 @@ static int irq_list[4] = { -1 }; MODULE_PARM(irq_list, "1-4i"); -/* Ugh! Let the user hardwire the hardware address for queer cards */ -static int hw_addr[6] = { 0, /* ... */ }; -MODULE_PARM(hw_addr, "6i"); +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"axnet_cs.c 1.24 2001/11/18 02:46:51 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ @@ -120,6 +112,11 @@ static dev_info_t dev_info = "axnet_cs"; static dev_link_t *dev_list; +static int axdev_init(struct net_device *dev); +static void AX88190_init(struct net_device *dev, int startp); +static int ax_open(struct net_device *dev); +static void ax_interrupt(int irq, void *dev_id, struct pt_regs *regs); + /*====================================================================*/ typedef struct axnet_dev_t { @@ -210,7 +207,7 @@ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - ethdev_init(dev); + axdev_init(dev); dev->init = &axnet_init; dev->open = &axnet_open; dev->stop = &axnet_close; @@ -302,7 +299,7 @@ {0x00, EN0_RCNTHI}, {0x00, EN0_IMR}, /* Mask completion irq. */ {0xFF, EN0_ISR}, - {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ + {E8390_RXOFF|0x40, EN0_RXCR}, /* 0x60 Set to monitor */ {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ {0x10, EN0_RCNTLO}, {0x00, EN0_RCNTHI}, @@ -331,30 +328,6 @@ /*====================================================================== - This should be totally unnecessary... but when we can't figure - out the hardware address any other way, we'll let the user hard - wire it when the module is initialized. - -======================================================================*/ - -static int get_hwired(dev_link_t *link) -{ - struct net_device *dev = link->priv; - int i; - - for (i = 0; i < 6; i++) - if (hw_addr[i] != 0) break; - if (i == 6) - return 0; - - for (i = 0; i < 6; i++) - dev->dev_addr[i] = hw_addr[i]; - - return 1; -} /* get_hwired */ - -/*====================================================================== - axnet_config() is scheduled to run after a CARD_INSERTION event is received, to configure the PCMCIA socket, and to make the ethernet device available to the system. @@ -419,7 +392,8 @@ CS_CHECK(GetTupleData, handle, &tuple); CS_CHECK(ParseTuple, handle, &tuple, &parse); link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; + /* don't trust the CIS on this; Linksys got it wrong */ + link->conf.Present = 0x63; /* Configure card */ link->state |= DEV_CONFIG; @@ -440,7 +414,7 @@ if ((cfg->index == 0) || (cfg->io.nwin == 0)) goto next_entry; - link->conf.ConfigIndex = cfg->index; + link->conf.ConfigIndex = 0x05; /* For multifunction cards, by convention, we configure the network function with window 0, and serial with window 1 */ if (io->nwin > 1) { @@ -480,9 +454,9 @@ goto failed; } - if (!get_prom(link) && !get_hwired(link)) { - printk(KERN_NOTICE "axnet_cs: unable to read hardware net" - " address for io base %#3lx\n", dev->base_addr); + if (!get_prom(link)) { + printk(KERN_NOTICE "axnet_cs: this is not an AX88190 card!\n"); + printk(KERN_NOTICE "axnet_cs: use pcnet_cs instead.\n"); unregister_netdev(dev); goto failed; } @@ -542,7 +516,7 @@ if (link->open) { DEBUG(1, "axnet_cs: release postponed, '%s' still open\n", - info->node.dev_name); + ((axnet_dev_t *)(link->priv))->node.dev_name); link->state |= DEV_STALE_CONFIG; return; } @@ -602,7 +576,7 @@ CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { axnet_reset_8390(&info->dev); - NS8390_init(&info->dev, 1); + AX88190_init(&info->dev, 1); netif_device_attach(&info->dev); } } @@ -692,7 +666,7 @@ info->watchdog.expires = jiffies + HZ; add_timer(&info->watchdog); - return ei_open(dev); + return ax_open(dev); } /* axnet_open */ /*====================================================================*/ @@ -708,7 +682,6 @@ link->open--; netif_stop_queue(dev); - netif_mark_down(dev); del_timer(&info->watchdog); if (link->state & DEV_STALE_CONFIG) mod_timer(&link->release, jiffies + HZ/20); @@ -755,7 +728,7 @@ { axnet_dev_t *info = dev_id; info->stale = 0; - ei_interrupt(irq, dev_id, regs); + ax_interrupt(irq, dev_id, regs); } static void ei_watchdog(u_long arg) @@ -807,7 +780,7 @@ else printk(KERN_INFO "%s: link partner did not autonegotiate\n", dev->name); - NS8390_init(dev, 1); + AX88190_init(dev, 1); } info->link_status = link; } @@ -944,10 +917,11 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + This is the chip-specific code for many 8390-based ethernet adaptors. This is not a complete driver, it must be combined with board-specific code such as ne.c, wd.c, 3c503.c, etc. @@ -957,7 +931,6 @@ a simple innocent change. Please contact me or Donald if you think you have found something that needs changing. -- PG - Changelog: Paul Gortmaker : remove set_bit lock, other cleanups. @@ -981,8 +954,8 @@ */ -static const char *version = - "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; +static const char *version_8390 = + "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@scyld.com)\n"; #include #include @@ -1062,25 +1035,23 @@ * them. */ - - /** - * ei_open - Open/initialize the board. + * ax_open - Open/initialize the board. * @dev: network device to initialize * * This routine goes all-out, setting everything * up anew at each open, even though many of these registers should only * need to be set once at boot. */ -static int ei_open(struct net_device *dev) +static int ax_open(struct net_device *dev) { unsigned long flags; struct ei_device *ei_local = (struct ei_device *) dev->priv; - /* This can't happen unless somebody forgot to call ethdev_init(). */ + /* This can't happen unless somebody forgot to call axdev_init(). */ if (ei_local == NULL) { - printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name); + printk(KERN_EMERG "%s: ax_open passed a non-existent device!\n", dev->name); return -ENXIO; } @@ -1099,10 +1070,9 @@ */ spin_lock_irqsave(&ei_local->page_lock, flags); - NS8390_init(dev, 1); + AX88190_init(dev, 1); /* Set the flag before we drop the lock, That way the IRQ arrives after its set and we get no silly warnings */ - netif_mark_up(dev); netif_start_queue(dev); spin_unlock_irqrestore(&ei_local->page_lock, flags); ei_local->irqlock = 0; @@ -1110,27 +1080,6 @@ } /** - * ei_close - shut down network device - * @dev: network device to close - * - * Opposite of ei_open(). Only used when "ifconfig down" is done. - */ -static int ei_close(struct net_device *dev) -{ - unsigned long flags; - - /* - * Hold the page lock during close - */ - - spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags); - NS8390_init(dev, 0); - spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags); - netif_stop_queue(dev); - return 0; -} - -/** * ei_tx_timeout - handle transmit time out condition * @dev: network device which has apparently fallen asleep * @@ -1169,7 +1118,7 @@ /* Try to restart the card. Perhaps the user has fixed something. */ ei_reset_8390(dev); - NS8390_init(dev, 1); + AX88190_init(dev, 1); spin_unlock(&ei_local->page_lock); enable_irq(dev->irq); @@ -1192,7 +1141,6 @@ unsigned long flags; netif_stop_queue(dev); - skb_tx_check(dev, skb); length = skb->len; @@ -1205,7 +1153,6 @@ outb_p(0x00, e8390_base + EN0_IMR); spin_unlock_irqrestore(&ei_local->page_lock, flags); - /* * Slow phase with lock held. */ @@ -1218,8 +1165,6 @@ send_length = ETH_ZLEN < length ? length : ETH_ZLEN; -#ifdef EI_PINGPONG - /* * We have two Tx slots available for use. Find the first free * slot, and then perform some sanity checks. With two Tx bufs, @@ -1288,22 +1233,6 @@ else netif_start_queue(dev); -#else /* EI_PINGPONG */ - - /* - * Only one Tx buffer in use. You need two Tx bufs to come close to - * back-to-back transmits. Expect a 20 -> 25% performance hit on - * reasonable hardware if you only use one Tx buffer. - */ - - ei_block_output(dev, length, skb->data, ei_local->tx_start_page); - ei_local->txing = 1; - NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); - dev->trans_start = jiffies; - netif_stop_queue(dev); - -#endif /* EI_PINGPONG */ - /* Turn 8390 interrupts back on. */ ei_local->irqlock = 0; outb_p(ENISR_ALL, e8390_base + EN0_IMR); @@ -1311,14 +1240,14 @@ spin_unlock(&ei_local->page_lock); enable_irq(dev->irq); - DEV_KFREE_SKB (skb); - add_tx_bytes(&ei_local->stat, send_length); + dev_kfree_skb (skb); + ei_local->stat.tx_bytes += send_length; return 0; } /** - * ei_interrupt - handle the interrupts from an 8390 + * ax_interrupt - handle the interrupts from an 8390 * @irq: interrupt number * @dev_id: a pointer to the net_device * @regs: unused @@ -1330,7 +1259,7 @@ * needed. */ -static void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static void ax_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; long e8390_base; @@ -1497,8 +1426,6 @@ struct ei_device *ei_local = (struct ei_device *) dev->priv; int status = inb(e8390_base + EN0_TSR); -#ifdef EI_PINGPONG - /* * There are two Tx buffers, see which one finished, and trigger * the send of another one if it exists. @@ -1541,13 +1468,6 @@ // else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n", // dev->name, ei_local->lasttx); -#else /* EI_PINGPONG */ - /* - * Single Tx buffer: mark it free so another packet can be loaded. - */ - ei_local->txing = 0; -#endif - /* Minimize Tx latency: update the statistics after we restart TXing. */ if (status & ENTSR_COL) ei_local->stat.collisions++; @@ -1655,7 +1575,7 @@ netif_rx(skb); dev->last_rx = jiffies; ei_local->stat.rx_packets++; - add_rx_bytes(&ei_local->stat, pkt_len); + ei_local->stat.rx_bytes += pkt_len; if (pkt_stat & ENRSR_PHY) ei_local->stat.multicast++; } @@ -1801,11 +1721,11 @@ long e8390_base = dev->base_addr; if(dev->flags&IFF_PROMISC) - outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR); + outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR); else if(dev->flags&IFF_ALLMULTI || dev->mc_list) - outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR); + outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR); else - outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); + outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); } /* @@ -1813,28 +1733,30 @@ * be parallel to just about everything else. Its also fairly quick and * not called too often. Must protect against both bh and irq users */ - + +#define dev_lock(dev) (((struct ei_device *)(dev)->priv)->page_lock) + static void set_multicast_list(struct net_device *dev) { unsigned long flags; - spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags); + spin_lock_irqsave(&dev_lock(dev), flags); do_set_multicast_list(dev); - spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags); + spin_unlock_irqrestore(&dev_lock(dev), flags); } /** - * ethdev_init - init rest of 8390 device struct + * axdev_init - init rest of 8390 device struct * @dev: network device structure to init * * Initialize the rest of the 8390 device structure. Do NOT __init * this, as it is used by 8390 based modular drivers too. */ -static int ethdev_init(struct net_device *dev) +static int axdev_init(struct net_device *dev) { if (ei_debug > 1) - printk(version); + printk(version_8390); if (dev->priv == NULL) { @@ -1857,20 +1779,18 @@ return 0; } - - /* This page of functions should be 8390 generic */ /* Follow National Semi's recommendations for initializing the "NIC". */ /** - * NS8390_init - initialize 8390 hardware + * AX88190_init - initialize 8390 hardware * @dev: network device to initialize * @startp: boolean. non-zero value to initiate chip processing * * Must be called with lock held. */ -static void NS8390_init(struct net_device *dev, int startp) +static void AX88190_init(struct net_device *dev, int startp) { axnet_dev_t *info = (axnet_dev_t *)dev; long e8390_base = dev->base_addr; @@ -1887,7 +1807,7 @@ outb_p(0x00, e8390_base + EN0_RCNTLO); outb_p(0x00, e8390_base + EN0_RCNTHI); /* Set to monitor and loopback mode -- this is vital!. */ - outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */ + outb_p(E8390_RXOFF|0x40, e8390_base + EN0_RXCR); /* 0x60 */ outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */ /* Set the transmit page and receive ring. */ outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR); @@ -1931,7 +1851,7 @@ outb_p(E8390_TXCONFIG | info->duplex_flag, e8390_base + EN0_TXCR); /* xmit on. */ /* 3c503 TechMan says rxconfig only after the NIC is started. */ - outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */ + outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); /* rx on, */ do_set_multicast_list(dev); /* (re)load the mcast table */ } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pcmcia/com20020_cs.c linux-2.5/drivers/net/pcmcia/com20020_cs.c --- linux-2.5.5/drivers/net/pcmcia/com20020_cs.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/net/pcmcia/com20020_cs.c Fri Feb 8 15:46:33 2002 @@ -122,6 +122,7 @@ MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); +MODULE_LICENSE("GPL"); /*====================================================================*/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pcmcia/i82593.h linux-2.5/drivers/net/pcmcia/i82593.h --- linux-2.5.5/drivers/net/pcmcia/i82593.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/pcmcia/i82593.h Tue Jan 22 17:43:48 2002 @@ -0,0 +1,224 @@ +/* + * Definitions for Intel 82593 CSMA/CD Core LAN Controller + * The definitions are taken from the 1992 users manual with Intel + * order number 297125-001. + * + * /usr/src/pc/RCS/i82593.h,v 1.1 1996/07/17 15:23:12 root Exp + * + * Copyright 1994, Anders Klemets + * + * This software may be freely distributed for noncommercial purposes + * as long as this notice is retained. + * + * HISTORY + * i82593.h,v + * Revision 1.1 1996/07/17 15:23:12 root + * Initial revision + * + * Revision 1.3 1995/04/05 15:13:58 adj + * Initial alpha release + * + * Revision 1.2 1994/06/16 23:57:31 klemets + * Mirrored all the fields in the configuration block. + * + * Revision 1.1 1994/06/02 20:25:34 klemets + * Initial revision + * + * + */ +#ifndef _I82593_H +#define _I82593_H + +/* Intel 82593 CSMA/CD Core LAN Controller */ + +/* Port 0 Command Register definitions */ + +/* Execution operations */ +#define OP0_NOP 0 /* CHNL = 0 */ +#define OP0_SWIT_TO_PORT_1 0 /* CHNL = 1 */ +#define OP0_IA_SETUP 1 +#define OP0_CONFIGURE 2 +#define OP0_MC_SETUP 3 +#define OP0_TRANSMIT 4 +#define OP0_TDR 5 +#define OP0_DUMP 6 +#define OP0_DIAGNOSE 7 +#define OP0_TRANSMIT_NO_CRC 9 +#define OP0_RETRANSMIT 12 +#define OP0_ABORT 13 +/* Reception operations */ +#define OP0_RCV_ENABLE 8 +#define OP0_RCV_DISABLE 10 +#define OP0_STOP_RCV 11 +/* Status pointer control operations */ +#define OP0_FIX_PTR 15 /* CHNL = 1 */ +#define OP0_RLS_PTR 15 /* CHNL = 0 */ +#define OP0_RESET 14 + +#define CR0_CHNL (1 << 4) /* 0=Channel 0, 1=Channel 1 */ +#define CR0_STATUS_0 0x00 +#define CR0_STATUS_1 0x20 +#define CR0_STATUS_2 0x40 +#define CR0_STATUS_3 0x60 +#define CR0_INT_ACK (1 << 7) /* 0=No ack, 1=acknowledge */ + +/* Port 0 Status Register definitions */ + +#define SR0_NO_RESULT 0 /* dummy */ +#define SR0_EVENT_MASK 0x0f +#define SR0_IA_SETUP_DONE 1 +#define SR0_CONFIGURE_DONE 2 +#define SR0_MC_SETUP_DONE 3 +#define SR0_TRANSMIT_DONE 4 +#define SR0_TDR_DONE 5 +#define SR0_DUMP_DONE 6 +#define SR0_DIAGNOSE_PASSED 7 +#define SR0_TRANSMIT_NO_CRC_DONE 9 +#define SR0_RETRANSMIT_DONE 12 +#define SR0_EXECUTION_ABORTED 13 +#define SR0_END_OF_FRAME 8 +#define SR0_RECEPTION_ABORTED 10 +#define SR0_DIAGNOSE_FAILED 15 +#define SR0_STOP_REG_HIT 11 + +#define SR0_CHNL (1 << 4) +#define SR0_EXECUTION (1 << 5) +#define SR0_RECEPTION (1 << 6) +#define SR0_INTERRUPT (1 << 7) +#define SR0_BOTH_RX_TX (SR0_EXECUTION | SR0_RECEPTION) + +#define SR3_EXEC_STATE_MASK 0x03 +#define SR3_EXEC_IDLE 0 +#define SR3_TX_ABORT_IN_PROGRESS 1 +#define SR3_EXEC_ACTIVE 2 +#define SR3_ABORT_IN_PROGRESS 3 +#define SR3_EXEC_CHNL (1 << 2) +#define SR3_STP_ON_NO_RSRC (1 << 3) +#define SR3_RCVING_NO_RSRC (1 << 4) +#define SR3_RCV_STATE_MASK 0x60 +#define SR3_RCV_IDLE 0x00 +#define SR3_RCV_READY 0x20 +#define SR3_RCV_ACTIVE 0x40 +#define SR3_RCV_STOP_IN_PROG 0x60 +#define SR3_RCV_CHNL (1 << 7) + +/* Port 1 Command Register definitions */ + +#define OP1_NOP 0 +#define OP1_SWIT_TO_PORT_0 1 +#define OP1_INT_DISABLE 2 +#define OP1_INT_ENABLE 3 +#define OP1_SET_TS 5 +#define OP1_RST_TS 7 +#define OP1_POWER_DOWN 8 +#define OP1_RESET_RING_MNGMT 11 +#define OP1_RESET 14 +#define OP1_SEL_RST 15 + +#define CR1_STATUS_4 0x00 +#define CR1_STATUS_5 0x20 +#define CR1_STATUS_6 0x40 +#define CR1_STOP_REG_UPDATE (1 << 7) + +/* Receive frame status bits */ + +#define RX_RCLD (1 << 0) +#define RX_IA_MATCH (1 << 1) +#define RX_NO_AD_MATCH (1 << 2) +#define RX_NO_SFD (1 << 3) +#define RX_SRT_FRM (1 << 7) +#define RX_OVRRUN (1 << 8) +#define RX_ALG_ERR (1 << 10) +#define RX_CRC_ERR (1 << 11) +#define RX_LEN_ERR (1 << 12) +#define RX_RCV_OK (1 << 13) +#define RX_TYP_LEN (1 << 15) + +/* Transmit status bits */ + +#define TX_NCOL_MASK 0x0f +#define TX_FRTL (1 << 4) +#define TX_MAX_COL (1 << 5) +#define TX_HRT_BEAT (1 << 6) +#define TX_DEFER (1 << 7) +#define TX_UND_RUN (1 << 8) +#define TX_LOST_CTS (1 << 9) +#define TX_LOST_CRS (1 << 10) +#define TX_LTCOL (1 << 11) +#define TX_OK (1 << 13) +#define TX_COLL (1 << 15) + +struct i82593_conf_block { + u_char fifo_limit : 4, + forgnesi : 1, + fifo_32 : 1, + d6mod : 1, + throttle_enb : 1; + u_char throttle : 6, + cntrxint : 1, + contin : 1; + u_char addr_len : 3, + acloc : 1, + preamb_len : 2, + loopback : 2; + u_char lin_prio : 3, + tbofstop : 1, + exp_prio : 3, + bof_met : 1; + u_char : 4, + ifrm_spc : 4; + u_char : 5, + slottim_low : 3; + u_char slottim_hi : 3, + : 1, + max_retr : 4; + u_char prmisc : 1, + bc_dis : 1, + : 1, + crs_1 : 1, + nocrc_ins : 1, + crc_1632 : 1, + : 1, + crs_cdt : 1; + u_char cs_filter : 3, + crs_src : 1, + cd_filter : 3, + : 1; + u_char : 2, + min_fr_len : 6; + u_char lng_typ : 1, + lng_fld : 1, + rxcrc_xf : 1, + artx : 1, + sarec : 1, + tx_jabber : 1, /* why is this called max_len in the manual? */ + hash_1 : 1, + lbpkpol : 1; + u_char : 6, + fdx : 1, + : 1; + u_char dummy_6 : 6, /* supposed to be ones */ + mult_ia : 1, + dis_bof : 1; + u_char dummy_1 : 1, /* supposed to be one */ + tx_ifs_retrig : 2, + mc_all : 1, + rcv_mon : 2, + frag_acpt : 1, + tstrttrs : 1; + u_char fretx : 1, + runt_eop : 1, + hw_sw_pin : 1, + big_endn : 1, + syncrqs : 1, + sttlen : 1, + tx_eop : 1, + rx_eop : 1; + u_char rbuf_size : 5, + rcvstop : 1, + : 2; +}; + +#define I82593_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ + +#endif /* _I82593_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pcmcia/nmclan_cs.c linux-2.5/drivers/net/pcmcia/nmclan_cs.c --- linux-2.5.5/drivers/net/pcmcia/nmclan_cs.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/net/pcmcia/nmclan_cs.c Thu Dec 27 16:32:31 2001 @@ -106,6 +106,10 @@ ---------------------------------------------------------------------------- */ +#define DRV_NAME "nmclan_cs" +#define DRV_VERSION "0.16" + + /* ---------------------------------------------------------------------------- Conditional Compilation Options ---------------------------------------------------------------------------- */ @@ -130,6 +134,9 @@ #include #include #include +#include + +#include #include #include #include @@ -375,7 +382,7 @@ static char rcsid[] = "nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao"; static char *version = -"nmclan_cs 0.16 (Roger C. Pao)"; +DRV_NAME " " DRV_VERSION " (Roger C. Pao)"; #endif static dev_info_t dev_info="nmclan_cs"; @@ -1001,6 +1008,66 @@ return 0; } /* mace_close */ + +static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + /* dev_ioctl() in ../../net/core/dev.c has already checked + capable(CAP_NET_ADMIN), so don't bother with that here. */ + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, DRV_NAME); + strcpy (info.version, DRV_VERSION); + sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + +#ifdef PCMCIA_DEBUG + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = pc_debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + pc_debug = edata.data; + return 0; + } +#endif + + default: + break; + } + + return -EOPNOTSUPP; +} + +static int smc91c92_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + switch (cmd) { + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + + default: + return -EOPNOTSUPP; + } + return 0; +} /* ---------------------------------------------------------------------------- mace_start_xmit diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pcmcia/wavelan.h linux-2.5/drivers/net/pcmcia/wavelan.h --- linux-2.5.5/drivers/net/pcmcia/wavelan.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/pcmcia/wavelan.h Tue Jan 22 17:43:48 2002 @@ -0,0 +1,386 @@ +/* + * Wavelan Pcmcia driver + * + * Jean II - HPLB '96 + * + * Reorganization and extension of the driver. + * Original copyright follow. See wavelan_cs.h for details. + * + * This file contain the declarations of the Wavelan hardware. Note that + * the Pcmcia Wavelan include a i82593 controller (see definitions in + * file i82593.h). + * + * The main difference between the pcmcia hardware and the ISA one is + * the Ethernet Controller (i82593 instead of i82586). The i82593 allow + * only one send buffer. The PSA (Parameter Storage Area : EEprom for + * permanent storage of various info) is memory mapped, but not the + * MMI (Modem Management Interface). + */ + +/* + * Definitions for the AT&T GIS (formerly NCR) WaveLAN PCMCIA card: + * An Ethernet-like radio transceiver controlled by an Intel 82593 + * coprocessor. + * + * + **************************************************************************** + * Copyright 1995 + * Anthony D. Joseph + * Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this program + * for any purpose and without fee is hereby granted, provided + * that this copyright and permission notice appear on all copies + * and supporting documentation, the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * program without specific prior permission, and notice be given + * in supporting documentation that copying and distribution is + * by permission of M.I.T. M.I.T. makes no representations about + * the suitability of this software for any purpose. It is pro- + * vided "as is" without express or implied warranty. + **************************************************************************** + * + * + * Credits: + * Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht for + * providing extremely useful information about WaveLAN PCMCIA hardware + * + * This driver is based upon several other drivers, in particular: + * David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter + * Bruce Janson's Linux driver for the AT-bus WaveLAN adapter + * Anders Klemets' PCMCIA WaveLAN adapter driver + * Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter + */ + +#ifndef _WAVELAN_H +#define _WAVELAN_H + +/************************** MAGIC NUMBERS ***************************/ + +/* The detection of the wavelan card is made by reading the MAC address + * from the card and checking it. If you have a non AT&T product (OEM, + * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this + * part to accomodate your hardware... + */ +const unsigned char MAC_ADDRESSES[][3] = +{ + { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */ + { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */ + { 0x00, 0x00, 0xE1 }, /* Hitachi Wavelan */ + { 0x00, 0x60, 0x1D } /* Lucent Wavelan (another one) */ + /* Add your card here and send me the patch ! */ +}; + +/* + * Constants used to convert channels to frequencies + */ + +/* Frequency available in the 2.0 modem, in units of 250 kHz + * (as read in the offset register of the dac area). + * Used to map channel numbers used by `wfreqsel' to frequencies + */ +const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, + 0xD0, 0xF0, 0xF8, 0x150 }; + +/* Frequencies of the 1.0 modem (fixed frequencies). + * Use to map the PSA `subband' to a frequency + * Note : all frequencies apart from the first one need to be multiplied by 10 + */ +const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; + + +/*************************** PC INTERFACE ****************************/ + +/* WaveLAN host interface definitions */ + +#define LCCR(base) (base) /* LAN Controller Command Register */ +#define LCSR(base) (base) /* LAN Controller Status Register */ +#define HACR(base) (base+0x1) /* Host Adapter Command Register */ +#define HASR(base) (base+0x1) /* Host Adapter Status Register */ +#define PIORL(base) (base+0x2) /* Program I/O Register Low */ +#define RPLL(base) (base+0x2) /* Receive Pointer Latched Low */ +#define PIORH(base) (base+0x3) /* Program I/O Register High */ +#define RPLH(base) (base+0x3) /* Receive Pointer Latched High */ +#define PIOP(base) (base+0x4) /* Program I/O Port */ +#define MMR(base) (base+0x6) /* MMI Address Register */ +#define MMD(base) (base+0x7) /* MMI Data Register */ + +/* Host Adaptor Command Register bit definitions */ + +#define HACR_LOF (1 << 3) /* Lock Out Flag, toggle every 250ms */ +#define HACR_PWR_STAT (1 << 4) /* Power State, 1=active, 0=sleep */ +#define HACR_TX_DMA_RESET (1 << 5) /* Reset transmit DMA ptr on high */ +#define HACR_RX_DMA_RESET (1 << 6) /* Reset receive DMA ptr on high */ +#define HACR_ROM_WEN (1 << 7) /* EEPROM write enabled when true */ + +#define HACR_RESET (HACR_TX_DMA_RESET | HACR_RX_DMA_RESET) +#define HACR_DEFAULT (HACR_PWR_STAT) + +/* Host Adapter Status Register bit definitions */ + +#define HASR_MMI_BUSY (1 << 2) /* MMI is busy when true */ +#define HASR_LOF (1 << 3) /* Lock out flag status */ +#define HASR_NO_CLK (1 << 4) /* active when modem not connected */ + +/* Miscellaneous bit definitions */ + +#define PIORH_SEL_TX (1 << 5) /* PIOR points to 0=rx/1=tx buffer */ +#define MMR_MMI_WR (1 << 0) /* Next MMI cycle is 0=read, 1=write */ +#define PIORH_MASK 0x1f /* only low 5 bits are significant */ +#define RPLH_MASK 0x1f /* only low 5 bits are significant */ +#define MMI_ADDR_MASK 0x7e /* Bits 1-6 of MMR are significant */ + +/* Attribute Memory map */ + +#define CIS_ADDR 0x0000 /* Card Information Status Register */ +#define PSA_ADDR 0x0e00 /* Parameter Storage Area address */ +#define EEPROM_ADDR 0x1000 /* EEPROM address (unused ?) */ +#define COR_ADDR 0x4000 /* Configuration Option Register */ + +/* Configuration Option Register bit definitions */ + +#define COR_CONFIG (1 << 0) /* Config Index, 0 when unconfigured */ +#define COR_SW_RESET (1 << 7) /* Software Reset on true */ +#define COR_LEVEL_IRQ (1 << 6) /* Level IRQ */ + +/* Local Memory map */ + +#define RX_BASE 0x0000 /* Receive memory, 8 kB */ +#define TX_BASE 0x2000 /* Transmit memory, 2 kB */ +#define UNUSED_BASE 0x2800 /* Unused, 22 kB */ +#define RX_SIZE (TX_BASE-RX_BASE) /* Size of receive area */ +#define RX_SIZE_SHIFT 6 /* Bits to shift in stop register */ + +#define TRUE 1 +#define FALSE 0 + +#define MOD_ENAL 1 +#define MOD_PROM 2 + +/* Size of a MAC address */ +#define WAVELAN_ADDR_SIZE 6 + +/* Maximum size of Wavelan packet */ +#define WAVELAN_MTU 1500 + +#define MAXDATAZ (6 + 6 + 2 + WAVELAN_MTU) + +/********************** PARAMETER STORAGE AREA **********************/ + +/* + * Parameter Storage Area (PSA). + */ +typedef struct psa_t psa_t; +struct psa_t +{ + /* For the PCMCIA Adapter, locations 0x00-0x0F are unused and fixed at 00 */ + unsigned char psa_io_base_addr_1; /* [0x00] Base address 1 ??? */ + unsigned char psa_io_base_addr_2; /* [0x01] Base address 2 */ + unsigned char psa_io_base_addr_3; /* [0x02] Base address 3 */ + unsigned char psa_io_base_addr_4; /* [0x03] Base address 4 */ + unsigned char psa_rem_boot_addr_1; /* [0x04] Remote Boot Address 1 */ + unsigned char psa_rem_boot_addr_2; /* [0x05] Remote Boot Address 2 */ + unsigned char psa_rem_boot_addr_3; /* [0x06] Remote Boot Address 3 */ + unsigned char psa_holi_params; /* [0x07] HOst Lan Interface (HOLI) Parameters */ + unsigned char psa_int_req_no; /* [0x08] Interrupt Request Line */ + unsigned char psa_unused0[7]; /* [0x09-0x0F] unused */ + + unsigned char psa_univ_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x10-0x15] Universal (factory) MAC Address */ + unsigned char psa_local_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x16-1B] Local MAC Address */ + unsigned char psa_univ_local_sel; /* [0x1C] Universal Local Selection */ +#define PSA_UNIVERSAL 0 /* Universal (factory) */ +#define PSA_LOCAL 1 /* Local */ + unsigned char psa_comp_number; /* [0x1D] Compatability Number: */ +#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */ +#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */ +#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */ +#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */ +#define PSA_COMP_PCMCIA_915 4 /* PCMCIA 915 MHz or 2.0 */ + unsigned char psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */ + unsigned char psa_feature_select; /* [0x1F] Call code required (1=on) */ +#define PSA_FEATURE_CALL_CODE 0x01 /* Call code required (Japan) */ + unsigned char psa_subband; /* [0x20] Subband */ +#define PSA_SUBBAND_915 0 /* 915 MHz or 2.0 */ +#define PSA_SUBBAND_2425 1 /* 2425 MHz */ +#define PSA_SUBBAND_2460 2 /* 2460 MHz */ +#define PSA_SUBBAND_2484 3 /* 2484 MHz */ +#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */ + unsigned char psa_quality_thr; /* [0x21] Modem Quality Threshold */ + unsigned char psa_mod_delay; /* [0x22] Modem Delay ??? (reserved) */ + unsigned char psa_nwid[2]; /* [0x23-0x24] Network ID */ + unsigned char psa_nwid_select; /* [0x25] Network ID Select On Off */ + unsigned char psa_encryption_select; /* [0x26] Encryption On Off */ + unsigned char psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */ + unsigned char psa_databus_width; /* [0x2F] AT bus width select 8/16 */ + unsigned char psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */ + unsigned char psa_nwid_prefix[2]; /* [0x38-0x39] Roaming domain */ + unsigned char psa_reserved[2]; /* [0x3A-0x3B] Reserved - fixed 00 */ + unsigned char psa_conf_status; /* [0x3C] Conf Status, bit 0=1:config*/ + unsigned char psa_crc[2]; /* [0x3D] CRC-16 over PSA */ + unsigned char psa_crc_status; /* [0x3F] CRC Valid Flag */ +}; + +/* Size for structure checking (if padding is correct) */ +#define PSA_SIZE 64 + +/* Calculate offset of a field in the above structure + * Warning : only even addresses are used */ +#define psaoff(p,f) ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL)) + +/******************** MODEM MANAGEMENT INTERFACE ********************/ + +/* + * Modem Management Controller (MMC) write structure. + */ +typedef struct mmw_t mmw_t; +struct mmw_t +{ + unsigned char mmw_encr_key[8]; /* encryption key */ + unsigned char mmw_encr_enable; /* enable/disable encryption */ +#define MMW_ENCR_ENABLE_MODE 0x02 /* Mode of security option */ +#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option */ + unsigned char mmw_unused0[1]; /* unused */ + unsigned char mmw_des_io_invert; /* Encryption option */ +#define MMW_DES_IO_INVERT_RES 0x0F /* Reserved */ +#define MMW_DES_IO_INVERT_CTRL 0xF0 /* Control ??? (set to 0) */ + unsigned char mmw_unused1[5]; /* unused */ + unsigned char mmw_loopt_sel; /* looptest selection */ +#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* disable NWID filtering */ +#define MMW_LOOPT_SEL_INT 0x20 /* activate Attention Request */ +#define MMW_LOOPT_SEL_LS 0x10 /* looptest w/o collision avoidance */ +#define MMW_LOOPT_SEL_LT3A 0x08 /* looptest 3a */ +#define MMW_LOOPT_SEL_LT3B 0x04 /* looptest 3b */ +#define MMW_LOOPT_SEL_LT3C 0x02 /* looptest 3c */ +#define MMW_LOOPT_SEL_LT3D 0x01 /* looptest 3d */ + unsigned char mmw_jabber_enable; /* jabber timer enable */ + /* Abort transmissions > 200 ms */ + unsigned char mmw_freeze; /* freeze / unfreeeze signal level */ + /* 0 : signal level & qual updated for every new message, 1 : frozen */ + unsigned char mmw_anten_sel; /* antenna selection */ +#define MMW_ANTEN_SEL_SEL 0x01 /* direct antenna selection */ +#define MMW_ANTEN_SEL_ALG_EN 0x02 /* antenna selection algo. enable */ + unsigned char mmw_ifs; /* inter frame spacing */ + /* min time between transmission in bit periods (.5 us) - bit 0 ignored */ + unsigned char mmw_mod_delay; /* modem delay (synchro) */ + unsigned char mmw_jam_time; /* jamming time (after collision) */ + unsigned char mmw_unused2[1]; /* unused */ + unsigned char mmw_thr_pre_set; /* level threshold preset */ + /* Discard all packet with signal < this value (4) */ + unsigned char mmw_decay_prm; /* decay parameters */ + unsigned char mmw_decay_updat_prm; /* decay update parameterz */ + unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */ + /* Discard all packet with quality < this value (3) */ + unsigned char mmw_netw_id_l; /* NWID low order byte */ + unsigned char mmw_netw_id_h; /* NWID high order byte */ + /* Network ID or Domain : create virtual net on the air */ + + /* 2.0 Hardware extension - frequency selection support */ + unsigned char mmw_mode_select; /* for analog tests (set to 0) */ + unsigned char mmw_unused3[1]; /* unused */ + unsigned char mmw_fee_ctrl; /* frequency eeprom control */ +#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions */ +#define MMW_FEE_CTRL_DWLD 0x08 /* Download eeprom to mmc */ +#define MMW_FEE_CTRL_CMD 0x07 /* EEprom commands : */ +#define MMW_FEE_CTRL_READ 0x06 /* Read */ +#define MMW_FEE_CTRL_WREN 0x04 /* Write enable */ +#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address */ +#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses */ +#define MMW_FEE_CTRL_WDS 0x04 /* Write disable */ +#define MMW_FEE_CTRL_PRREAD 0x16 /* Read addr from protect register */ +#define MMW_FEE_CTRL_PREN 0x14 /* Protect register enable */ +#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers */ +#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write addr in protect register */ +#define MMW_FEE_CTRL_PRDS 0x14 /* Protect register disable */ + /* Never issue this command (PRDS) : it's irreversible !!! */ + + unsigned char mmw_fee_addr; /* EEprom address */ +#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel */ +#define MMW_FEE_ADDR_OFFSET 0x0F /* Offset in channel data */ +#define MMW_FEE_ADDR_EN 0xC0 /* FEE_CTRL enable operations */ +#define MMW_FEE_ADDR_DS 0x00 /* FEE_CTRL disable operations */ +#define MMW_FEE_ADDR_ALL 0x40 /* FEE_CTRL all operations */ +#define MMW_FEE_ADDR_CLEAR 0xFF /* FEE_CTRL clear operations */ + + unsigned char mmw_fee_data_l; /* Write data to EEprom */ + unsigned char mmw_fee_data_h; /* high octet */ + unsigned char mmw_ext_ant; /* Setting for external antenna */ +#define MMW_EXT_ANT_EXTANT 0x01 /* Select external antenna */ +#define MMW_EXT_ANT_POL 0x02 /* Polarity of the antenna */ +#define MMW_EXT_ANT_INTERNAL 0x00 /* Internal antenna */ +#define MMW_EXT_ANT_EXTERNAL 0x03 /* External antenna */ +#define MMW_EXT_ANT_IQ_TEST 0x1C /* IQ test pattern (set to 0) */ +}; + +/* Size for structure checking (if padding is correct) */ +#define MMW_SIZE 37 + +/* Calculate offset of a field in the above structure */ +#define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0) + + +/* + * Modem Management Controller (MMC) read structure. + */ +typedef struct mmr_t mmr_t; +struct mmr_t +{ + unsigned char mmr_unused0[8]; /* unused */ + unsigned char mmr_des_status; /* encryption status */ + unsigned char mmr_des_avail; /* encryption available (0x55 read) */ +#define MMR_DES_AVAIL_DES 0x55 /* DES available */ +#define MMR_DES_AVAIL_AES 0x33 /* AES (AT&T) available */ + unsigned char mmr_des_io_invert; /* des I/O invert register */ + unsigned char mmr_unused1[5]; /* unused */ + unsigned char mmr_dce_status; /* DCE status */ +#define MMR_DCE_STATUS_RX_BUSY 0x01 /* receiver busy */ +#define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */ +#define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */ +#define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */ +#define MMR_DCE_STATUS 0x0F /* mask to get the bits */ + unsigned char mmr_dsp_id; /* DSP id (AA = Daedalus rev A) */ + unsigned char mmr_unused2[2]; /* unused */ + unsigned char mmr_correct_nwid_l; /* # of correct NWID's rxd (low) */ + unsigned char mmr_correct_nwid_h; /* # of correct NWID's rxd (high) */ + /* Warning : Read high order octet first !!! */ + unsigned char mmr_wrong_nwid_l; /* # of wrong NWID's rxd (low) */ + unsigned char mmr_wrong_nwid_h; /* # of wrong NWID's rxd (high) */ + unsigned char mmr_thr_pre_set; /* level threshold preset */ +#define MMR_THR_PRE_SET 0x3F /* level threshold preset */ +#define MMR_THR_PRE_SET_CUR 0x80 /* Current signal above it */ + unsigned char mmr_signal_lvl; /* signal level */ +#define MMR_SIGNAL_LVL 0x3F /* signal level */ +#define MMR_SIGNAL_LVL_VALID 0x80 /* Updated since last read */ + unsigned char mmr_silence_lvl; /* silence level (noise) */ +#define MMR_SILENCE_LVL 0x3F /* silence level */ +#define MMR_SILENCE_LVL_VALID 0x80 /* Updated since last read */ + unsigned char mmr_sgnl_qual; /* signal quality */ +#define MMR_SGNL_QUAL 0x0F /* signal quality */ +#define MMR_SGNL_QUAL_ANT 0x80 /* current antenna used */ + unsigned char mmr_netw_id_l; /* NWID low order byte ??? */ + unsigned char mmr_unused3[3]; /* unused */ + + /* 2.0 Hardware extension - frequency selection support */ + unsigned char mmr_fee_status; /* Status of frequency eeprom */ +#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision id */ +#define MMR_FEE_STATUS_DWLD 0x08 /* Download in progress */ +#define MMR_FEE_STATUS_BUSY 0x04 /* EEprom busy */ + unsigned char mmr_unused4[1]; /* unused */ + unsigned char mmr_fee_data_l; /* Read data from eeprom (low) */ + unsigned char mmr_fee_data_h; /* Read data from eeprom (high) */ +}; + +/* Size for structure checking (if padding is correct) */ +#define MMR_SIZE 36 + +/* Calculate offset of a field in the above structure */ +#define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0) + + +/* Make the two above structures one */ +typedef union mm_t +{ + struct mmw_t w; /* Write to the mmc */ + struct mmr_t r; /* Read from the mmc */ +} mm_t; + +#endif /* _WAVELAN_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pcmcia/wavelan_cs.c linux-2.5/drivers/net/pcmcia/wavelan_cs.c --- linux-2.5.5/drivers/net/pcmcia/wavelan_cs.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/pcmcia/wavelan_cs.c Tue Jan 22 17:43:49 2002 @@ -0,0 +1,4837 @@ +/* + * Wavelan Pcmcia driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * Original copyright follow. See wavelan_cs.h for details. + * + * This code is derived from Anthony D. Joseph's code and all the changes here + * are also under the original copyright below. + * + * This code supports version 2.00 of WaveLAN/PCMCIA cards (2.4GHz), and + * can work on Linux 2.0.36 with support of David Hinds' PCMCIA Card Services + * + * Joe Finney (joe@comp.lancs.ac.uk) at Lancaster University in UK added + * critical code in the routine to initialize the Modem Management Controller. + * + * Thanks to Alan Cox and Bruce Janson for their advice. + * + * -- Yunzhou Li (scip4166@nus.sg) + * +#ifdef WAVELAN_ROAMING + * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu) + * based on patch by Joe Finney from Lancaster University. +#endif + * + * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An + * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor. + * + * A non-shared memory PCMCIA ethernet driver for linux + * + * ISA version modified to support PCMCIA by Anthony Joseph (adj@lcs.mit.edu) + * + * + * Joseph O'Sullivan & John Langford (josullvn@cs.cmu.edu & jcl@cs.cmu.edu) + * + * Apr 2 '98 made changes to bring the i82593 control/int handling in line + * with offical specs... + * + **************************************************************************** + * Copyright 1995 + * Anthony D. Joseph + * Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this program + * for any purpose and without fee is hereby granted, provided + * that this copyright and permission notice appear on all copies + * and supporting documentation, the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * program without specific prior permission, and notice be given + * in supporting documentation that copying and distribution is + * by permission of M.I.T. M.I.T. makes no representations about + * the suitability of this software for any purpose. It is pro- + * vided "as is" without express or implied warranty. + **************************************************************************** + * + */ + +#include "wavelan_cs.h" /* Private header */ + +/************************* MISC SUBROUTINES **************************/ +/* + * Subroutines which won't fit in one of the following category + * (wavelan modem or i82593) + */ + +/*------------------------------------------------------------------*/ +/* + * Wrapper for disabling interrupts. + * (note : inline, so optimised away) + */ +static inline void +wv_splhi(net_local * lp, + unsigned long * pflags) +{ + spin_lock_irqsave(&lp->spinlock, *pflags); + /* Note : above does the cli(); itself */ +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper for re-enabling interrupts. + */ +static inline void +wv_splx(net_local * lp, + unsigned long * pflags) +{ + spin_unlock_irqrestore(&lp->spinlock, *pflags); + + /* Note : enabling interrupts on the hardware is done in wv_ru_start() + * via : outb(OP1_INT_ENABLE, LCCR(base)); + */ +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper for reporting error to cardservices + */ +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +#ifdef STRUCT_CHECK +/*------------------------------------------------------------------*/ +/* + * Sanity routine to verify the sizes of the various WaveLAN interface + * structures. + */ +static char * +wv_structuct_check(void) +{ +#define SC(t,s,n) if (sizeof(t) != s) return(n); + + SC(psa_t, PSA_SIZE, "psa_t"); + SC(mmw_t, MMW_SIZE, "mmw_t"); + SC(mmr_t, MMR_SIZE, "mmr_t"); + +#undef SC + + return((char *) NULL); +} /* wv_structuct_check */ +#endif /* STRUCT_CHECK */ + +/******************* MODEM MANAGEMENT SUBROUTINES *******************/ +/* + * Useful subroutines to manage the modem of the wavelan + */ + +/*------------------------------------------------------------------*/ +/* + * Read from card's Host Adaptor Status Register. + */ +static inline u_char +hasr_read(u_long base) +{ + return(inb(HASR(base))); +} /* hasr_read */ + +/*------------------------------------------------------------------*/ +/* + * Write to card's Host Adapter Command Register. + */ +static inline void +hacr_write(u_long base, + u_char hacr) +{ + outb(hacr, HACR(base)); +} /* hacr_write */ + +/*------------------------------------------------------------------*/ +/* + * Write to card's Host Adapter Command Register. Include a delay for + * those times when it is needed. + */ +static inline void +hacr_write_slow(u_long base, + u_char hacr) +{ + hacr_write(base, hacr); + /* delay might only be needed sometimes */ + mdelay(1); +} /* hacr_write_slow */ + +/*------------------------------------------------------------------*/ +/* + * Read the Parameter Storage Area from the WaveLAN card's memory + */ +static void +psa_read(device * dev, + int o, /* offset in PSA */ + u_char * b, /* buffer to fill */ + int n) /* size to read */ +{ + u_char * ptr = ((u_char *)dev->mem_start) + PSA_ADDR + (o << 1); + + while(n-- > 0) + { + *b++ = readb(ptr); + /* Due to a lack of address decode pins, the WaveLAN PCMCIA card + * only supports reading even memory addresses. That means the + * increment here MUST be two. + * Because of that, we can't use memcpy_fromio()... + */ + ptr += 2; + } +} /* psa_read */ + +/*------------------------------------------------------------------*/ +/* + * Write the Paramter Storage Area to the WaveLAN card's memory + */ +static void +psa_write(device * dev, + int o, /* Offset in psa */ + u_char * b, /* Buffer in memory */ + int n) /* Length of buffer */ +{ + u_char * ptr = ((u_char *) dev->mem_start) + PSA_ADDR + (o << 1); + int count = 0; + ioaddr_t base = dev->base_addr; + /* As there seem to have no flag PSA_BUSY as in the ISA model, we are + * oblige to verify this address to know when the PSA is ready... */ + volatile u_char * verify = ((u_char *) dev->mem_start) + PSA_ADDR + + (psaoff(0, psa_comp_number) << 1); + + /* Authorize writting to PSA */ + hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN); + + while(n-- > 0) + { + /* write to PSA */ + writeb(*b++, ptr); + ptr += 2; + + /* I don't have the spec, so I don't know what the correct + * sequence to write is. This hack seem to work for me... */ + count = 0; + while((readb(verify) != PSA_COMP_PCMCIA_915) && (count++ < 100)) + mdelay(1); + } + + /* Put the host interface back in standard state */ + hacr_write(base, HACR_DEFAULT); +} /* psa_write */ + +#ifdef SET_PSA_CRC +/*------------------------------------------------------------------*/ +/* + * Calculate the PSA CRC + * Thanks to Valster, Nico for the code + * NOTE: By specifying a length including the CRC position the + * returned value should be zero. (i.e. a correct checksum in the PSA) + * + * The Windows drivers don't use the CRC, but the AP and the PtP tool + * depend on it. + */ +static u_short +psa_crc(unsigned char * psa, /* The PSA */ + int size) /* Number of short for CRC */ +{ + int byte_cnt; /* Loop on the PSA */ + u_short crc_bytes = 0; /* Data in the PSA */ + int bit_cnt; /* Loop on the bits of the short */ + + for(byte_cnt = 0; byte_cnt < size; byte_cnt++ ) + { + crc_bytes ^= psa[byte_cnt]; /* Its an xor */ + + for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ ) + { + if(crc_bytes & 0x0001) + crc_bytes = (crc_bytes >> 1) ^ 0xA001; + else + crc_bytes >>= 1 ; + } + } + + return crc_bytes; +} /* psa_crc */ +#endif /* SET_PSA_CRC */ + +/*------------------------------------------------------------------*/ +/* + * update the checksum field in the Wavelan's PSA + */ +static void +update_psa_checksum(device * dev) +{ +#ifdef SET_PSA_CRC + psa_t psa; + u_short crc; + + /* read the parameter storage area */ + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + + /* update the checksum */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1]) + - sizeof(psa.psa_crc_status)); + + psa.psa_crc[0] = crc & 0xFF; + psa.psa_crc[1] = (crc & 0xFF00) >> 8; + + /* Write it ! */ + psa_write(dev, (char *)&psa.psa_crc - (char *)&psa, + (unsigned char *)&psa.psa_crc, 2); + +#ifdef DEBUG_IOCTL_INFO + printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", + dev->name, psa.psa_crc[0], psa.psa_crc[1]); + + /* Check again (luxury !) */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc_status)); + + if(crc != 0) + printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name); +#endif /* DEBUG_IOCTL_INFO */ +#endif /* SET_PSA_CRC */ +} /* update_psa_checksum */ + +/*------------------------------------------------------------------*/ +/* + * Write 1 byte to the MMC. + */ +static inline void +mmc_out(u_long base, + u_short o, + u_char d) +{ + /* Wait for MMC to go idle */ + while(inb(HASR(base)) & HASR_MMI_BUSY) + ; + + outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base)); + outb(d, MMD(base)); +} + +/*------------------------------------------------------------------*/ +/* + * Routine to write bytes to the Modem Management Controller. + * We start by the end because it is the way it should be ! + */ +static inline void +mmc_write(u_long base, + u_char o, + u_char * b, + int n) +{ + o += n; + b += n; + + while(n-- > 0 ) + mmc_out(base, --o, *(--b)); +} /* mmc_write */ + +/*------------------------------------------------------------------*/ +/* + * Read 1 byte from the MMC. + * Optimised version for 1 byte, avoid using memory... + */ +static inline u_char +mmc_in(u_long base, + u_short o) +{ + while(inb(HASR(base)) & HASR_MMI_BUSY) + ; + outb(o << 1, MMR(base)); /* Set the read address */ + + outb(0, MMD(base)); /* Required dummy write */ + + while(inb(HASR(base)) & HASR_MMI_BUSY) + ; + return (u_char) (inb(MMD(base))); /* Now do the actual read */ +} + +/*------------------------------------------------------------------*/ +/* + * Routine to read bytes from the Modem Management Controller. + * The implementation is complicated by a lack of address lines, + * which prevents decoding of the low-order bit. + * (code has just been moved in the above function) + * We start by the end because it is the way it should be ! + */ +static inline void +mmc_read(u_long base, + u_char o, + u_char * b, + int n) +{ + o += n; + b += n; + + while(n-- > 0) + *(--b) = mmc_in(base, --o); +} /* mmc_read */ + +/*------------------------------------------------------------------*/ +/* + * Get the type of encryption available... + */ +static inline int +mmc_encr(u_long base) /* i/o port of the card */ +{ + int temp; + + temp = mmc_in(base, mmroff(0, mmr_des_avail)); + if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) + return 0; + else + return temp; +} + +/*------------------------------------------------------------------*/ +/* + * Wait for the frequency EEprom to complete a command... + * I hope this one will be optimally inlined... + */ +static inline void +fee_wait(u_long base, /* i/o port of the card */ + int delay, /* Base delay to wait for */ + int number) /* Number of time to wait */ +{ + int count = 0; /* Wait only a limited time */ + + while((count++ < number) && + (mmc_in(base, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY)) + udelay(delay); +} + +/*------------------------------------------------------------------*/ +/* + * Read bytes from the Frequency EEprom (frequency select cards). + */ +static void +fee_read(u_long base, /* i/o port of the card */ + u_short o, /* destination offset */ + u_short * b, /* data buffer */ + int n) /* number of registers */ +{ + b += n; /* Position at the end of the area */ + + /* Write the address */ + mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while(n-- > 0) + { + /* Write the read command */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ); + + /* Wait until EEprom is ready (should be quick !) */ + fee_wait(base, 10, 100); + + /* Read the value */ + *--b = ((mmc_in(base, mmroff(0, mmr_fee_data_h)) << 8) | + mmc_in(base, mmroff(0, mmr_fee_data_l))); + } +} + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ + +/*------------------------------------------------------------------*/ +/* + * Write bytes from the Frequency EEprom (frequency select cards). + * This is a bit complicated, because the frequency eeprom has to + * be unprotected and the write enabled. + * Jean II + */ +static void +fee_write(u_long base, /* i/o port of the card */ + u_short o, /* destination offset */ + u_short * b, /* data buffer */ + int n) /* number of registers */ +{ + b += n; /* Position at the end of the area */ + +#ifdef EEPROM_IS_PROTECTED /* disabled */ +#ifdef DOESNT_SEEM_TO_WORK /* disabled */ + /* Ask to read the protected register */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); + + fee_wait(base, 10, 100); + + /* Read the protected register */ + printk("Protected 2 : %02X-%02X\n", + mmc_in(base, mmroff(0, mmr_fee_data_h)), + mmc_in(base, mmroff(0, mmr_fee_data_l))); +#endif /* DOESNT_SEEM_TO_WORK */ + + /* Enable protected register */ + mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); + + fee_wait(base, 10, 100); + + /* Unprotect area */ + mmc_out(base, mmwoff(0, mmw_fee_addr), o + n); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); +#ifdef DOESNT_SEEM_TO_WORK /* disabled */ + /* Or use : */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); +#endif /* DOESNT_SEEM_TO_WORK */ + + fee_wait(base, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ + + /* Write enable */ + mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); + + fee_wait(base, 10, 100); + + /* Write the EEprom address */ + mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while(n-- > 0) + { + /* Write the value */ + mmc_out(base, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); + mmc_out(base, mmwoff(0, mmw_fee_data_l), *b & 0xFF); + + /* Write the write command */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE); + + /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */ + mdelay(10); + fee_wait(base, 10, 100); + } + + /* Write disable */ + mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); + + fee_wait(base, 10, 100); + +#ifdef EEPROM_IS_PROTECTED /* disabled */ + /* Reprotect EEprom */ + mmc_out(base, mmwoff(0, mmw_fee_addr), 0x00); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); + + fee_wait(base, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ +} +#endif /* WIRELESS_EXT */ + +/******************* WaveLAN Roaming routines... ********************/ + +#ifdef WAVELAN_ROAMING /* Conditional compile, see wavelan_cs.h */ + +unsigned char WAVELAN_BEACON_ADDRESS[]= {0x09,0x00,0x0e,0x20,0x03,0x00}; + +void wv_roam_init(struct net_device *dev) +{ + net_local *lp= (net_local *)dev->priv; + + /* Do not remove this unless you have a good reason */ + printk(KERN_NOTICE "%s: Warning, you have enabled roaming on" + " device %s !\n", dev->name, dev->name); + printk(KERN_NOTICE "Roaming is currently an experimental unsupported feature" + " of the Wavelan driver.\n"); + printk(KERN_NOTICE "It may work, but may also make the driver behave in" + " erratic ways or crash.\n"); + + lp->wavepoint_table.head=NULL; /* Initialise WavePoint table */ + lp->wavepoint_table.num_wavepoints=0; + lp->wavepoint_table.locked=0; + lp->curr_point=NULL; /* No default WavePoint */ + lp->cell_search=0; + + lp->cell_timer.data=(long)lp; /* Start cell expiry timer */ + lp->cell_timer.function=wl_cell_expiry; + lp->cell_timer.expires=jiffies+CELL_TIMEOUT; + add_timer(&lp->cell_timer); + + wv_nwid_filter(NWID_PROMISC,lp) ; /* Enter NWID promiscuous mode */ + /* to build up a good WavePoint */ + /* table... */ + printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name); +} + +void wv_roam_cleanup(struct net_device *dev) +{ + wavepoint_history *ptr,*old_ptr; + net_local *lp= (net_local *)dev->priv; + + printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name); + + /* Fixme : maybe we should check that the timer exist before deleting it */ + del_timer(&lp->cell_timer); /* Remove cell expiry timer */ + ptr=lp->wavepoint_table.head; /* Clear device's WavePoint table */ + while(ptr!=NULL) + { + old_ptr=ptr; + ptr=ptr->next; + wl_del_wavepoint(old_ptr,lp); + } +} + +/* Enable/Disable NWID promiscuous mode on a given device */ +void wv_nwid_filter(unsigned char mode, net_local *lp) +{ + mm_t m; + unsigned long flags; + +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name); +#endif + + /* Disable interrupts & save flags */ + wv_splhi(lp, &flags); + + m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00; + mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1); + + if(mode==NWID_PROMISC) + lp->cell_search=1; + else + lp->cell_search=0; + + /* ReEnable interrupts & restore flags */ + wv_splx(lp, &flags); +} + +/* Find a record in the WavePoint table matching a given NWID */ +wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp) +{ + wavepoint_history *ptr=lp->wavepoint_table.head; + + while(ptr!=NULL){ + if(ptr->nwid==nwid) + return ptr; + ptr=ptr->next; + } + return NULL; +} + +/* Create a new wavepoint table entry */ +wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp) +{ + wavepoint_history *new_wavepoint; + +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: New Wavepoint, NWID:%.4X\n",nwid); +#endif + + if(lp->wavepoint_table.num_wavepoints==MAX_WAVEPOINTS) + return NULL; + + new_wavepoint=(wavepoint_history *) kmalloc(sizeof(wavepoint_history),GFP_ATOMIC); + if(new_wavepoint==NULL) + return NULL; + + new_wavepoint->nwid=nwid; /* New WavePoints NWID */ + new_wavepoint->average_fast=0; /* Running Averages..*/ + new_wavepoint->average_slow=0; + new_wavepoint->qualptr=0; /* Start of ringbuffer */ + new_wavepoint->last_seq=seq-1; /* Last sequence no.seen */ + memset(new_wavepoint->sigqual,0,WAVEPOINT_HISTORY);/* Empty ringbuffer */ + + new_wavepoint->next=lp->wavepoint_table.head;/* Add to wavepoint table */ + new_wavepoint->prev=NULL; + + if(lp->wavepoint_table.head!=NULL) + lp->wavepoint_table.head->prev=new_wavepoint; + + lp->wavepoint_table.head=new_wavepoint; + + lp->wavepoint_table.num_wavepoints++; /* no. of visible wavepoints */ + + return new_wavepoint; +} + +/* Remove a wavepoint entry from WavePoint table */ +void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp) +{ + if(wavepoint==NULL) + return; + + if(lp->curr_point==wavepoint) + lp->curr_point=NULL; + + if(wavepoint->prev!=NULL) + wavepoint->prev->next=wavepoint->next; + + if(wavepoint->next!=NULL) + wavepoint->next->prev=wavepoint->prev; + + if(lp->wavepoint_table.head==wavepoint) + lp->wavepoint_table.head=wavepoint->next; + + lp->wavepoint_table.num_wavepoints--; + kfree(wavepoint); +} + +/* Timer callback function - checks WavePoint table for stale entries */ +void wl_cell_expiry(unsigned long data) +{ + net_local *lp=(net_local *)data; + wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point; + +#if WAVELAN_ROAMING_DEBUG > 1 + printk(KERN_DEBUG "WaveLAN: Wavepoint timeout, dev %s\n",lp->dev->name); +#endif + + if(lp->wavepoint_table.locked) + { +#if WAVELAN_ROAMING_DEBUG > 1 + printk(KERN_DEBUG "WaveLAN: Wavepoint table locked...\n"); +#endif + + lp->cell_timer.expires=jiffies+1; /* If table in use, come back later */ + add_timer(&lp->cell_timer); + return; + } + + while(wavepoint!=NULL) + { + if(wavepoint->last_seen < jiffies-CELL_TIMEOUT) + { +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid); +#endif + + old_point=wavepoint; + wavepoint=wavepoint->next; + wl_del_wavepoint(old_point,lp); + } + else + wavepoint=wavepoint->next; + } + lp->cell_timer.expires=jiffies+CELL_TIMEOUT; + add_timer(&lp->cell_timer); +} + +/* Update SNR history of a wavepoint */ +void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq) +{ + int i=0,num_missed=0,ptr=0; + int average_fast=0,average_slow=0; + + num_missed=(seq-wavepoint->last_seq)%WAVEPOINT_HISTORY;/* Have we missed + any beacons? */ + if(num_missed) + for(i=0;isigqual[wavepoint->qualptr++]=0; /* If so, enter them as 0's */ + wavepoint->qualptr %=WAVEPOINT_HISTORY; /* in the ringbuffer. */ + } + wavepoint->last_seen=jiffies; /* Add beacon to history */ + wavepoint->last_seq=seq; + wavepoint->sigqual[wavepoint->qualptr++]=sigqual; + wavepoint->qualptr %=WAVEPOINT_HISTORY; + ptr=(wavepoint->qualptr-WAVEPOINT_FAST_HISTORY+WAVEPOINT_HISTORY)%WAVEPOINT_HISTORY; + + for(i=0;isigqual[ptr++]; + ptr %=WAVEPOINT_HISTORY; + } + + average_slow=average_fast; + for(i=WAVEPOINT_FAST_HISTORY;isigqual[ptr++]; + ptr %=WAVEPOINT_HISTORY; + } + + wavepoint->average_fast=average_fast/WAVEPOINT_FAST_HISTORY; + wavepoint->average_slow=average_slow/WAVEPOINT_HISTORY; +} + +/* Perform a handover to a new WavePoint */ +void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) +{ + ioaddr_t base = lp->dev->base_addr; + mm_t m; + unsigned long flags; + + if(wavepoint==lp->curr_point) /* Sanity check... */ + { + wv_nwid_filter(!NWID_PROMISC,lp); + return; + } + +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: Doing handover to %.4X, dev %s\n",wavepoint->nwid,lp->dev->name); +#endif + + /* Disable interrupts & save flags */ + wv_splhi(lp, &flags); + + m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF; + m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8; + + mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); + + /* ReEnable interrupts & restore flags */ + wv_splx(lp, &flags); + + wv_nwid_filter(!NWID_PROMISC,lp); + lp->curr_point=wavepoint; +} + +/* Called when a WavePoint beacon is received */ +static inline void wl_roam_gather(device * dev, + u_char * hdr, /* Beacon header */ + u_char * stats) /* SNR, Signal quality + of packet */ +{ + wavepoint_beacon *beacon= (wavepoint_beacon *)hdr; /* Rcvd. Beacon */ + unsigned short nwid=ntohs(beacon->nwid); + unsigned short sigqual=stats[2] & MMR_SGNL_QUAL; /* SNR of beacon */ + wavepoint_history *wavepoint=NULL; /* WavePoint table entry */ + net_local *lp=(net_local *)dev->priv; /* Device info */ + +#if 0 + /* Some people don't need this, some other may need it */ + nwid=nwid^ntohs(beacon->domain_id); +#endif + +#if WAVELAN_ROAMING_DEBUG > 1 + printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name); + printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual); +#endif + + lp->wavepoint_table.locked=1; /* */ + + wavepoint=wl_roam_check(nwid,lp); /* Find WavePoint table entry */ + if(wavepoint==NULL) /* If no entry, Create a new one... */ + { + wavepoint=wl_new_wavepoint(nwid,beacon->seq,lp); + if(wavepoint==NULL) + goto out; + } + if(lp->curr_point==NULL) /* If this is the only WavePoint, */ + wv_roam_handover(wavepoint, lp); /* Jump on it! */ + + wl_update_history(wavepoint, sigqual, beacon->seq); /* Update SNR history + stats. */ + + if(lp->curr_point->average_slow < SEARCH_THRESH_LOW) /* If our current */ + if(!lp->cell_search) /* WavePoint is getting faint, */ + wv_nwid_filter(NWID_PROMISC,lp); /* start looking for a new one */ + + if(wavepoint->average_slow > + lp->curr_point->average_slow + WAVELAN_ROAMING_DELTA) + wv_roam_handover(wavepoint, lp); /* Handover to a better WavePoint */ + + if(lp->curr_point->average_slow > SEARCH_THRESH_HIGH) /* If our SNR is */ + if(lp->cell_search) /* getting better, drop out of cell search mode */ + wv_nwid_filter(!NWID_PROMISC,lp); + +out: + lp->wavepoint_table.locked=0; /* :-) */ +} + +/* Test this MAC frame a WavePoint beacon */ +static inline int WAVELAN_BEACON(unsigned char *data) +{ + wavepoint_beacon *beacon= (wavepoint_beacon *)data; + static wavepoint_beacon beacon_template={0xaa,0xaa,0x03,0x08,0x00,0x0e,0x20,0x03,0x00}; + + if(memcmp(beacon,&beacon_template,9)==0) + return 1; + else + return 0; +} +#endif /* WAVELAN_ROAMING */ + +/************************ I82593 SUBROUTINES *************************/ +/* + * Useful subroutines to manage the Ethernet controller + */ + +/*------------------------------------------------------------------*/ +/* + * Routine to synchronously send a command to the i82593 chip. + * Should be called with interrupts disabled. + * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(), + * wv_82593_config() & wv_diag()) + */ +static int +wv_82593_cmd(device * dev, + char * str, + int cmd, + int result) +{ + ioaddr_t base = dev->base_addr; + int status; + int wait_completed; + long spin; + + /* Spin until the chip finishes executing its current command (if any) */ + spin = 1000; + do + { + /* Time calibration of the loop */ + udelay(10); + + /* Read the interrupt register */ + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + } + while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); + + /* If the interrupt hasn't be posted */ + if(spin <= 0) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n", + str, status); +#endif + return(FALSE); + } + + /* Issue the command to the controller */ + outb(cmd, LCCR(base)); + + /* If we don't have to check the result of the command + * Note : this mean that the irq handler will deal with that */ + if(result == SR0_NO_RESULT) + return(TRUE); + + /* We are waiting for command completion */ + wait_completed = TRUE; + + /* Busy wait while the LAN controller executes the command. */ + spin = 1000; + do + { + /* Time calibration of the loop */ + udelay(10); + + /* Read the interrupt register */ + outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); + status = inb(LCSR(base)); + + /* Check if there was an interrupt posted */ + if((status & SR0_INTERRUPT)) + { + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); + + /* Check if interrupt is a command completion */ + if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) && + ((status & SR0_BOTH_RX_TX) != 0x0) && + !(status & SR0_RECEPTION)) + { + /* Signal command completion */ + wait_completed = FALSE; + } + else + { + /* Note : Rx interrupts will be handled later, because we can + * handle multiple Rx packets at once */ +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_INFO "wv_82593_cmd: not our interrupt\n"); +#endif + } + } + } + while(wait_completed && (spin-- > 0)); + + /* If the interrupt hasn't be posted */ + if(wait_completed) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n", + str, status); +#endif + return(FALSE); + } + + /* Check the return code returned by the card (see above) against + * the expected return code provided by the caller */ + if((status & SR0_EVENT_MASK) != result) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n", + str, status); +#endif + return(FALSE); + } + + return(TRUE); +} /* wv_82593_cmd */ + +/*------------------------------------------------------------------*/ +/* + * This routine does a 593 op-code number 7, and obtains the diagnose + * status for the WaveLAN. + */ +static inline int +wv_diag(device * dev) +{ + int ret = FALSE; + + if(wv_82593_cmd(dev, "wv_diag(): diagnose", + OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED)) + ret = TRUE; + +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n"); +#endif + return(ret); +} /* wv_diag */ + +/*------------------------------------------------------------------*/ +/* + * Routine to read len bytes from the i82593's ring buffer, starting at + * chip address addr. The results read from the chip are stored in buf. + * The return value is the address to use for next the call. + */ +static int +read_ringbuf(device * dev, + int addr, + char * buf, + int len) +{ + ioaddr_t base = dev->base_addr; + int ring_ptr = addr; + int chunk_len; + char * buf_ptr = buf; + + /* Get all the buffer */ + while(len > 0) + { + /* Position the Program I/O Register at the ring buffer pointer */ + outb(ring_ptr & 0xff, PIORL(base)); + outb(((ring_ptr >> 8) & PIORH_MASK), PIORH(base)); + + /* First, determine how much we can read without wrapping around the + ring buffer */ + if((addr + len) < (RX_BASE + RX_SIZE)) + chunk_len = len; + else + chunk_len = RX_BASE + RX_SIZE - addr; + insb(PIOP(base), buf_ptr, chunk_len); + buf_ptr += chunk_len; + len -= chunk_len; + ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE; + } + return(ring_ptr); +} /* read_ringbuf */ + +/*------------------------------------------------------------------*/ +/* + * Reconfigure the i82593, or at least ask for it... + * Because wv_82593_config use the transmission buffer, we must do it + * when we are sure that there is no transmission, so we do it now + * or in wavelan_packet_xmit() (I can't find any better place, + * wavelan_interrupt is not an option...), so you may experience + * some delay sometime... + */ +static inline void +wv_82593_reconfig(device * dev) +{ + net_local * lp = (net_local *)dev->priv; + dev_link_t * link = ((net_local *) dev->priv)->link; + unsigned long flags; + + /* Arm the flag, will be cleard in wv_82593_config() */ + lp->reconfig_82593 = TRUE; + + /* Check if we can do it now ! */ + if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev))) + { + wv_splhi(lp, &flags); /* Disable interrupts */ + wv_82593_config(dev); + wv_splx(lp, &flags); /* Re-enable interrupts */ + } + else + { +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG + "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n", + dev->name, dev->state, link->open); +#endif + } +} + +/********************* DEBUG & INFO SUBROUTINES *********************/ +/* + * This routines are used in the code to show debug informations. + * Most of the time, it dump the content of hardware structures... + */ + +#ifdef DEBUG_PSA_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted contents of the Parameter Storage Area. + */ +static void +wv_psa_show(psa_t * p) +{ + printk(KERN_DEBUG "##### wavelan psa contents: #####\n"); + printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", + p->psa_io_base_addr_1, + p->psa_io_base_addr_2, + p->psa_io_base_addr_3, + p->psa_io_base_addr_4); + printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", + p->psa_rem_boot_addr_1, + p->psa_rem_boot_addr_2, + p->psa_rem_boot_addr_3); + printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); + printk("psa_int_req_no: %d\n", p->psa_int_req_no); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + p->psa_unused0[0], + p->psa_unused0[1], + p->psa_unused0[2], + p->psa_unused0[3], + p->psa_unused0[4], + p->psa_unused0[5], + p->psa_unused0[6]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_univ_mac_addr[0], + p->psa_univ_mac_addr[1], + p->psa_univ_mac_addr[2], + p->psa_univ_mac_addr[3], + p->psa_univ_mac_addr[4], + p->psa_univ_mac_addr[5]); + printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_local_mac_addr[0], + p->psa_local_mac_addr[1], + p->psa_local_mac_addr[2], + p->psa_local_mac_addr[3], + p->psa_local_mac_addr[4], + p->psa_local_mac_addr[5]); + printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); + printk("psa_comp_number: %d, ", p->psa_comp_number); + printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); + printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", + p->psa_feature_select); + printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); + printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); + printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); + printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]); + printk("psa_nwid_select: %d\n", p->psa_nwid_select); + printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select); + printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_encryption_key[0], + p->psa_encryption_key[1], + p->psa_encryption_key[2], + p->psa_encryption_key[3], + p->psa_encryption_key[4], + p->psa_encryption_key[5], + p->psa_encryption_key[6], + p->psa_encryption_key[7]); + printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); + printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", + p->psa_call_code[0]); + printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + p->psa_call_code[0], + p->psa_call_code[1], + p->psa_call_code[2], + p->psa_call_code[3], + p->psa_call_code[4], + p->psa_call_code[5], + p->psa_call_code[6], + p->psa_call_code[7]); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n", + p->psa_reserved[0], + p->psa_reserved[1], + p->psa_reserved[2], + p->psa_reserved[3]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); + printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); + printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); +} /* wv_psa_show */ +#endif /* DEBUG_PSA_SHOW */ + +#ifdef DEBUG_MMC_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the Modem Management Controller. + * This function need to be completed... + */ +static void +wv_mmc_show(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *)dev->priv; + mmr_t m; + + /* Basic check */ + if(hasr_read(base) & HASR_NO_CLK) + { + printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n", + dev->name); + return; + } + + wv_splhi(lp, &flags); + + /* Read the mmc */ + mmc_out(base, mmwoff(0, mmw_freeze), 1); + mmc_read(base, 0, (u_char *)&m, sizeof(m)); + mmc_out(base, mmwoff(0, mmw_freeze), 0); + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ + /* Don't forget to update statistics */ + lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; +#endif /* WIRELESS_EXT */ + + wv_splx(lp, &flags); + + printk(KERN_DEBUG "##### wavelan modem status registers: #####\n"); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused0[0], + m.mmr_unused0[1], + m.mmr_unused0[2], + m.mmr_unused0[3], + m.mmr_unused0[4], + m.mmr_unused0[5], + m.mmr_unused0[6], + m.mmr_unused0[7]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n", + m.mmr_des_avail, m.mmr_des_status); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused1[0], + m.mmr_unused1[1], + m.mmr_unused1[2], + m.mmr_unused1[3], + m.mmr_unused1[4]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", + m.mmr_dce_status, + (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"", + (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? + "loop test indicated," : "", + (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "", + (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? + "jabber timer expired," : ""); + printk(KERN_DEBUG "Dsp ID: %02X\n", + m.mmr_dsp_id); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", + m.mmr_unused2[0], + m.mmr_unused2[1]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", + (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, + (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); + printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", + m.mmr_thr_pre_set & MMR_THR_PRE_SET, + (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below"); + printk(KERN_DEBUG "signal_lvl: %d [%s], ", + m.mmr_signal_lvl & MMR_SIGNAL_LVL, + (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg"); + printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL, + (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update"); + printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL, + (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0"); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); +#endif /* DEBUG_SHOW_UNUSED */ +} /* wv_mmc_show */ +#endif /* DEBUG_MMC_SHOW */ + +#ifdef DEBUG_I82593_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the i82593's receive unit. + */ +static void +wv_ru_show(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + + printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n"); + printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop); + /* + * Not implemented yet... + */ + printk("\n"); +} /* wv_ru_show */ +#endif /* DEBUG_I82593_SHOW */ + +#ifdef DEBUG_DEVICE_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the WaveLAN PCMCIA device driver. + */ +static void +wv_dev_show(device * dev) +{ + printk(KERN_DEBUG "dev:"); + printk(" state=%lX,", dev->state); + printk(" trans_start=%ld,", dev->trans_start); + printk(" flags=0x%x,", dev->flags); + printk("\n"); +} /* wv_dev_show */ + +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the WaveLAN PCMCIA device driver's + * private information. + */ +static void +wv_local_show(device * dev) +{ + net_local *lp; + + lp = (net_local *)dev->priv; + + printk(KERN_DEBUG "local:"); + /* + * Not implemented yet... + */ + printk("\n"); +} /* wv_local_show */ +#endif /* DEBUG_DEVICE_SHOW */ + +#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) +/*------------------------------------------------------------------*/ +/* + * Dump packet header (and content if necessary) on the screen + */ +static inline void +wv_packet_info(u_char * p, /* Packet to dump */ + int length, /* Length of the packet */ + char * msg1, /* Name of the device */ + char * msg2) /* Name of the function */ +{ + int i; + int maxi; + + printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", + msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); + printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", + msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]); + +#ifdef DEBUG_PACKET_DUMP + + printk(KERN_DEBUG "data=\""); + + if((maxi = length) > DEBUG_PACKET_DUMP) + maxi = DEBUG_PACKET_DUMP; + for(i = 14; i < maxi; i++) + if(p[i] >= ' ' && p[i] <= '~') + printk(" %c", p[i]); + else + printk("%02X", p[i]); + if(maxi < length) + printk(".."); + printk("\"\n"); + printk(KERN_DEBUG "\n"); +#endif /* DEBUG_PACKET_DUMP */ +} +#endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ + +/*------------------------------------------------------------------*/ +/* + * This is the information which is displayed by the driver at startup + * There is a lot of flag to configure it at your will... + */ +static inline void +wv_init_info(device * dev) +{ + ioaddr_t base = dev->base_addr; + psa_t psa; + int i; + + /* Read the parameter storage area */ + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + +#ifdef DEBUG_PSA_SHOW + wv_psa_show(&psa); +#endif +#ifdef DEBUG_MMC_SHOW + wv_mmc_show(dev); +#endif +#ifdef DEBUG_I82593_SHOW + wv_ru_show(dev); +#endif + +#ifdef DEBUG_BASIC_SHOW + /* Now, let's go for the basic stuff */ + printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr", + dev->name, base, dev->irq); + for(i = 0; i < WAVELAN_ADDR_SIZE; i++) + printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); + + /* Print current network id */ + if(psa.psa_nwid_select) + printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]); + else + printk(", nwid off"); + + /* If 2.00 card */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + unsigned short freq; + + /* Ask the EEprom to read the frequency from the first area */ + fee_read(base, 0x00 /* 1st area - frequency... */, + &freq, 1); + + /* Print frequency */ + printk(", 2.00, %ld", (freq >> 6) + 2400L); + + /* Hack !!! */ + if(freq & 0x20) + printk(".5"); + } + else + { + printk(", PCMCIA, "); + switch (psa.psa_subband) + { + case PSA_SUBBAND_915: + printk("915"); + break; + case PSA_SUBBAND_2425: + printk("2425"); + break; + case PSA_SUBBAND_2460: + printk("2460"); + break; + case PSA_SUBBAND_2484: + printk("2484"); + break; + case PSA_SUBBAND_2430_5: + printk("2430.5"); + break; + default: + printk("???"); + } + } + + printk(" MHz\n"); +#endif /* DEBUG_BASIC_SHOW */ + +#ifdef DEBUG_VERSION_SHOW + /* Print version information */ + printk(KERN_NOTICE "%s", version); +#endif +} /* wv_init_info */ + +/********************* IOCTL, STATS & RECONFIG *********************/ +/* + * We found here routines that are called by Linux on differents + * occasions after the configuration and not for transmitting data + * These may be called when the user use ifconfig, /proc/net/dev + * or wireless extensions + */ + +/*------------------------------------------------------------------*/ +/* + * Get the current ethernet statistics. This may be called with the + * card open or closed. + * Used when the user read /proc/net/dev + */ +static en_stats * +wavelan_get_stats(device * dev) +{ +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); +#endif + + return(&((net_local *) dev->priv)->stats); +} + +/*------------------------------------------------------------------*/ +/* + * Set or clear the multicast filter for this adaptor. + * num_addrs == -1 Promiscuous mode, receive all packets + * num_addrs == 0 Normal mode, clear multicast list + * num_addrs > 0 Multicast mode, receive normal and MC packets, + * and do best-effort filtering. + */ + +static void +wavelan_set_multicast_list(device * dev) +{ + net_local * lp = (net_local *) dev->priv; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name); +#endif + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", + dev->name, dev->flags, dev->mc_count); +#endif + + if(dev->flags & IFF_PROMISC) + { + /* + * Enable promiscuous mode: receive all packets. + */ + if(!lp->promiscuous) + { + lp->promiscuous = 1; + lp->allmulticast = 0; + lp->mc_count = 0; + + wv_82593_reconfig(dev); + + /* Tell the kernel that we are doing a really bad job... */ + dev->flags |= IFF_PROMISC; + } + } + else + /* If all multicast addresses + * or too much multicast addresses for the hardware filter */ + if((dev->flags & IFF_ALLMULTI) || + (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES)) + { + /* + * Disable promiscuous mode, but active the all multicast mode + */ + if(!lp->allmulticast) + { + lp->promiscuous = 0; + lp->allmulticast = 1; + lp->mc_count = 0; + + wv_82593_reconfig(dev); + + /* Tell the kernel that we are doing a really bad job... */ + dev->flags |= IFF_ALLMULTI; + } + } + else + /* If there is some multicast addresses to send */ + if(dev->mc_list != (struct dev_mc_list *) NULL) + { + /* + * Disable promiscuous mode, but receive all packets + * in multicast list + */ +#ifdef MULTICAST_AVOID + if(lp->promiscuous || lp->allmulticast || + (dev->mc_count != lp->mc_count)) +#endif + { + lp->promiscuous = 0; + lp->allmulticast = 0; + lp->mc_count = dev->mc_count; + + wv_82593_reconfig(dev); + } + } + else + { + /* + * Switch to normal mode: disable promiscuous mode and + * clear the multicast list. + */ + if(lp->promiscuous || lp->mc_count == 0) + { + lp->promiscuous = 0; + lp->allmulticast = 0; + lp->mc_count = 0; + + wv_82593_reconfig(dev); + } + } +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * This function doesn't exist... + * (Note : it was a nice way to test the reconfigure stuff...) + */ +#ifdef SET_MAC_ADDRESS +static int +wavelan_set_mac_address(device * dev, + void * addr) +{ + struct sockaddr * mac = addr; + + /* Copy the address */ + memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); + + /* Reconfig the beast */ + wv_82593_reconfig(dev); + + return 0; +} +#endif /* SET_MAC_ADDRESS */ + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ + +/*------------------------------------------------------------------*/ +/* + * Frequency setting (for hardware able of it) + * It's a bit complicated and you don't really want to look into it... + * (called in wavelan_ioctl) + */ +static inline int +wv_set_frequency(u_long base, /* i/o port of the card */ + iw_freq * frequency) +{ + const int BAND_NUM = 10; /* Number of bands */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ +#ifdef DEBUG_IOCTL_INFO + int i; +#endif + + /* Setting by frequency */ + /* Theoritically, you may set any frequency between + * the two limits with a 0.5 MHz precision. In practice, + * I don't want you to have trouble with local + * regulations... */ + if((frequency->e == 1) && + (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8)) + { + freq = ((frequency->m / 10000) - 24000L) / 5; + } + + /* Setting by channel (same as wfreqsel) */ + /* Warning : each channel is 22MHz wide, so some of the channels + * will interfere... */ + if((frequency->e == 0) && + (frequency->m >= 0) && (frequency->m < BAND_NUM)) + { + /* Get frequency offset. */ + freq = channel_bands[frequency->m] >> 1; + } + + /* Verify if the frequency is allowed */ + if(freq != 0L) + { + u_short table[10]; /* Authorized frequency table */ + + /* Read the frequency table */ + fee_read(base, 0x71 /* frequency table */, + table, 10); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Frequency table :"); + for(i = 0; i < 10; i++) + { + printk(" %04X", + table[i]); + } + printk("\n"); +#endif + + /* Look in the table if the frequency is allowed */ + if(!(table[9 - ((freq - 24) / 16)] & + (1 << ((freq - 24) % 16)))) + return -EINVAL; /* not allowed */ + } + else + return -EINVAL; + + /* If we get a usable frequency */ + if(freq != 0L) + { + unsigned short area[16]; + unsigned short dac[2]; + unsigned short area_verify[16]; + unsigned short dac_verify[2]; + /* Corresponding gain (in the power adjust value table) + * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8 + * & WCIN062D.DOC, page 6.2.9 */ + unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; + int power_band = 0; /* Selected band */ + unsigned short power_adjust; /* Correct value */ + + /* Search for the gain */ + power_band = 0; + while((freq > power_limit[power_band]) && + (power_limit[++power_band] != 0)) + ; + + /* Read the first area */ + fee_read(base, 0x00, + area, 16); + + /* Read the DAC */ + fee_read(base, 0x60, + dac, 2); + + /* Read the new power adjust value */ + fee_read(base, 0x6B - (power_band >> 1), + &power_adjust, 1); + if(power_band & 0x1) + power_adjust >>= 8; + else + power_adjust &= 0xFF; + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); + for(i = 0; i < 16; i++) + { + printk(" %04X", + area[i]); + } + printk("\n"); + + printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", + dac[0], dac[1]); +#endif + + /* Frequency offset (for info only...) */ + area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); + + /* Receiver Principle main divider coefficient */ + area[3] = (freq >> 1) + 2400L - 352L; + area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + + /* Transmitter Main divider coefficient */ + area[13] = (freq >> 1) + 2400L; + area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + + /* Others part of the area are flags, bit streams or unused... */ + + /* Set the value in the DAC */ + dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); + dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); + + /* Write the first area */ + fee_write(base, 0x00, + area, 16); + + /* Write the DAC */ + fee_write(base, 0x60, + dac, 2); + + /* We now should verify here that the EEprom writting was ok */ + + /* ReRead the first area */ + fee_read(base, 0x00, + area_verify, 16); + + /* ReRead the DAC */ + fee_read(base, 0x60, + dac_verify, 2); + + /* Compare */ + if(memcmp(area, area_verify, 16 * 2) || + memcmp(dac, dac_verify, 2 * 2)) + { +#ifdef DEBUG_IOCTL_ERROR + printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n"); +#endif + return -EOPNOTSUPP; + } + + /* We must download the frequency parameters to the + * synthetisers (from the EEprom - area 1) + * Note : as the EEprom is auto decremented, we set the end + * if the area... */ + mmc_out(base, mmwoff(0, mmw_fee_addr), 0x0F); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + + /* Wait until the download is finished */ + fee_wait(base, 100, 100); + + /* We must now download the power adjust value (gain) to + * the synthetisers (from the EEprom - area 7 - DAC) */ + mmc_out(base, mmwoff(0, mmw_fee_addr), 0x61); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + + /* Wait until the download is finished */ + fee_wait(base, 100, 100); + +#ifdef DEBUG_IOCTL_INFO + /* Verification of what we have done... */ + + printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); + for(i = 0; i < 16; i++) + { + printk(" %04X", + area_verify[i]); + } + printk("\n"); + + printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", + dac_verify[0], dac_verify[1]); +#endif + + return 0; + } + else + return -EINVAL; /* Bah, never get there... */ +} + +/*------------------------------------------------------------------*/ +/* + * Give the list of available frequencies + */ +static inline int +wv_frequency_list(u_long base, /* i/o port of the card */ + iw_freq * list, /* List of frequency to fill */ + int max) /* Maximum number of frequencies */ +{ + u_short table[10]; /* Authorized frequency table */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ + int i; /* index in the table */ +#if WIRELESS_EXT > 7 + const int BAND_NUM = 10; /* Number of bands */ + int c = 0; /* Channel number */ +#endif /* WIRELESS_EXT */ + + /* Read the frequency table */ + fee_read(base, 0x71 /* frequency table */, + table, 10); + + /* Look all frequencies */ + i = 0; + for(freq = 0; freq < 150; freq++) + /* Look in the table if the frequency is allowed */ + if(table[9 - (freq / 16)] & (1 << (freq % 16))) + { +#if WIRELESS_EXT > 7 + /* Compute approximate channel number */ + while((((channel_bands[c] >> 1) - 24) < freq) && + (c < BAND_NUM)) + c++; + list[i].i = c; /* Set the list index */ +#endif /* WIRELESS_EXT */ + + /* put in the list */ + list[i].m = (((freq + 24) * 5) + 24000L) * 10000; + list[i++].e = 1; + + /* Check number */ + if(i >= max) + return(i); + } + + return(i); +} + +#ifdef WIRELESS_SPY +/*------------------------------------------------------------------*/ +/* + * Gather wireless spy statistics : for each packet, compare the source + * address with out list, and if match, get the stats... + * Sorry, but this function really need wireless extensions... + */ +static inline void +wl_spy_gather(device * dev, + u_char * mac, /* MAC address */ + u_char * stats) /* Statistics to gather */ +{ + net_local * lp = (net_local *) dev->priv; + int i; + + /* Look all addresses */ + for(i = 0; i < lp->spy_number; i++) + /* If match */ + if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) + { + /* Update statistics */ + lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL; + lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL; + lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL; + lp->spy_stat[i].updated = 0x7; + } +} +#endif /* WIRELESS_SPY */ + +#ifdef HISTOGRAM +/*------------------------------------------------------------------*/ +/* + * This function calculate an histogram on the signal level. + * As the noise is quite constant, it's like doing it on the SNR. + * We have defined a set of interval (lp->his_range), and each time + * the level goes in that interval, we increment the count (lp->his_sum). + * With this histogram you may detect if one wavelan is really weak, + * or you may also calculate the mean and standard deviation of the level... + */ +static inline void +wl_his_gather(device * dev, + u_char * stats) /* Statistics to gather */ +{ + net_local * lp = (net_local *) dev->priv; + u_char level = stats[0] & MMR_SIGNAL_LVL; + int i; + + /* Find the correct interval */ + i = 0; + while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++])) + ; + + /* Increment interval counter */ + (lp->his_sum[i])++; +} +#endif /* HISTOGRAM */ + +/*------------------------------------------------------------------*/ +/* + * Perform ioctl : config & info stuff + * This is here that are treated the wireless extensions (iwconfig) + */ +static int +wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ + struct ifreq * rq, /* Data passed */ + int cmd) /* Ioctl number */ +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *)dev->priv; /* lp is not unused */ + struct iwreq * wrq = (struct iwreq *) rq; + psa_t psa; + mm_t m; + unsigned long flags; + int ret = 0; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd); +#endif + + /* Disable interrupts & save flags */ + wv_splhi(lp, &flags); + + /* Look what is the request */ + switch(cmd) + { + /* --------------- WIRELESS EXTENSIONS --------------- */ + + case SIOCGIWNAME: + strcpy(wrq->u.name, "Wavelan"); + break; + + case SIOCSIWNWID: + /* Set NWID in wavelan */ +#if WIRELESS_EXT > 8 + if(!wrq->u.nwid.disabled) + { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8; + psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF; +#else /* WIRELESS_EXT > 8 */ + if(wrq->u.nwid.on) + { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; + psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF; +#endif /* WIRELESS_EXT > 8 */ + psa.psa_nwid_select = 0x01; + psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, + (unsigned char *)psa.psa_nwid, 3); + + /* Set NWID in mmc */ + m.w.mmw_netw_id_l = psa.psa_nwid[1]; + m.w.mmw_netw_id_h = psa.psa_nwid[0]; + mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, + (unsigned char *)&m.w.mmw_netw_id_l, 2); + mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00); + } + else + { + /* Disable nwid in the psa */ + psa.psa_nwid_select = 0x00; + psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa, + (unsigned char *)&psa.psa_nwid_select, 1); + + /* Disable nwid in the mmc (no filtering) */ + mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev); + break; + + case SIOCGIWNWID: + /* Read the NWID */ + psa_read(dev, (char *)psa.psa_nwid - (char *)&psa, + (unsigned char *)psa.psa_nwid, 3); +#if WIRELESS_EXT > 8 + wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrq->u.nwid.disabled = !(psa.psa_nwid_select); + wrq->u.nwid.fixed = 1; /* Superfluous */ +#else /* WIRELESS_EXT > 8 */ + wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrq->u.nwid.on = psa.psa_nwid_select; +#endif /* WIRELESS_EXT > 8 */ + break; + + case SIOCSIWFREQ: + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + ret = wv_set_frequency(base, &(wrq->u.freq)); + else + ret = -EOPNOTSUPP; + break; + + case SIOCGIWFREQ: + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) + * (does it work for everybody ??? - especially old cards...) */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + unsigned short freq; + + /* Ask the EEprom to read the frequency from the first area */ + fee_read(base, 0x00 /* 1st area - frequency... */, + &freq, 1); + wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; + wrq->u.freq.e = 1; + } + else + { + psa_read(dev, (char *)&psa.psa_subband - (char *)&psa, + (unsigned char *)&psa.psa_subband, 1); + + if(psa.psa_subband <= 4) + { + wrq->u.freq.m = fixed_bands[psa.psa_subband]; + wrq->u.freq.e = (psa.psa_subband != 0); + } + else + ret = -EOPNOTSUPP; + } + break; + + case SIOCSIWSENS: + /* Set the level threshold */ +#if WIRELESS_EXT > 7 + /* We should complain loudly if wrq->u.sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; +#else /* WIRELESS_EXT > 7 */ + psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; +#endif /* WIRELESS_EXT > 7 */ + psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, + (unsigned char *)&psa.psa_thr_pre_set, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); + mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); + break; + + case SIOCGIWSENS: + /* Read the level threshold */ + psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, + (unsigned char *)&psa.psa_thr_pre_set, 1); +#if WIRELESS_EXT > 7 + wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; + wrq->u.sens.fixed = 1; +#else /* WIRELESS_EXT > 7 */ + wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F; +#endif /* WIRELESS_EXT > 7 */ + break; + +#if WIRELESS_EXT > 8 + case SIOCSIWENCODE: + /* Set encryption key */ + if(!mmc_encr(base)) + { + ret = -EOPNOTSUPP; + break; + } + + /* Basic checking... */ + if(wrq->u.encoding.pointer != (caddr_t) 0) + { + /* Check the size of the key */ + if(wrq->u.encoding.length != 8) + { + ret = -EINVAL; + break; + } + + /* Copy the key in the driver */ + if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer, + wrq->u.encoding.length)) + { + ret = -EFAULT; + break; + } + + psa.psa_encryption_select = 1; + psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa, + (unsigned char *) &psa.psa_encryption_select, 8+1); + + mmc_out(base, mmwoff(0, mmw_encr_enable), + MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); + mmc_write(base, mmwoff(0, mmw_encr_key), + (unsigned char *) &psa.psa_encryption_key, 8); + } + + if(wrq->u.encoding.flags & IW_ENCODE_DISABLED) + { /* disable encryption */ + psa.psa_encryption_select = 0; + psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa, + (unsigned char *) &psa.psa_encryption_select, 1); + + mmc_out(base, mmwoff(0, mmw_encr_enable), 0); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev); + break; + + case SIOCGIWENCODE: + /* Read the encryption key */ + if(!mmc_encr(base)) + { + ret = -EOPNOTSUPP; + break; + } + + /* only super-user can see encryption key */ + if(!capable(CAP_NET_ADMIN)) + { + ret = -EPERM; + break; + } + + /* Basic checking... */ + if(wrq->u.encoding.pointer != (caddr_t) 0) + { + psa_read(dev, (char *) &psa.psa_encryption_select - (char *) &psa, + (unsigned char *) &psa.psa_encryption_select, 1+8); + + /* encryption is enabled ? */ + if(psa.psa_encryption_select) + wrq->u.encoding.flags = IW_ENCODE_ENABLED; + else + wrq->u.encoding.flags = IW_ENCODE_DISABLED; + wrq->u.encoding.flags |= mmc_encr(base); + + /* Copy the key to the user buffer */ + wrq->u.encoding.length = 8; + if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8)) + ret = -EFAULT; + } + break; +#endif /* WIRELESS_EXT > 8 */ + +#ifdef WAVELAN_ROAMING_EXT +#if WIRELESS_EXT > 5 + case SIOCSIWESSID: + /* Check if disable */ + if(wrq->u.data.flags == 0) + lp->filter_domains = 0; + else + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) + { + char essid[IW_ESSID_MAX_SIZE + 1]; + char * endp; + + /* Check the size of the string */ + if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1) + { + ret = -E2BIG; + break; + } + + /* Copy the string in the driver */ + if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.length)) + { + ret = -EFAULT; + break; + } + essid[IW_ESSID_MAX_SIZE] = '\0'; + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "SetEssid : ``%s''\n", essid); +#endif /* DEBUG_IOCTL_INFO */ + + /* Convert to a number (note : Wavelan specific) */ + lp->domain_id = simple_strtoul(essid, &endp, 16); + /* Has it worked ? */ + if(endp > essid) + lp->filter_domains = 1; + else + { + lp->filter_domains = 0; + ret = -EINVAL; + } + } + break; + + case SIOCGIWESSID: + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) + { + char essid[IW_ESSID_MAX_SIZE + 1]; + + /* Is the domain ID active ? */ + wrq->u.data.flags = lp->filter_domains; + + /* Copy Domain ID into a string (Wavelan specific) */ + /* Sound crazy, be we can't have a snprintf in the kernel !!! */ + sprintf(essid, "%lX", lp->domain_id); + essid[IW_ESSID_MAX_SIZE] = '\0'; + + /* Set the length */ + wrq->u.data.length = strlen(essid) + 1; + + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length)) + ret = -EFAULT; + } + break; + + case SIOCSIWAP: +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n", + wrq->u.ap_addr.sa_data[0], + wrq->u.ap_addr.sa_data[1], + wrq->u.ap_addr.sa_data[2], + wrq->u.ap_addr.sa_data[3], + wrq->u.ap_addr.sa_data[4], + wrq->u.ap_addr.sa_data[5]); +#endif /* DEBUG_IOCTL_INFO */ + + ret = -EOPNOTSUPP; /* Not supported yet */ + break; + + case SIOCGIWAP: + /* Should get the real McCoy instead of own Ethernet address */ + memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE); + wrq->u.ap_addr.sa_family = ARPHRD_ETHER; + + ret = -EOPNOTSUPP; /* Not supported yet */ + break; +#endif /* WIRELESS_EXT > 5 */ +#endif /* WAVELAN_ROAMING_EXT */ + +#if WIRELESS_EXT > 8 +#ifdef WAVELAN_ROAMING + case SIOCSIWMODE: + switch(wrq->u.mode) + { + case IW_MODE_ADHOC: + if(do_roaming) + { + wv_roam_cleanup(dev); + do_roaming = 0; + } + break; + case IW_MODE_INFRA: + if(!do_roaming) + { + wv_roam_init(dev); + do_roaming = 1; + } + break; + default: + ret = -EINVAL; + } + break; + + case SIOCGIWMODE: + if(do_roaming) + wrq->u.mode = IW_MODE_INFRA; + else + wrq->u.mode = IW_MODE_ADHOC; + break; +#endif /* WAVELAN_ROAMING */ +#endif /* WIRELESS_EXT > 8 */ + + case SIOCGIWRANGE: + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) + { + struct iw_range range; + + /* Set the length (very important for backward compatibility) */ + wrq->u.data.length = sizeof(struct iw_range); + + /* Set all the info we don't care or don't know about to zero */ + memset(&range, 0, sizeof(range)); + +#if WIRELESS_EXT > 10 + /* Set the Wireless Extension versions */ + range.we_version_compiled = WIRELESS_EXT; + range.we_version_source = 9; /* Nothing for us in v10 and v11 */ +#endif /* WIRELESS_EXT > 10 */ + + /* Set information in the range struct */ + range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ + range.min_nwid = 0x0000; + range.max_nwid = 0xFFFF; + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + range.num_channels = 10; + range.num_frequency = wv_frequency_list(base, range.freq, + IW_MAX_FREQUENCIES); + } + else + range.num_channels = range.num_frequency = 0; + + range.sensitivity = 0x3F; + range.max_qual.qual = MMR_SGNL_QUAL; + range.max_qual.level = MMR_SIGNAL_LVL; + range.max_qual.noise = MMR_SILENCE_LVL; +#if WIRELESS_EXT > 11 + range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ + /* Need to get better values for those two */ + range.avg_qual.level = 30; + range.avg_qual.noise = 8; +#endif /* WIRELESS_EXT > 11 */ + +#if WIRELESS_EXT > 7 + range.num_bitrates = 1; + range.bitrate[0] = 2000000; /* 2 Mb/s */ +#endif /* WIRELESS_EXT > 7 */ + +#if WIRELESS_EXT > 8 + /* Encryption supported ? */ + if(mmc_encr(base)) + { + range.encoding_size[0] = 8; /* DES = 64 bits key */ + range.num_encoding_sizes = 1; + range.max_encoding_tokens = 1; /* Only one key possible */ + } + else + { + range.num_encoding_sizes = 0; + range.max_encoding_tokens = 0; + } +#endif /* WIRELESS_EXT > 8 */ + + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, &range, + sizeof(struct iw_range))) + ret = -EFAULT; + } + break; + + case SIOCGIWPRIV: + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) + { + struct iw_priv_args priv[] = + { /* cmd, set_args, get_args, name */ + { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, + { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, + { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, + { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, + { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1 , 0, "setroam" }, + { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" }, + }; + + /* Set the number of ioctl available */ + wrq->u.data.length = 6; + + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, + sizeof(priv))) + ret = -EFAULT; + } + break; + +#ifdef WIRELESS_SPY + case SIOCSIWSPY: + /* Set the spy list */ + + /* Check the number of addresses */ + if(wrq->u.data.length > IW_MAX_SPY) + { + ret = -E2BIG; + break; + } + lp->spy_number = wrq->u.data.length; + + /* If there is some addresses to copy */ + if(lp->spy_number > 0) + { + struct sockaddr address[IW_MAX_SPY]; + int i; + + /* Copy addresses to the driver */ + if(copy_from_user(address, wrq->u.data.pointer, + sizeof(struct sockaddr) * lp->spy_number)) + { + ret = -EFAULT; + break; + } + + /* Copy addresses to the lp structure */ + for(i = 0; i < lp->spy_number; i++) + { + memcpy(lp->spy_address[i], address[i].sa_data, + WAVELAN_ADDR_SIZE); + } + + /* Reset structure... */ + memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n"); + for(i = 0; i < wrq->u.data.length; i++) + printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n", + lp->spy_address[i][0], + lp->spy_address[i][1], + lp->spy_address[i][2], + lp->spy_address[i][3], + lp->spy_address[i][4], + lp->spy_address[i][5]); +#endif /* DEBUG_IOCTL_INFO */ + } + + break; + + case SIOCGIWSPY: + /* Get the spy list and spy stats */ + + /* Set the number of addresses */ + wrq->u.data.length = lp->spy_number; + + /* If the user want to have the addresses back... */ + if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) + { + struct sockaddr address[IW_MAX_SPY]; + int i; + + /* Copy addresses from the lp structure */ + for(i = 0; i < lp->spy_number; i++) + { + memcpy(address[i].sa_data, lp->spy_address[i], + WAVELAN_ADDR_SIZE); + address[i].sa_family = ARPHRD_ETHER; + } + + /* Copy addresses to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, address, + sizeof(struct sockaddr) * lp->spy_number)) + { + ret = -EFAULT; + break; + } + + /* Copy stats to the user buffer (just after) */ + if(copy_to_user(wrq->u.data.pointer + + (sizeof(struct sockaddr) * lp->spy_number), + lp->spy_stat, sizeof(iw_qual) * lp->spy_number)) + { + ret = -EFAULT; + break; + } + + /* Reset updated flags */ + for(i = 0; i < lp->spy_number; i++) + lp->spy_stat[i].updated = 0x0; + } /* if(pointer != NULL) */ + + break; +#endif /* WIRELESS_SPY */ + + /* ------------------ PRIVATE IOCTL ------------------ */ + + case SIOCSIPQTHR: + if(!capable(CAP_NET_ADMIN)) + { + ret = -EPERM; + break; + } + psa.psa_quality_thr = *(wrq->u.name) & 0x0F; + psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa, + (unsigned char *)&psa.psa_quality_thr, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); + mmc_out(base, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr); + break; + + case SIOCGIPQTHR: + psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa, + (unsigned char *)&psa.psa_quality_thr, 1); + *(wrq->u.name) = psa.psa_quality_thr & 0x0F; + break; + +#ifdef WAVELAN_ROAMING + case SIOCSIPROAM: + /* Note : should check if user == root */ + if(do_roaming && (*wrq->u.name)==0) + wv_roam_cleanup(dev); + else if(do_roaming==0 && (*wrq->u.name)!=0) + wv_roam_init(dev); + + do_roaming = (*wrq->u.name); + + break; + + case SIOCGIPROAM: + *(wrq->u.name) = do_roaming; + break; +#endif /* WAVELAN_ROAMING */ + +#ifdef HISTOGRAM + case SIOCSIPHISTO: + /* Verif if the user is root */ + if(!capable(CAP_NET_ADMIN)) + { + ret = -EPERM; + } + + /* Check the number of intervals */ + if(wrq->u.data.length > 16) + { + ret = -E2BIG; + break; + } + lp->his_number = wrq->u.data.length; + + /* If there is some addresses to copy */ + if(lp->his_number > 0) + { + /* Copy interval ranges to the driver */ + if(copy_from_user(lp->his_range, wrq->u.data.pointer, + sizeof(char) * lp->his_number)) + { + ret = -EFAULT; + break; + } + + /* Reset structure... */ + memset(lp->his_sum, 0x00, sizeof(long) * 16); + } + break; + + case SIOCGIPHISTO: + /* Set the number of intervals */ + wrq->u.data.length = lp->his_number; + + /* Give back the distribution statistics */ + if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) + { + /* Copy data to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, lp->his_sum, + sizeof(long) * lp->his_number)) + ret = -EFAULT; + + } /* if(pointer != NULL) */ + break; +#endif /* HISTOGRAM */ + + /* ------------------- OTHER IOCTL ------------------- */ + + default: + ret = -EOPNOTSUPP; + } + + /* ReEnable interrupts & restore flags */ + wv_splx(lp, &flags); + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); +#endif + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Get wireless statistics + * Called by /proc/net/wireless... + */ +static iw_stats * +wavelan_get_wireless_stats(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + mmr_t m; + iw_stats * wstats; + unsigned long flags; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); +#endif + + /* Disable interrupts & save flags */ + wv_splhi(lp, &flags); + + wstats = &lp->wstats; + + /* Get data from the mmc */ + mmc_out(base, mmwoff(0, mmw_freeze), 1); + + mmc_read(base, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); + mmc_read(base, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2); + mmc_read(base, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4); + + mmc_out(base, mmwoff(0, mmw_freeze), 0); + + /* Copy data to wireless stuff */ + wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; + wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; + wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; + wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; + wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) | + ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) | + ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); + wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; + wstats->discard.code = 0L; + wstats->discard.misc = 0L; + + /* ReEnable interrupts & restore flags */ + wv_splx(lp, &flags); + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); +#endif + return &lp->wstats; +} +#endif /* WIRELESS_EXT */ + +/************************* PACKET RECEPTION *************************/ +/* + * This part deal with receiving the packets. + * The interrupt handler get an interrupt when a packet has been + * successfully received and called this part... + */ + +/*------------------------------------------------------------------*/ +/* + * Calculate the starting address of the frame pointed to by the receive + * frame pointer and verify that the frame seem correct + * (called by wv_packet_rcv()) + */ +static inline int +wv_start_of_frame(device * dev, + int rfp, /* end of frame */ + int wrap) /* start of buffer */ +{ + ioaddr_t base = dev->base_addr; + int rp; + int len; + + rp = (rfp - 5 + RX_SIZE) % RX_SIZE; + outb(rp & 0xff, PIORL(base)); + outb(((rp >> 8) & PIORH_MASK), PIORH(base)); + len = inb(PIOP(base)); + len |= inb(PIOP(base)) << 8; + + /* Sanity checks on size */ + /* Frame too big */ + if(len > MAXDATAZ + 100) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_start_of_frame: Received frame too large, rfp %d len 0x%x\n", + dev->name, rfp, len); +#endif + return(-1); + } + + /* Frame too short */ + if(len < 7) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_start_of_frame: Received null frame, rfp %d len 0x%x\n", + dev->name, rfp, len); +#endif + return(-1); + } + + /* Wrap around buffer */ + if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE)) /* magic formula ! */ + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n", + dev->name, wrap, rfp, len); +#endif + return(-1); + } + + return((rp - len + RX_SIZE) % RX_SIZE); +} /* wv_start_of_frame */ + +/*------------------------------------------------------------------*/ +/* + * This routine does the actual copy of data (including the ethernet + * header structure) from the WaveLAN card to an sk_buff chain that + * will be passed up to the network interface layer. NOTE: We + * currently don't handle trailer protocols (neither does the rest of + * the network interface), so if that is needed, it will (at least in + * part) be added here. The contents of the receive ring buffer are + * copied to a message chain that is then passed to the kernel. + * + * Note: if any errors occur, the packet is "dropped on the floor" + * (called by wv_packet_rcv()) + */ +static inline void +wv_packet_read(device * dev, + int fd_p, + int sksize) +{ + net_local * lp = (net_local *) dev->priv; + struct sk_buff * skb; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", + dev->name, fd_p, sksize); +#endif + + /* Allocate some buffer for the new packet */ + if((skb = dev_alloc_skb(sksize+2)) == (struct sk_buff *) NULL) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC)\n", + dev->name, sksize); +#endif + lp->stats.rx_dropped++; + /* + * Not only do we want to return here, but we also need to drop the + * packet on the floor to clear the interrupt. + */ + return; + } + + skb->dev = dev; + + skb_reserve(skb, 2); + fd_p = read_ringbuf(dev, fd_p, (char *) skb_put(skb, sksize), sksize); + skb->protocol = eth_type_trans(skb, dev); + +#ifdef DEBUG_RX_INFO + wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read"); +#endif /* DEBUG_RX_INFO */ + + /* Statistics gathering & stuff associated. + * It seem a bit messy with all the define, but it's really simple... */ + if( +#ifdef WIRELESS_SPY + (lp->spy_number > 0) || +#endif /* WIRELESS_SPY */ +#ifdef HISTOGRAM + (lp->his_number > 0) || +#endif /* HISTOGRAM */ +#ifdef WAVELAN_ROAMING + (do_roaming) || +#endif /* WAVELAN_ROAMING */ + 0) + { + u_char stats[3]; /* Signal level, Noise level, Signal quality */ + + /* read signal level, silence level and signal quality bytes */ + fd_p = read_ringbuf(dev, (fd_p + 4) % RX_SIZE + RX_BASE, + stats, 3); +#ifdef DEBUG_RX_INFO + printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", + dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F); +#endif + +#ifdef WAVELAN_ROAMING + if(do_roaming) + if(WAVELAN_BEACON(skb->data)) + wl_roam_gather(dev, skb->data, stats); +#endif /* WAVELAN_ROAMING */ + +#ifdef WIRELESS_SPY + wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats); +#endif /* WIRELESS_SPY */ +#ifdef HISTOGRAM + wl_his_gather(dev, stats); +#endif /* HISTOGRAM */ + } + + /* + * Hand the packet to the Network Module + */ + netif_rx(skb); + + /* Keep stats up to date */ + dev->last_rx = jiffies; + lp->stats.rx_packets++; + lp->stats.rx_bytes += sksize; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); +#endif + return; +} + +/*------------------------------------------------------------------*/ +/* + * This routine is called by the interrupt handler to initiate a + * packet transfer from the card to the network interface layer above + * this driver. This routine checks if a buffer has been successfully + * received by the WaveLAN card. If so, the routine wv_packet_read is + * called to do the actual transfer of the card's data including the + * ethernet header into a packet consisting of an sk_buff chain. + * (called by wavelan_interrupt()) + * Note : the spinlock is already grabbed for us and irq are disabled. + */ +static inline void +wv_packet_rcv(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + int newrfp; + int rp; + int len; + int f_start; + int status; + int i593_rfp; + int stat_ptr; + u_char c[4]; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_rcv()\n", dev->name); +#endif + + /* Get the new receive frame pointer from the i82593 chip */ + outb(CR0_STATUS_2 | OP0_NOP, LCCR(base)); + i593_rfp = inb(LCSR(base)); + i593_rfp |= inb(LCSR(base)) << 8; + i593_rfp %= RX_SIZE; + + /* Get the new receive frame pointer from the WaveLAN card. + * It is 3 bytes more than the increment of the i82593 receive + * frame pointer, for each packet. This is because it includes the + * 3 roaming bytes added by the mmc. + */ + newrfp = inb(RPLL(base)); + newrfp |= inb(RPLH(base)) << 8; + newrfp %= RX_SIZE; + +#ifdef DEBUG_RX_INFO + printk(KERN_DEBUG "%s: wv_packet_rcv(): i593_rfp %d stop %d newrfp %d lp->rfp %d\n", + dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); +#endif + +#ifdef DEBUG_RX_ERROR + /* If no new frame pointer... */ + if(lp->overrunning || newrfp == lp->rfp) + printk(KERN_INFO "%s: wv_packet_rcv(): no new frame: i593_rfp %d stop %d newrfp %d lp->rfp %d\n", + dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); +#endif + + /* Read all frames (packets) received */ + while(newrfp != lp->rfp) + { + /* A frame is composed of the packet, followed by a status word, + * the length of the frame (word) and the mmc info (SNR & qual). + * It's because the length is at the end that we can only scan + * frames backward. */ + + /* Find the first frame by skipping backwards over the frames */ + rp = newrfp; /* End of last frame */ + while(((f_start = wv_start_of_frame(dev, rp, newrfp)) != lp->rfp) && + (f_start != -1)) + rp = f_start; + + /* If we had a problem */ + if(f_start == -1) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "wavelan_cs: cannot find start of frame "); + printk(" i593_rfp %d stop %d newrfp %d lp->rfp %d\n", + i593_rfp, lp->stop, newrfp, lp->rfp); +#endif + lp->rfp = rp; /* Get to the last usable frame */ + continue; + } + + /* f_start point to the beggining of the first frame received + * and rp to the beggining of the next one */ + + /* Read status & length of the frame */ + stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE; + stat_ptr = read_ringbuf(dev, stat_ptr, c, 4); + status = c[0] | (c[1] << 8); + len = c[2] | (c[3] << 8); + + /* Check status */ + if((status & RX_RCV_OK) != RX_RCV_OK) + { + lp->stats.rx_errors++; + if(status & RX_NO_SFD) + lp->stats.rx_frame_errors++; + if(status & RX_CRC_ERR) + lp->stats.rx_crc_errors++; + if(status & RX_OVRRUN) + lp->stats.rx_over_errors++; + +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG "%s: wv_packet_rcv(): packet not received ok, status = 0x%x\n", + dev->name, status); +#endif + } + else + /* Read the packet and transmit to Linux */ + wv_packet_read(dev, f_start, len - 2); + + /* One frame has been processed, skip it */ + lp->rfp = rp; + } + + /* + * Update the frame stop register, but set it to less than + * the full 8K to allow space for 3 bytes of signal strength + * per packet. + */ + lp->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; + outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); + outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); + outb(OP1_SWIT_TO_PORT_0, LCCR(base)); + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_rcv()\n", dev->name); +#endif +} + +/*********************** PACKET TRANSMISSION ***********************/ +/* + * This part deal with sending packet through the wavelan + * We copy the packet to the send buffer and then issue the send + * command to the i82593. The result of this operation will be + * checked in wavelan_interrupt() + */ + +/*------------------------------------------------------------------*/ +/* + * This routine fills in the appropriate registers and memory + * locations on the WaveLAN card and starts the card off on + * the transmit. + * (called in wavelan_packet_xmit()) + */ +static inline void +wv_packet_write(device * dev, + void * buf, + short length) +{ + net_local * lp = (net_local *) dev->priv; + ioaddr_t base = dev->base_addr; + unsigned long flags; + int clen = length; + register u_short xmtdata_base = TX_BASE; + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); +#endif + + wv_splhi(lp, &flags); + + /* Check if we need some padding */ + if(clen < ETH_ZLEN) + clen = ETH_ZLEN; + + /* Write the length of data buffer followed by the buffer */ + outb(xmtdata_base & 0xff, PIORL(base)); + outb(((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(clen & 0xff, PIOP(base)); /* lsb */ + outb(clen >> 8, PIOP(base)); /* msb */ + + /* Send the data */ + outsb(PIOP(base), buf, clen); + + /* Indicate end of transmit chain */ + outb(OP0_NOP, PIOP(base)); + /* josullvn@cs.cmu.edu: need to send a second NOP for alignment... */ + outb(OP0_NOP, PIOP(base)); + + /* Reset the transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + /* Send the transmit command */ + wv_82593_cmd(dev, "wv_packet_write(): transmit", + OP0_TRANSMIT, SR0_NO_RESULT); + + /* Keep stats up to date */ + lp->stats.tx_bytes += length; + + wv_splx(lp, &flags); + +#ifdef DEBUG_TX_INFO + wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); +#endif /* DEBUG_TX_INFO */ + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * This routine is called when we want to send a packet (NET3 callback) + * In this routine, we check if the harware is ready to accept + * the packet. We also prevent reentrance. Then, we call the function + * to send the packet... + */ +static int +wavelan_packet_xmit(struct sk_buff * skb, + device * dev) +{ + net_local * lp = (net_local *)dev->priv; + unsigned long flags; + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, + (unsigned) skb); +#endif + + /* + * Block a timer-based transmit from overlapping a previous transmit. + * In other words, prevent reentering this routine. + */ + netif_stop_queue(dev); + + /* If somebody has asked to reconfigure the controller, + * we can do it now */ + if(lp->reconfig_82593) + { + wv_splhi(lp, &flags); /* Disable interrupts */ + wv_82593_config(dev); + wv_splx(lp, &flags); /* Re-enable interrupts */ + /* Note : the configure procedure was totally synchronous, + * so the Tx buffer is now free */ + } + +#ifdef DEBUG_TX_ERROR + if (skb->next) + printk(KERN_INFO "skb has next\n"); +#endif + + wv_packet_write(dev, skb->data, skb->len); + + dev_kfree_skb(skb); + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); +#endif + return(0); +} + +/********************** HARDWARE CONFIGURATION **********************/ +/* + * This part do the real job of starting and configuring the hardware. + */ + +/*------------------------------------------------------------------*/ +/* + * Routine to initialize the Modem Management Controller. + * (called by wv_hw_config()) + */ +static inline int +wv_mmc_init(device * dev) +{ + ioaddr_t base = dev->base_addr; + psa_t psa; + mmw_t m; + int configured; + int i; /* Loop counter */ + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); +#endif + + /* Read the parameter storage area */ + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + + /* + * Check the first three octets of the MAC addr for the manufacturer's code. + * Note: If you get the error message below, you've got a + * non-NCR/AT&T/Lucent PCMCIA cards, see wavelan_cs.h for detail on + * how to configure your card... + */ + for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++) + if((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) && + (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) && + (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2])) + break; + + /* If we have not found it... */ + if(i == (sizeof(MAC_ADDRESSES) / sizeof(char) / 3)) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wv_mmc_init(): Invalid MAC address: %02X:%02X:%02X:...\n", + dev->name, psa.psa_univ_mac_addr[0], + psa.psa_univ_mac_addr[1], psa.psa_univ_mac_addr[2]); +#endif + return FALSE; + } + + /* Get the MAC address */ + memcpy(&dev->dev_addr[0], &psa.psa_univ_mac_addr[0], WAVELAN_ADDR_SIZE); + +#ifdef USE_PSA_CONFIG + configured = psa.psa_conf_status & 1; +#else + configured = 0; +#endif + + /* Is the PSA is not configured */ + if(!configured) + { + /* User will be able to configure NWID after (with iwconfig) */ + psa.psa_nwid[0] = 0; + psa.psa_nwid[1] = 0; + + /* As NWID is not set : no NWID checking */ + psa.psa_nwid_select = 0; + + /* Disable encryption */ + psa.psa_encryption_select = 0; + + /* Set to standard values + * 0x04 for AT, + * 0x01 for MCA, + * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) + */ + if (psa.psa_comp_number & 1) + psa.psa_thr_pre_set = 0x01; + else + psa.psa_thr_pre_set = 0x04; + psa.psa_quality_thr = 0x03; + + /* It is configured */ + psa.psa_conf_status |= 1; + +#ifdef USE_PSA_CONFIG + /* Write the psa */ + psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, + (unsigned char *)psa.psa_nwid, 4); + psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, + (unsigned char *)&psa.psa_thr_pre_set, 1); + psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa, + (unsigned char *)&psa.psa_quality_thr, 1); + psa_write(dev, (char *)&psa.psa_conf_status - (char *)&psa, + (unsigned char *)&psa.psa_conf_status, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); +#endif /* USE_PSA_CONFIG */ + } + + /* Zero the mmc structure */ + memset(&m, 0x00, sizeof(m)); + + /* Copy PSA info to the mmc */ + m.mmw_netw_id_l = psa.psa_nwid[1]; + m.mmw_netw_id_h = psa.psa_nwid[0]; + + if(psa.psa_nwid_select & 1) + m.mmw_loopt_sel = 0x00; + else + m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; + + memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, + sizeof(m.mmw_encr_key)); + + if(psa.psa_encryption_select) + m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; + else + m.mmw_encr_enable = 0; + + m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; + m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; + + /* + * Set default modem control parameters. + * See NCR document 407-0024326 Rev. A. + */ + m.mmw_jabber_enable = 0x01; + m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; + m.mmw_ifs = 0x20; + m.mmw_mod_delay = 0x04; + m.mmw_jam_time = 0x38; + + m.mmw_des_io_invert = 0; + m.mmw_freeze = 0; + m.mmw_decay_prm = 0; + m.mmw_decay_updat_prm = 0; + + /* Write all info to mmc */ + mmc_write(base, 0, (u_char *)&m, sizeof(m)); + + /* The following code start the modem of the 2.00 frequency + * selectable cards at power on. It's not strictly needed for the + * following boots... + * The original patch was by Joe Finney for the PCMCIA driver, but + * I've cleaned it a bit and add documentation. + * Thanks to Loeke Brederveld from Lucent for the info. + */ + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) + * (does it work for everybody ??? - especially old cards...) */ + /* Note : WFREQSEL verify that it is able to read from EEprom + * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID + * is 0xA (Xilinx version) or 0xB (Ariadne version). + * My test is more crude but do work... */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + /* We must download the frequency parameters to the + * synthetisers (from the EEprom - area 1) + * Note : as the EEprom is auto decremented, we set the end + * if the area... */ + m.mmw_fee_addr = 0x0F; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, + (unsigned char *)&m.mmw_fee_ctrl, 2); + + /* Wait until the download is finished */ + fee_wait(base, 100, 100); + +#ifdef DEBUG_CONFIG_INFO + /* The frequency was in the last word downloaded... */ + mmc_read(base, (char *)&m.mmw_fee_data_l - (char *)&m, + (unsigned char *)&m.mmw_fee_data_l, 2); + + /* Print some info for the user */ + printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n", + dev->name, + ((m.mmw_fee_data_h << 4) | + (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L); +#endif + + /* We must now download the power adjust value (gain) to + * the synthetisers (from the EEprom - area 7 - DAC) */ + m.mmw_fee_addr = 0x61; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, + (unsigned char *)&m.mmw_fee_ctrl, 2); + + /* Wait until the download is finished */ + } /* if 2.00 card */ + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * Routine to gracefully turn off reception, and wait for any commands + * to complete. + * (called in wv_ru_start() and wavelan_close() and wavelan_event()) + */ +static int +wv_ru_stop(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + unsigned long flags; + int status; + int spin; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name); +#endif + + wv_splhi(lp, &flags); + + /* First, send the LAN controller a stop receive command */ + wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv", + OP0_STOP_RCV, SR0_NO_RESULT); + + /* Then, spin until the receive unit goes idle */ + spin = 300; + do + { + udelay(10); + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + } + while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0)); + + /* Now, spin until the chip finishes executing its current command */ + do + { + udelay(10); + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + } + while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); + + wv_splx(lp, &flags); + + /* If there was a problem */ + if(spin <= 0) + { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n", + dev->name); +#endif + return FALSE; + } + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_ru_stop()\n", dev->name); +#endif + return TRUE; +} /* wv_ru_stop */ + +/*------------------------------------------------------------------*/ +/* + * This routine starts the receive unit running. First, it checks if + * the card is actually ready. Then the card is instructed to receive + * packets again. + * (called in wv_hw_reset() & wavelan_open()) + */ +static int +wv_ru_start(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + unsigned long flags; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); +#endif + + /* + * We need to start from a quiescent state. To do so, we could check + * if the card is already running, but instead we just try to shut + * it down. First, we disable reception (in case it was already enabled). + */ + if(!wv_ru_stop(dev)) + return FALSE; + + wv_splhi(lp, &flags); + + /* Now we know that no command is being executed. */ + + /* Set the receive frame pointer and stop pointer */ + lp->rfp = 0; + outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); + + /* Reset ring management. This sets the receive frame pointer to 1 */ + outb(OP1_RESET_RING_MNGMT, LCCR(base)); + +#if 0 + /* XXX the i82593 manual page 6-4 seems to indicate that the stop register + should be set as below */ + /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/ +#elif 0 + /* but I set it 0 instead */ + lp->stop = 0; +#else + /* but I set it to 3 bytes per packet less than 8K */ + lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; +#endif + outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); + outb(OP1_INT_ENABLE, LCCR(base)); + outb(OP1_SWIT_TO_PORT_0, LCCR(base)); + + /* Reset receive DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write_slow(base, HACR_DEFAULT); + + /* Receive DMA on channel 1 */ + wv_82593_cmd(dev, "wv_ru_start(): rcv-enable", + CR0_CHNL | OP0_RCV_ENABLE, SR0_NO_RESULT); + +#ifdef DEBUG_I82593_SHOW + { + int status; + int opri; + int spin = 10000; + + /* spin until the chip starts receiving */ + do + { + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + if(spin-- <= 0) + break; + } + while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) && + ((status & SR3_RCV_STATE_MASK) != SR3_RCV_READY)); + printk(KERN_DEBUG "rcv status is 0x%x [i:%d]\n", + (status & SR3_RCV_STATE_MASK), i); + } +#endif + + wv_splx(lp, &flags); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * This routine does a standard config of the WaveLAN controller (i82593). + * In the ISA driver, this is integrated in wavelan_hardware_reset() + * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit()) + */ +static int +wv_82593_config(device * dev) +{ + ioaddr_t base = dev->base_addr; + net_local * lp = (net_local *) dev->priv; + struct i82593_conf_block cfblk; + int ret = TRUE; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name); +#endif + + /* Create & fill i82593 config block + * + * Now conform to Wavelan document WCIN085B + */ + memset(&cfblk, 0x00, sizeof(struct i82593_conf_block)); + cfblk.d6mod = FALSE; /* Run in i82593 advanced mode */ + cfblk.fifo_limit = 5; /* = 56 B rx and 40 B tx fifo thresholds */ + cfblk.forgnesi = FALSE; /* 0=82C501, 1=AMD7992B compatibility */ + cfblk.fifo_32 = 1; + cfblk.throttle_enb = FALSE; + cfblk.contin = TRUE; /* enable continuous mode */ + cfblk.cntrxint = FALSE; /* enable continuous mode receive interrupts */ + cfblk.addr_len = WAVELAN_ADDR_SIZE; + cfblk.acloc = TRUE; /* Disable source addr insertion by i82593 */ + cfblk.preamb_len = 0; /* 2 bytes preamble (SFD) */ + cfblk.loopback = FALSE; + cfblk.lin_prio = 0; /* conform to 802.3 backoff algoritm */ + cfblk.exp_prio = 5; /* conform to 802.3 backoff algoritm */ + cfblk.bof_met = 1; /* conform to 802.3 backoff algoritm */ + cfblk.ifrm_spc = 0x20; /* 32 bit times interframe spacing */ + cfblk.slottim_low = 0x20; /* 32 bit times slot time */ + cfblk.slottim_hi = 0x0; + cfblk.max_retr = 15; + cfblk.prmisc = ((lp->promiscuous) ? TRUE: FALSE); /* Promiscuous mode */ + cfblk.bc_dis = FALSE; /* Enable broadcast reception */ + cfblk.crs_1 = TRUE; /* Transmit without carrier sense */ + cfblk.nocrc_ins = FALSE; /* i82593 generates CRC */ + cfblk.crc_1632 = FALSE; /* 32-bit Autodin-II CRC */ + cfblk.crs_cdt = FALSE; /* CD not to be interpreted as CS */ + cfblk.cs_filter = 0; /* CS is recognized immediately */ + cfblk.crs_src = FALSE; /* External carrier sense */ + cfblk.cd_filter = 0; /* CD is recognized immediately */ + cfblk.min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length 64 bytes */ + cfblk.lng_typ = FALSE; /* Length field > 1500 = type field */ + cfblk.lng_fld = TRUE; /* Disable 802.3 length field check */ + cfblk.rxcrc_xf = TRUE; /* Don't transfer CRC to memory */ + cfblk.artx = TRUE; /* Disable automatic retransmission */ + cfblk.sarec = TRUE; /* Disable source addr trig of CD */ + cfblk.tx_jabber = TRUE; /* Disable jabber jam sequence */ + cfblk.hash_1 = FALSE; /* Use bits 0-5 in mc address hash */ + cfblk.lbpkpol = TRUE; /* Loopback pin active high */ + cfblk.fdx = FALSE; /* Disable full duplex operation */ + cfblk.dummy_6 = 0x3f; /* all ones */ + cfblk.mult_ia = FALSE; /* No multiple individual addresses */ + cfblk.dis_bof = FALSE; /* Disable the backoff algorithm ?! */ + cfblk.dummy_1 = TRUE; /* set to 1 */ + cfblk.tx_ifs_retrig = 3; /* Hmm... Disabled */ +#ifdef MULTICAST_ALL + cfblk.mc_all = (lp->allmulticast ? TRUE: FALSE); /* Allow all multicasts */ +#else + cfblk.mc_all = FALSE; /* No multicast all mode */ +#endif + cfblk.rcv_mon = 0; /* Monitor mode disabled */ + cfblk.frag_acpt = TRUE; /* Do not accept fragments */ + cfblk.tstrttrs = FALSE; /* No start transmission threshold */ + cfblk.fretx = TRUE; /* FIFO automatic retransmission */ + cfblk.syncrqs = FALSE; /* Synchronous DRQ deassertion... */ + cfblk.sttlen = TRUE; /* 6 byte status registers */ + cfblk.rx_eop = TRUE; /* Signal EOP on packet reception */ + cfblk.tx_eop = TRUE; /* Signal EOP on packet transmission */ + cfblk.rbuf_size = RX_SIZE>>11; /* Set receive buffer size */ + cfblk.rcvstop = TRUE; /* Enable Receive Stop Register */ + +#ifdef DEBUG_I82593_SHOW + { + u_char *c = (u_char *) &cfblk; + int i; + printk(KERN_DEBUG "wavelan_cs: config block:"); + for(i = 0; i < sizeof(struct i82593_conf_block); i++,c++) + { + if((i % 16) == 0) printk("\n" KERN_DEBUG); + printk("%02x ", *c); + } + printk("\n"); + } +#endif + + /* Copy the config block to the i82593 */ + outb(TX_BASE & 0xff, PIORL(base)); + outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(sizeof(struct i82593_conf_block) & 0xff, PIOP(base)); /* lsb */ + outb(sizeof(struct i82593_conf_block) >> 8, PIOP(base)); /* msb */ + outsb(PIOP(base), (char *) &cfblk, sizeof(struct i82593_conf_block)); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + if(!wv_82593_cmd(dev, "wv_82593_config(): configure", + OP0_CONFIGURE, SR0_CONFIGURE_DONE)) + ret = FALSE; + + /* Initialize adapter's ethernet MAC address */ + outb(TX_BASE & 0xff, PIORL(base)); + outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(WAVELAN_ADDR_SIZE, PIOP(base)); /* byte count lsb */ + outb(0, PIOP(base)); /* byte count msb */ + outsb(PIOP(base), &dev->dev_addr[0], WAVELAN_ADDR_SIZE); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup", + OP0_IA_SETUP, SR0_IA_SETUP_DONE)) + ret = FALSE; + +#ifdef WAVELAN_ROAMING + /* If roaming is enabled, join the "Beacon Request" multicast group... */ + /* But only if it's not in there already! */ + if(do_roaming) + dev_mc_add(dev,WAVELAN_BEACON_ADDRESS, WAVELAN_ADDR_SIZE, 1); +#endif /* WAVELAN_ROAMING */ + + /* If any multicast address to set */ + if(lp->mc_count) + { + struct dev_mc_list * dmi; + int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count; + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n", + dev->name, lp->mc_count); + for(dmi=dev->mc_list; dmi; dmi=dmi->next) + printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n", + dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], + dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] ); +#endif + + /* Initialize adapter's ethernet multicast addresses */ + outb(TX_BASE & 0xff, PIORL(base)); + outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(addrs_len & 0xff, PIOP(base)); /* byte count lsb */ + outb((addrs_len >> 8), PIOP(base)); /* byte count msb */ + for(dmi=dev->mc_list; dmi; dmi=dmi->next) + outsb(PIOP(base), dmi->dmi_addr, dmi->dmi_addrlen); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup", + OP0_MC_SETUP, SR0_MC_SETUP_DONE)) + ret = FALSE; + lp->mc_count = dev->mc_count; /* remember to avoid repeated reset */ + } + + /* Job done, clear the flag */ + lp->reconfig_82593 = FALSE; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name); +#endif + return(ret); +} + +/*------------------------------------------------------------------*/ +/* + * Read the Access Configuration Register, perform a software reset, + * and then re-enable the card's software. + * + * If I understand correctly : reset the pcmcia interface of the + * wavelan. + * (called by wv_config()) + */ +static inline int +wv_pcmcia_reset(device * dev) +{ + int i; + conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 }; + dev_link_t * link = ((net_local *) dev->priv)->link; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name); +#endif + + i = CardServices(AccessConfigurationRegister, link->handle, ®); + if(i != CS_SUCCESS) + { + cs_error(link->handle, AccessConfigurationRegister, i); + return FALSE; + } + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wavelan_pcmcia_reset(): Config reg is 0x%x\n", + dev->name, (u_int) reg.Value); +#endif + + reg.Action = CS_WRITE; + reg.Value = reg.Value | COR_SW_RESET; + i = CardServices(AccessConfigurationRegister, link->handle, ®); + if(i != CS_SUCCESS) + { + cs_error(link->handle, AccessConfigurationRegister, i); + return FALSE; + } + + reg.Action = CS_WRITE; + reg.Value = COR_LEVEL_IRQ | COR_CONFIG; + i = CardServices(AccessConfigurationRegister, link->handle, ®); + if(i != CS_SUCCESS) + { + cs_error(link->handle, AccessConfigurationRegister, i); + return FALSE; + } + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_pcmcia_reset()\n", dev->name); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * wavelan_hw_config() is called after a CARD_INSERTION event is + * received, to configure the wavelan hardware. + * Note that the reception will be enabled in wavelan->open(), so the + * device is configured but idle... + * Performs the following actions: + * 1. A pcmcia software reset (using wv_pcmcia_reset()) + * 2. A power reset (reset DMA) + * 3. Reset the LAN controller + * 4. Initialize the radio modem (using wv_mmc_init) + * 5. Configure LAN controller (using wv_82593_config) + * 6. Perform a diagnostic on the LAN controller + * (called by wavelan_event() & wv_hw_reset()) + */ +static int +wv_hw_config(device * dev) +{ + net_local * lp = (net_local *) dev->priv; + ioaddr_t base = dev->base_addr; + unsigned long flags; + int ret = FALSE; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name); +#endif + +#ifdef STRUCT_CHECK + if(wv_structuct_check() != (char *) NULL) + { + printk(KERN_WARNING "%s: wv_hw_config: structure/compiler botch: \"%s\"\n", + dev->name, wv_structuct_check()); + return FALSE; + } +#endif /* STRUCT_CHECK == 1 */ + + /* Reset the pcmcia interface */ + if(wv_pcmcia_reset(dev) == FALSE) + return FALSE; + + /* Disable interrupts */ + wv_splhi(lp, &flags); + + /* Disguised goto ;-) */ + do + { + /* Power UP the module + reset the modem + reset host adapter + * (in fact, reset DMA channels) */ + hacr_write_slow(base, HACR_RESET); + hacr_write(base, HACR_DEFAULT); + + /* Check if the module has been powered up... */ + if(hasr_read(base) & HASR_NO_CLK) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n", + dev->name); +#endif + break; + } + + /* initialize the modem */ + if(wv_mmc_init(dev) == FALSE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n", + dev->name); +#endif + break; + } + + /* reset the LAN controller (i82593) */ + outb(OP0_RESET, LCCR(base)); + mdelay(1); /* A bit crude ! */ + + /* Initialize the LAN controller */ + if(wv_82593_config(dev) == FALSE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", + dev->name); +#endif + break; + } + + /* Diagnostic */ + if(wv_diag(dev) == FALSE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n", + dev->name); +#endif + break; + } + + /* + * insert code for loopback test here + */ + + /* The device is now configured */ + lp->configured = 1; + ret = TRUE; + } + while(0); + + /* Re-enable interrupts */ + wv_splx(lp, &flags); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name); +#endif + return(ret); +} + +/*------------------------------------------------------------------*/ +/* + * Totally reset the wavelan and restart it. + * Performs the following actions: + * 1. Call wv_hw_config() + * 2. Start the LAN controller's receive unit + * (called by wavelan_event(), wavelan_watchdog() and wavelan_open()) + */ +static inline void +wv_hw_reset(device * dev) +{ + net_local * lp = (net_local *) dev->priv; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name); +#endif + + lp->nresets++; + lp->configured = 0; + + /* Call wv_hw_config() for most of the reset & init stuff */ + if(wv_hw_config(dev) == FALSE) + return; + + /* start receive unit */ + wv_ru_start(dev); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * wv_pcmcia_config() is called after a CARD_INSERTION event is + * received, to configure the PCMCIA socket, and to make the ethernet + * device available to the system. + * (called by wavelan_event()) + */ +static inline int +wv_pcmcia_config(dev_link_t * link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + struct net_device * dev; + int i; + u_char buf[64]; + win_req_t req; + memreq_t mem; + + handle = link->handle; + dev = (device *) link->priv; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link); +#endif + + /* + * This reads the card's CONFIG tuple to find its configuration + * registers. + */ + do + { + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + i = CardServices(GetFirstTuple, handle, &tuple); + if(i != CS_SUCCESS) + break; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + i = CardServices(GetTupleData, handle, &tuple); + if(i != CS_SUCCESS) + break; + i = CardServices(ParseTuple, handle, &tuple, &parse); + if(i != CS_SUCCESS) + break; + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + } + while(0); + if(i != CS_SUCCESS) + { + cs_error(link->handle, ParseTuple, i); + link->state &= ~DEV_CONFIG_PENDING; + return FALSE; + } + + /* Configure card */ + link->state |= DEV_CONFIG; + do + { + i = CardServices(RequestIO, link->handle, &link->io); + if(i != CS_SUCCESS) + { + cs_error(link->handle, RequestIO, i); + break; + } + + /* + * Now allocate an interrupt line. Note that this does not + * actually assign a handler to the interrupt. + */ + i = CardServices(RequestIRQ, link->handle, &link->irq); + if(i != CS_SUCCESS) + { + cs_error(link->handle, RequestIRQ, i); + break; + } + + /* + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping. + */ + link->conf.ConfigIndex = 1; + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if(i != CS_SUCCESS) + { + cs_error(link->handle, RequestConfiguration, i); + break; + } + + /* + * Allocate a small memory window. Note that the dev_link_t + * structure provides space for one window handle -- if your + * device needs several windows, you'll need to keep track of + * the handles in your private data structure, link->priv. + */ + req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; + req.Base = req.Size = 0; + req.AccessSpeed = mem_speed; + link->win = (window_handle_t)link->handle; + i = CardServices(RequestWindow, &link->win, &req); + if(i != CS_SUCCESS) + { + cs_error(link->handle, RequestWindow, i); + break; + } + + dev->rmem_start = dev->mem_start = + (u_long)ioremap(req.Base, req.Size); + dev->rmem_end = dev->mem_end = dev->mem_start + req.Size; + + mem.CardOffset = 0; mem.Page = 0; + i = CardServices(MapMemPage, link->win, &mem); + if(i != CS_SUCCESS) + { + cs_error(link->handle, MapMemPage, i); + break; + } + + /* Feed device with this info... */ + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + netif_start_queue(dev); + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n", + (u_int) dev->mem_start, dev->irq, (u_int) dev->base_addr); +#endif + + i = register_netdev(dev); + if(i != 0) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "wv_pcmcia_config(): register_netdev() failed\n"); +#endif + break; + } + } + while(0); /* Humm... Disguised goto !!! */ + + link->state &= ~DEV_CONFIG_PENDING; + /* If any step failed, release any partially configured state */ + if(i != 0) + { + wv_pcmcia_release((u_long) link); + return FALSE; + } + + strcpy(((net_local *) dev->priv)->node.dev_name, dev->name); + link->dev = &((net_local *) dev->priv)->node; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "<-wv_pcmcia_config()\n"); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * After a card is removed, wv_pcmcia_release() will unregister the net + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. + */ +static void +wv_pcmcia_release(u_long arg) /* Address of the interface struct */ +{ + dev_link_t * link = (dev_link_t *) arg; + device * dev = (device *) link->priv; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); +#endif + + /* If the device is currently in use, we won't release until it is + * actually closed. */ + if(link->open) + { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wv_pcmcia_release: release postponed, device still open\n", + dev->name); +#endif + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Don't bother checking to see if these succeed or not */ + iounmap((u_char *)dev->mem_start); + CardServices(ReleaseWindow, link->win); + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name); +#endif +} /* wv_pcmcia_release */ + +/*------------------------------------------------------------------*/ +/* + * Sometimes, wavelan_detach can't be performed following a call from + * cardmgr (device still open, pcmcia_release not done) and the device + * is put in a STALE_LINK state and remains in memory. + * + * This function run through our current list of device and attempt + * another time to remove them. We hope that since last time the + * device has properly been closed. + * + * (called by wavelan_attach() & cleanup_module()) + */ +static void +wv_flush_stale_links(void) +{ + dev_link_t * link; /* Current node in linked list */ + dev_link_t * next; /* Next node in linked list */ + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "-> wv_flush_stale_links(0x%p)\n", dev_list); +#endif + + /* Go through the list */ + for (link = dev_list; link; link = next) + { + next = link->next; + + /* Check if in need of being removed */ + if((link->state & DEV_STALE_LINK) || + (! (link->state & DEV_PRESENT))) + wavelan_detach(link); + + } + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "<- wv_flush_stale_links()\n"); +#endif +} + +/************************ INTERRUPT HANDLING ************************/ + +/* + * This function is the interrupt handler for the WaveLAN card. This + * routine will be called whenever: + * 1. A packet is received. + * 2. A packet has successfully been transferred and the unit is + * ready to transmit another packet. + * 3. A command has completed execution. + */ +static void +wavelan_interrupt(int irq, + void * dev_id, + struct pt_regs * regs) +{ + device * dev; + net_local * lp; + ioaddr_t base; + int status0; + u_int tx_status; + + if((dev = (device *)dev_id) == (device *) NULL) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n", + irq); +#endif + return; + } + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); +#endif + + lp = (net_local *) dev->priv; + base = dev->base_addr; + +#ifdef DEBUG_INTERRUPT_INFO + /* Check state of our spinlock (it should be cleared) */ + if(spin_is_locked(&lp->spinlock)) + printk(KERN_DEBUG + "%s: wavelan_interrupt(): spinlock is already locked !!!\n", + dev->name); +#endif + + /* Prevent reentrancy. We need to do that because we may have + * multiple interrupt handler running concurently. + * It is safe because wv_splhi() disable interrupts before aquiring + * the spinlock. */ + spin_lock(&lp->spinlock); + + /* Treat all pending interrupts */ + while(1) + { + /* ---------------- INTERRUPT CHECKING ---------------- */ + /* + * Look for the interrupt and verify the validity + */ + outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); + status0 = inb(LCSR(base)); + +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "status0 0x%x [%s => 0x%x]", status0, + (status0&SR0_INTERRUPT)?"int":"no int",status0&~SR0_INTERRUPT); + if(status0&SR0_INTERRUPT) + { + printk(" [%s => %d]\n", (status0 & SR0_CHNL) ? "chnl" : + ((status0 & SR0_EXECUTION) ? "cmd" : + ((status0 & SR0_RECEPTION) ? "recv" : "unknown")), + (status0 & SR0_EVENT_MASK)); + } + else + printk("\n"); +#endif + + /* Return if no actual interrupt from i82593 (normal exit) */ + if(!(status0 & SR0_INTERRUPT)) + break; + + /* If interrupt is both Rx and Tx or none... + * This code in fact is there to catch the spurious interrupt + * when you remove the wavelan pcmcia card from the socket */ + if(((status0 & SR0_BOTH_RX_TX) == SR0_BOTH_RX_TX) || + ((status0 & SR0_BOTH_RX_TX) == 0x0)) + { +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_INFO "%s: wv_interrupt(): bogus interrupt (or from dead card) : %X\n", + dev->name, status0); +#endif + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); + break; + } + + /* ----------------- RECEIVING PACKET ----------------- */ + /* + * When the wavelan signal the reception of a new packet, + * we call wv_packet_rcv() to copy if from the buffer and + * send it to NET3 + */ + if(status0 & SR0_RECEPTION) + { +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "%s: wv_interrupt(): receive\n", dev->name); +#endif + + if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wv_interrupt(): receive buffer overflow\n", + dev->name); +#endif + lp->stats.rx_over_errors++; + lp->overrunning = 1; + } + + /* Get the packet */ + wv_packet_rcv(dev); + lp->overrunning = 0; + + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); + continue; + } + + /* ---------------- COMMAND COMPLETION ---------------- */ + /* + * Interrupts issued when the i82593 has completed a command. + * Most likely : transmission done + */ + + /* If a transmission has been done */ + if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE || + (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE || + (status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) + { +#ifdef DEBUG_TX_ERROR + if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) + printk(KERN_INFO "%s: wv_interrupt(): packet transmitted without CRC.\n", + dev->name); +#endif + + /* Get transmission status */ + tx_status = inb(LCSR(base)); + tx_status |= (inb(LCSR(base)) << 8); +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "%s: wv_interrupt(): transmission done\n", + dev->name); + { + u_int rcv_bytes; + u_char status3; + rcv_bytes = inb(LCSR(base)); + rcv_bytes |= (inb(LCSR(base)) << 8); + status3 = inb(LCSR(base)); + printk(KERN_DEBUG "tx_status 0x%02x rcv_bytes 0x%02x status3 0x%x\n", + tx_status, rcv_bytes, (u_int) status3); + } +#endif + /* Check for possible errors */ + if((tx_status & TX_OK) != TX_OK) + { + lp->stats.tx_errors++; + + if(tx_status & TX_FRTL) + { +#ifdef DEBUG_TX_ERROR + printk(KERN_INFO "%s: wv_interrupt(): frame too long\n", + dev->name); +#endif + } + if(tx_status & TX_UND_RUN) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): DMA underrun\n", + dev->name); +#endif + lp->stats.tx_aborted_errors++; + } + if(tx_status & TX_LOST_CTS) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): no CTS\n", dev->name); +#endif + lp->stats.tx_carrier_errors++; + } + if(tx_status & TX_LOST_CRS) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): no carrier\n", + dev->name); +#endif + lp->stats.tx_carrier_errors++; + } + if(tx_status & TX_HRT_BEAT) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): heart beat\n", dev->name); +#endif + lp->stats.tx_heartbeat_errors++; + } + if(tx_status & TX_DEFER) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): channel jammed\n", + dev->name); +#endif + } + /* Ignore late collisions since they're more likely to happen + * here (the WaveLAN design prevents the LAN controller from + * receiving while it is transmitting). We take action only when + * the maximum retransmit attempts is exceeded. + */ + if(tx_status & TX_COLL) + { + if(tx_status & TX_MAX_COL) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): channel congestion\n", + dev->name); +#endif + if(!(tx_status & TX_NCOL_MASK)) + { + lp->stats.collisions += 0x10; + } + } + } + } /* if(!(tx_status & TX_OK)) */ + + lp->stats.collisions += (tx_status & TX_NCOL_MASK); + lp->stats.tx_packets++; + + netif_wake_queue(dev); + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ + } + else /* if interrupt = transmit done or retransmit done */ + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wavelan_cs: unknown interrupt, status0 = %02x\n", + status0); +#endif + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ + } + } /* while(1) */ + + spin_unlock(&lp->spinlock); + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); +#endif +} /* wv_interrupt */ + +/*------------------------------------------------------------------*/ +/* + * Watchdog: when we start a transmission, a timer is set for us in the + * kernel. If the transmission completes, this timer is disabled. If + * the timer expires, we are called and we try to unlock the hardware. + * + * Note : This watchdog is move clever than the one in the ISA driver, + * because it try to abort the current command before reseting + * everything... + * On the other hand, it's a bit simpler, because we don't have to + * deal with the multiple Tx buffers... + */ +static void +wavelan_watchdog(device * dev) +{ + net_local * lp = (net_local *) dev->priv; + ioaddr_t base = dev->base_addr; + unsigned long flags; + int aborted = FALSE; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); +#endif + +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", + dev->name); +#endif + + wv_splhi(lp, &flags); + + /* Ask to abort the current command */ + outb(OP0_ABORT, LCCR(base)); + + /* Wait for the end of the command (a bit hackish) */ + if(wv_82593_cmd(dev, "wavelan_watchdog(): abort", + OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED)) + aborted = TRUE; + + /* Release spinlock here so that wv_hw_reset() can grab it */ + wv_splx(lp, &flags); + + /* Check if we were successful in aborting it */ + if(!aborted) + { + /* It seem that it wasn't enough */ +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wavelan_watchdog: abort failed, trying reset\n", + dev->name); +#endif + wv_hw_reset(dev); + } + +#ifdef DEBUG_PSA_SHOW + { + psa_t psa; + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + wv_psa_show(&psa); + } +#endif +#ifdef DEBUG_MMC_SHOW + wv_mmc_show(dev); +#endif +#ifdef DEBUG_I82593_SHOW + wv_ru_show(dev); +#endif + + /* We are no more waiting for something... */ + netif_wake_queue(dev); + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); +#endif +} + +/********************* CONFIGURATION CALLBACKS *********************/ +/* + * Here are the functions called by the pcmcia package (cardmgr) and + * linux networking (NET3) for initialization, configuration and + * deinstallations of the Wavelan Pcmcia Hardware. + */ + +/*------------------------------------------------------------------*/ +/* + * Configure and start up the WaveLAN PCMCIA adaptor. + * Called by NET3 when it "open" the device. + */ +static int +wavelan_open(device * dev) +{ + dev_link_t * link = ((net_local *) dev->priv)->link; + net_local * lp = (net_local *)dev->priv; + ioaddr_t base = dev->base_addr; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + /* Check if the modem is powered up (wavelan_close() power it down */ + if(hasr_read(base) & HASR_NO_CLK) + { + /* Power up (power up time is 250us) */ + hacr_write(base, HACR_DEFAULT); + + /* Check if the module has been powered up... */ + if(hasr_read(base) & HASR_NO_CLK) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wavelan_open(): modem not connected\n", + dev->name); +#endif + return FALSE; + } + } + + /* Start reception and declare the driver ready */ + if(!lp->configured) + return FALSE; + if(!wv_ru_start(dev)) + wv_hw_reset(dev); /* If problem : reset */ + netif_start_queue(dev); + + /* Mark the device as used */ + link->open++; + MOD_INC_USE_COUNT; + +#ifdef WAVELAN_ROAMING + if(do_roaming) + wv_roam_init(dev); +#endif /* WAVELAN_ROAMING */ + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Shutdown the WaveLAN PCMCIA adaptor. + * Called by NET3 when it "close" the device. + */ +static int +wavelan_close(device * dev) +{ + dev_link_t * link = ((net_local *) dev->priv)->link; + ioaddr_t base = dev->base_addr; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + /* If the device isn't open, then nothing to do */ + if(!link->open) + { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wavelan_close(): device not open\n", dev->name); +#endif + return 0; + } + +#ifdef WAVELAN_ROAMING + /* Cleanup of roaming stuff... */ + if(do_roaming) + wv_roam_cleanup(dev); +#endif /* WAVELAN_ROAMING */ + + link->open--; + MOD_DEC_USE_COUNT; + + /* If the card is still present */ + if(netif_running(dev)) + { + netif_stop_queue(dev); + + /* Stop receiving new messages and wait end of transmission */ + wv_ru_stop(dev); + + /* Power down the module */ + hacr_write(base, HACR_DEFAULT & (~HACR_PWR_STAT)); + } + else + /* The card is no more there (flag is activated in wv_pcmcia_release) */ + if(link->state & DEV_STALE_CONFIG) + wv_pcmcia_release((u_long)link); + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * wavelan_attach() creates an "instance" of the driver, allocating + * local data structures for one device (one interface). The device + * is registered with Card Services. + * + * The dev_link structure is initialized, but we don't actually + * configure the card at this point -- we wait until we receive a + * card insertion event. + */ +static dev_link_t * +wavelan_attach(void) +{ + client_reg_t client_reg; /* Register with cardmgr */ + dev_link_t * link; /* Info for cardmgr */ + device * dev; /* Interface generic data */ + net_local * lp; /* Interface specific data */ + int i, ret; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "-> wavelan_attach()\n"); +#endif + + /* Perform some cleanup */ + wv_flush_stale_links(); + + /* Initialize the dev_link_t structure */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + if (!link) return NULL; + memset(link, 0, sizeof(struct dev_link_t)); + + /* Unused for the Wavelan */ + link->release.function = &wv_pcmcia_release; + link->release.data = (u_long) link; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 8; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = 3; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = wavelan_interrupt; + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Chain drivers */ + link->next = dev_list; + dev_list = link; + + /* Allocate the generic data structure */ + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (!dev) { + kfree(link); + return NULL; + } + memset(dev, 0x00, sizeof(struct net_device)); + link->priv = link->irq.Instance = dev; + + /* Allocate the wavelan-specific data structure. */ + dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); + if (!lp) { + kfree(link); + kfree(dev); + return NULL; + } + memset(lp, 0x00, sizeof(net_local)); + + /* Init specific data */ + lp->configured = 0; + lp->reconfig_82593 = FALSE; + lp->nresets = 0; + /* Multicast stuff */ + lp->promiscuous = 0; + lp->allmulticast = 0; + lp->mc_count = 0; + + /* Init spinlock */ + spin_lock_init(&lp->spinlock); + + /* back links */ + lp->link = link; + lp->dev = dev; + + /* Standard setup for generic data */ + ether_setup(dev); + + /* wavelan NET3 callbacks */ + dev->open = &wavelan_open; + dev->stop = &wavelan_close; + dev->hard_start_xmit = &wavelan_packet_xmit; + dev->get_stats = &wavelan_get_stats; + dev->set_multicast_list = &wavelan_set_multicast_list; +#ifdef SET_MAC_ADDRESS + dev->set_mac_address = &wavelan_set_mac_address; +#endif /* SET_MAC_ADDRESS */ + + /* Set the watchdog timer */ + dev->tx_timeout = &wavelan_watchdog; + dev->watchdog_timeo = WATCHDOG_JIFFIES; + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ + dev->do_ioctl = wavelan_ioctl; /* wireless extensions */ + dev->get_wireless_stats = wavelan_get_wireless_stats; +#endif + + /* Other specific data */ + dev->mtu = WAVELAN_MTU; + + /* Register with Card Services */ + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_REGISTRATION_COMPLETE | + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &wavelan_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "wavelan_attach(): almost done, calling CardServices\n"); +#endif + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if(ret != 0) + { + cs_error(link->handle, RegisterClient, ret); + wavelan_detach(link); + return NULL; + } + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "<- wavelan_attach()\n"); +#endif + + return link; +} + +/*------------------------------------------------------------------*/ +/* + * This deletes a driver "instance". The device is de-registered with + * Card Services. If it has been released, all local data structures + * are freed. Otherwise, the structures will be freed when the device + * is released. + */ +static void +wavelan_detach(dev_link_t * link) +{ +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link); +#endif + + /* + * If the device is currently configured and active, we won't + * actually delete it yet. Instead, it is marked so that when the + * release() function is called, that will trigger a proper + * detach(). + */ + if(link->state & DEV_CONFIG) + { + /* Some others haven't done their job : give them another chance */ + wv_pcmcia_release((u_long) link); + if(link->state & DEV_STALE_CONFIG) + { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "wavelan_detach: detach postponed," + " '%s' still locked\n", link->dev->dev_name); +#endif + link->state |= DEV_STALE_LINK; + return; + } + } + + /* Break the link with Card Services */ + if(link->handle) + CardServices(DeregisterClient, link->handle); + + /* Remove the interface data from the linked list */ + if(dev_list == link) + dev_list = link->next; + else + { + dev_link_t * prev = dev_list; + + while((prev != (dev_link_t *) NULL) && (prev->next != link)) + prev = prev->next; + + if(prev == (dev_link_t *) NULL) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "wavelan_detach : Attempting to remove a nonexistent device.\n"); +#endif + return; + } + + prev->next = link->next; + } + + /* Free pieces */ + if(link->priv) + { + device * dev = (device *) link->priv; + + /* Remove ourselves from the kernel list of ethernet devices */ + /* Warning : can't be called from interrupt, timer or wavelan_close() */ + if(link->dev != NULL) + unregister_netdev(dev); + link->dev = NULL; + + if(dev->priv) + { + /* Sound strange, but safe... */ + ((net_local *) dev->priv)->link = (dev_link_t *) NULL; + ((net_local *) dev->priv)->dev = (device *) NULL; + kfree(dev->priv); + } + kfree(link->priv); + } + kfree(link); + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "<- wavelan_detach()\n"); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * The card status event handler. Mostly, this schedules other stuff + * to run after an event is received. A CARD_REMOVAL event also sets + * some flags to discourage the net drivers from trying to talk to the + * card any more. + */ +static int +wavelan_event(event_t event, /* The event received */ + int priority, + event_callback_args_t * args) +{ + dev_link_t * link = (dev_link_t *) args->client_data; + device * dev = (device *) link->priv; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "->wavelan_event(): %s\n", + ((event == CS_EVENT_REGISTRATION_COMPLETE)?"registration complete" : + ((event == CS_EVENT_CARD_REMOVAL) ? "card removal" : + ((event == CS_EVENT_CARD_INSERTION) ? "card insertion" : + ((event == CS_EVENT_PM_SUSPEND) ? "pm suspend" : + ((event == CS_EVENT_RESET_PHYSICAL) ? "physical reset" : + ((event == CS_EVENT_PM_RESUME) ? "pm resume" : + ((event == CS_EVENT_CARD_RESET) ? "card reset" : + "unknown")))))))); +#endif + + switch(event) + { + case CS_EVENT_REGISTRATION_COMPLETE: +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "wavelan_cs: registration complete\n"); +#endif + break; + + case CS_EVENT_CARD_REMOVAL: + /* Oups ! The card is no more there */ + link->state &= ~DEV_PRESENT; + if(link->state & DEV_CONFIG) + { + /* Accept no more transmissions */ + netif_device_detach(dev); + + /* Release the card */ + wv_pcmcia_release((u_long) link); + } + break; + + case CS_EVENT_CARD_INSERTION: + /* Reset and configure the card */ + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + if(wv_pcmcia_config(link) && + wv_hw_config(dev)) + wv_init_info(dev); + else + dev->irq = 0; + break; + + case CS_EVENT_PM_SUSPEND: + /* NB: wavelan_close will be called, but too late, so we are + * obliged to close nicely the wavelan here. David, could you + * close the device before suspending them ? And, by the way, + * could you, on resume, add a "route add -net ..." after the + * ifconfig up ??? Thanks... */ + + /* Stop receiving new messages and wait end of transmission */ + wv_ru_stop(dev); + + /* Power down the module */ + hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT)); + + /* The card is now suspended */ + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if(link->state & DEV_CONFIG) + { + if(link->open) + netif_device_detach(dev); + CardServices(ReleaseConfiguration, link->handle); + } + break; + + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if(link->state & DEV_CONFIG) + { + CardServices(RequestConfiguration, link->handle, &link->conf); + if(link->open) /* If RESET -> True, If RESUME -> False ??? */ + { + wv_hw_reset(dev); + netif_device_attach(dev); + } + } + break; + } + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "<-wavelan_event()\n"); +#endif + return 0; +} + +/****************************** MODULE ******************************/ +/* + * Module entry points : insertion & removal + */ + +/*------------------------------------------------------------------*/ +/* + * Module insertion : initialisation of the module. + * Register the card with cardmgr... + */ +static int __init +init_wavelan_cs(void) +{ + servinfo_t serv; + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "-> init_wavelan_cs()\n"); +#ifdef DEBUG_VERSION_SHOW + printk(KERN_DEBUG "%s", version); +#endif +#endif + + CardServices(GetCardServicesInfo, &serv); + if(serv.Revision != CS_RELEASE_CODE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "init_wavelan_cs: Card Services release does not match!\n"); +#endif + return -1; + } + + register_pccard_driver(&dev_info, &wavelan_attach, &wavelan_detach); + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "<- init_wavelan_cs()\n"); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Module removal + */ +static void __exit +exit_wavelan_cs(void) +{ +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "-> cleanup_module()\n"); +#endif +#ifdef DEBUG_BASIC_SHOW + printk(KERN_NOTICE "wavelan_cs: unloading\n"); +#endif + + /* Do some cleanup of the device list */ + wv_flush_stale_links(); + + /* If there remain some devices... */ +#ifdef DEBUG_CONFIG_ERRORS + if(dev_list != NULL) + { + /* Honestly, if this happen we are in a deep s**t */ + printk(KERN_INFO "wavelan_cs: devices remaining when removing module\n"); + printk(KERN_INFO "Please flush your disks and reboot NOW !\n"); + } +#endif + + unregister_pccard_driver(&dev_info); + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "<- cleanup_module()\n"); +#endif +} + +module_init(init_wavelan_cs); +module_exit(exit_wavelan_cs); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pcmcia/wavelan_cs.h linux-2.5/drivers/net/pcmcia/wavelan_cs.h --- linux-2.5.5/drivers/net/pcmcia/wavelan_cs.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/pcmcia/wavelan_cs.h Tue Jan 22 17:44:56 2002 @@ -0,0 +1,825 @@ +/* + * Wavelan Pcmcia driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * + * This file contain all definition and declarations necessary for the + * wavelan pcmcia driver. This file is a private header, so it should + * be included only on wavelan_cs.c !!! + */ + +#ifndef WAVELAN_CS_H +#define WAVELAN_CS_H + +/************************** DOCUMENTATION **************************/ +/* + * This driver provide a Linux interface to the Wavelan Pcmcia hardware + * The Wavelan is a product of Lucent (http://www.wavelan.com/). + * This division was formerly part of NCR and then AT&T. + * Wavelan are also distributed by DEC (RoamAbout DS)... + * + * To know how to use this driver, read the PCMCIA HOWTO. + * If you want to exploit the many other fonctionalities, look comments + * in the code... + * + * This driver is the result of the effort of many peoples (see below). + */ + +/* ------------------------ SPECIFIC NOTES ------------------------ */ +/* + * Web page + * -------- + * I try to maintain a web page with the Wireless LAN Howto at : + * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html + * + * SMP + * --- + * We now are SMP compliant (I eventually fixed the remaining bugs). + * The driver has been tested on a dual P6-150 and survived my usual + * set of torture tests. + * Anyway, I spent enough time chasing interrupt re-entrancy during + * errors or reconfigure, and I designed the locked/unlocked sections + * of the driver with great care, and with the recent addition of + * the spinlock (thanks to the new API), we should be quite close to + * the truth. + * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), + * but better safe than sorry (especially at 2 Mb/s ;-). + * + * I have also looked into disabling only our interrupt on the card + * (via HACR) instead of all interrupts in the processor (via cli), + * so that other driver are not impacted, and it look like it's + * possible, but it's very tricky to do right (full of races). As + * the gain would be mostly for SMP systems, it can wait... + * + * Debugging and options + * --------------------- + * You will find below a set of '#define" allowing a very fine control + * on the driver behaviour and the debug messages printed. + * The main options are : + * o WAVELAN_ROAMING, for the experimental roaming support. + * o SET_PSA_CRC, to have your card correctly recognised by + * an access point and the Point-to-Point diagnostic tool. + * o USE_PSA_CONFIG, to read configuration from the PSA (EEprom) + * (otherwise we always start afresh with some defaults) + * + * wavelan_cs.o is darn too big + * ------------------------- + * That's true ! There is a very simple way to reduce the driver + * object by 33% (yes !). Comment out the following line : + * #include + * Other compile options can also reduce the size of it... + * + * MAC address and hardware detection : + * ---------------------------------- + * The detection code of the wavelan chech that the first 3 + * octets of the MAC address fit the company code. This type of + * detection work well for AT&T cards (because the AT&T code is + * hardcoded in wavelan.h), but of course will fail for other + * manufacturer. + * + * If you are sure that your card is derived from the wavelan, + * here is the way to configure it : + * 1) Get your MAC address + * a) With your card utilities (wfreqsel, instconf, ...) + * b) With the driver : + * o compile the kernel with DEBUG_CONFIG_INFO enabled + * o Boot and look the card messages + * 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h) + * 3) Compile & verify + * 4) Send me the MAC code - I will include it in the next version... + * + */ + +/* --------------------- WIRELESS EXTENSIONS --------------------- */ +/* + * This driver is the first one to support "wireless extensions". + * This set of extensions provide you some way to control the wireless + * caracteristics of the hardware in a standard way and support for + * applications for taking advantage of it (like Mobile IP). + * + * You will need to enable the CONFIG_NET_RADIO define in the kernel + * configuration to enable the wireless extensions (this is the one + * giving access to the radio network device choice). + * + * It might also be a good idea as well to fetch the wireless tools to + * configure the device and play a bit. + */ + +/* ---------------------------- FILES ---------------------------- */ +/* + * wavelan_cs.c : The actual code for the driver - C functions + * + * wavelan_cs.h : Private header : local types / vars for the driver + * + * wavelan.h : Description of the hardware interface & structs + * + * i82593.h : Description if the Ethernet controller + */ + +/* --------------------------- HISTORY --------------------------- */ +/* + * The history of the Wavelan drivers is as complicated as history of + * the Wavelan itself (NCR -> AT&T -> Lucent). + * + * All started with Anders Klemets , + * writting a Wavelan ISA driver for the MACH microkernel. Girish + * Welling had also worked on it. + * Keith Moore modify this for the Pcmcia hardware. + * + * Robert Morris port these two drivers to BSDI + * and add specific Pcmcia support (there is currently no equivalent + * of the PCMCIA package under BSD...). + * + * Jim Binkley port both BSDI drivers to FreeBSD. + * + * Bruce Janson port the BSDI ISA driver to Linux. + * + * Anthony D. Joseph started modify Bruce driver + * (with help of the BSDI PCMCIA driver) for PCMCIA. + * Yunzhou Li finished is work. + * Joe Finney patched the driver to start + * correctly 2.00 cards (2.4 GHz with frequency selection). + * David Hinds integrated the whole in his + * Pcmcia package (+ bug corrections). + * + * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some + * patchs to the Pcmcia driver. After, I added code in the ISA driver + * for Wireless Extensions and full support of frequency selection + * cards. Now, I'm doing the same to the Pcmcia driver + some + * reorganisation. + * Loeke Brederveld from Lucent has given me + * much needed informations on the Wavelan hardware. + */ + +/* By the way : for the copyright & legal stuff : + * Almost everybody wrote code under GNU or BSD license (or alike), + * and want that their original copyright remain somewhere in the + * code (for myself, I go with the GPL). + * Nobody want to take responsibility for anything, except the fame... + */ + +/* --------------------------- CREDITS --------------------------- */ +/* + * Credits: + * Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht and + * Loeke Brederveld of Lucent for providing extremely useful + * information about WaveLAN PCMCIA hardware + * + * This driver is based upon several other drivers, in particular: + * David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter + * Bruce Janson's Linux driver for the AT-bus WaveLAN adapter + * Anders Klemets' PCMCIA WaveLAN adapter driver + * Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter + * + * Additional Credits: + * + * This software was originally developed under Linux 1.2.3 + * (Slackware 2.0 distribution). + * And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+) + * with an HP OmniBook 4000 and then a 5500. + * + * It is based on other device drivers and information either written + * or supplied by: + * James Ashton (jaa101@syseng.anu.edu.au), + * Ajay Bakre (bakre@paul.rutgers.edu), + * Donald Becker (becker@super.org), + * Jim Binkley , + * Loeke Brederveld , + * Allan Creighton (allanc@cs.su.oz.au), + * Brent Elphick , + * Joe Finney , + * Matthew Geier (matthew@cs.su.oz.au), + * Remo di Giovanni (remo@cs.su.oz.au), + * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), + * David Hinds , + * Jan Hoogendoorn (c/o marteijn@lucent.com), + * Bruce Janson , + * Anthony D. Joseph , + * Anders Klemets (klemets@paul.rutgers.edu), + * Yunzhou Li , + * Marc Meertens (mmeertens@lucent.com), + * Keith Moore, + * Robert Morris (rtm@das.harvard.edu), + * Ian Parkin (ian@cs.su.oz.au), + * John Rosenberg (johnr@cs.su.oz.au), + * George Rossi (george@phm.gov.au), + * Arthur Scott (arthur@cs.su.oz.au), + * Stanislav Sinyagin + * Peter Storey, + * Jean Tourrilhes , + * Girish Welling (welling@paul.rutgers.edu) + * Clark Woodworth + * Yongguang Zhang ... + */ + +/* ------------------------- IMPROVEMENTS ------------------------- */ +/* + * I proudly present : + * + * Changes made in 2.8.22 : + * ---------------------- + * - improved wv_set_multicast_list + * - catch spurious interrupt + * - correct release of the device + * + * Changes mades in release : + * ------------------------ + * - Reorganisation of the code, function name change + * - Creation of private header (wavelan_cs.h) + * - Reorganised debug messages + * - More comments, history, ... + * - Configure earlier (in "insert" instead of "open") + * and do things only once + * - mmc_init : configure the PSA if not done + * - mmc_init : 2.00 detection better code for 2.00 init + * - better info at startup + * - Correct a HUGE bug (volatile & uncalibrated busy loop) + * in wv_82593_cmd => config speedup + * - Stop receiving & power down on close (and power up on open) + * use "ifconfig down" & "ifconfig up ; route add -net ..." + * - Send packets : add watchdog instead of pooling + * - Receive : check frame wrap around & try to recover some frames + * - wavelan_set_multicast_list : avoid reset + * - add wireless extensions (ioctl & get_wireless_stats) + * get/set nwid/frequency on fly, info for /proc/net/wireless + * - Suppress useless stuff from lp (net_local), but add link + * - More inlines + * - Lot of others minor details & cleanups + * + * Changes made in second release : + * ------------------------------ + * - Optimise wv_85893_reconfig stuff, fix potential problems + * - Change error values for ioctl + * - Non blocking wv_ru_stop() + call wv_reset() in case of problems + * - Remove development printk from wavelan_watchdog() + * - Remove of the watchdog to wavelan_close instead of wavelan_release + * fix potential problems... + * - Start debugging suspend stuff (but it's still a bit weird) + * - Debug & optimize dump header/packet in Rx & Tx (debug) + * - Use "readb" and "writeb" to be kernel 2.1 compliant + * - Better handling of bogus interrupts + * - Wireless extension : SETSPY and GETSPY + * - Remove old stuff (stats - for those needing it, just ask me...) + * - Make wireless extensions optional + * + * Changes made in third release : + * ----------------------------- + * - cleanups & typos + * - modif wireless ext (spy -> only one pointer) + * - new private ioctl to set/get quality & level threshold + * - Init : correct default value of level threshold for pcmcia + * - kill watchdog in hw_reset + * - more 2.1 support (copy_to/from_user instead of memcpy_to/fromfs) + * - Add message level (debug stuff in /var/adm/debug & errors not + * displayed at console and still in /var/adm/messages) + * + * Changes made in fourth release : + * ------------------------------ + * - multicast support (yes !) thanks to Yongguang Zhang. + * + * Changes made in fifth release (2.9.0) : + * ------------------------------------- + * - Revisited multicast code (it was mostly wrong). + * - protect code in wv_82593_reconfig with dev->tbusy (oups !) + * + * Changes made in sixth release (2.9.1a) : + * -------------------------------------- + * - Change the detection code for multi manufacturer code support + * - Correct bug (hang kernel) in init when we were "rejecting" a card + * + * Changes made in seventh release (2.9.1b) : + * ---------------------------------------- + * - Update to wireless extensions changes + * - Silly bug in card initial configuration (psa_conf_status) + * + * Changes made in eigth release : + * ----------------------------- + * - Small bug in debug code (probably not the last one...) + * - 1.2.13 support (thanks to Clark Woodworth) + * + * Changes made for release in 2.9.2b : + * ---------------------------------- + * - Level threshold is now a standard wireless extension (version 4 !) + * - modules parameters types for kernel > 2.1.17 + * - updated man page + * - Others cleanup from David Hinds + * + * Changes made for release in 2.9.5 : + * --------------------------------- + * - byte count stats (courtesy of David Hinds) + * - Remove dev_tint stuff (courtesy of David Hinds) + * - Others cleanup from David Hinds + * - Encryption setting from Brent Elphick (thanks a lot !) + * - 'base' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) + * + * Changes made for release in 2.9.6 : + * --------------------------------- + * - fix bug : no longuer disable watchdog in case of bogus interrupt + * - increase timeout in config code for picky hardware + * - mask unused bits in status (Wireless Extensions) + * + * Changes integrated by Justin Seger & David Hinds : + * ----------------------------------------------------------------- + * - Roaming "hack" from Joe Finney + * - PSA CRC code from Bob Gray + * - Better initialisation of the i82593 controller + * from Joseph K. O'Sullivan + * + * Changes made for release in 3.0.10 : + * ---------------------------------- + * - Fix eject "hang" of the driver under 2.2.X : + * o create wv_flush_stale_links() + * o Rename wavelan_release to wv_pcmcia_release & move up + * o move unregister_netdev to wavelan_detach() + * o wavelan_release() no longer call wavelan_detach() + * o Suppress "release" timer + * o Other cleanups & fixes + * - New MAC address in the probe + * - Reorg PSA_CRC code (endian neutral & cleaner) + * - Correct initialisation of the i82593 from Lucent manual + * - Put back the watchdog, with larger timeout + * - TRANSMIT_NO_CRC is a "normal" error, so recover from it + * from Derrick J Brashear + * - Better handling of TX and RX normal failure conditions + * - #ifdef out all the roaming code + * - Add ESSID & "AP current address" ioctl stubs + * - General cleanup of the code + * + * Changes made for release in 3.0.13 : + * ---------------------------------- + * - Re-enable compilation of roaming code by default, but with + * do_roaming = 0 + * - Nuke `nwid=nwid^ntohs(beacon->domain_id)' in wl_roam_gather + * at the demand of John Carol Langford + * - Introduced WAVELAN_ROAMING_EXT for incomplete ESSID stuff. + * + * Changes made for release in 3.0.15 : + * ---------------------------------- + * - Change e-mail and web page addresses + * - Watchdog timer is now correctly expressed in HZ, not in jiffies + * - Add channel number to the list of frequencies in range + * - Add the (short) list of bit-rates in range + * - Developp a new sensitivity... (sens.value & sens.fixed) + * + * Changes made for release in 3.1.2 : + * --------------------------------- + * - Fix check for root permission (break instead of exit) + * - New nwid & encoding setting (Wireless Extension 9) + * + * Changes made for release in 3.1.12 : + * ---------------------------------- + * - reworked wv_82593_cmd to avoid using the IRQ handler and doing + * ugly things with interrupts. + * - Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog + * - Update to new network API (softnet - 2.3.43) : + * o replace dev->tbusy (David + me) + * o replace dev->tstart (David + me) + * o remove dev->interrupt (David) + * o add SMP locking via spinlock in splxx (me) + * o add spinlock in interrupt handler (me) + * o use kernel watchdog instead of ours (me) + * o verify that all the changes make sense and work (me) + * - Re-sync kernel/pcmcia versions (not much actually) + * - A few other cleanups (David & me)... + * + * Changes made for release in 3.1.22 : + * ---------------------------------- + * - Check that SMP works, remove annoying log message + * + * Changes made for release in 3.1.24 : + * ---------------------------------- + * - Fix unfrequent card lockup when watchdog was reseting the hardware : + * o control first busy loop in wv_82593_cmd() + * o Extend spinlock protection in wv_hw_config() + * + * Wishes & dreams: + * ---------------- + * - Cleanup and integrate the roaming code + * (std debug, set DomainID, decay avg and co...) + */ + +/***************************** INCLUDES *****************************/ + +/* Linux headers that we need */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_NET_PCMCIA_RADIO +#include /* Wireless extensions */ +#endif + +/* Pcmcia headers that we need */ +#include +#include +#include +#include +#include +#include + +/* Wavelan declarations */ +#include "i82593.h" /* Definitions for the Intel chip */ + +#include "wavelan.h" /* Others bits of the hardware */ + +/************************** DRIVER OPTIONS **************************/ +/* + * `#define' or `#undef' the following constant to change the behaviour + * of the driver... + */ +#define WAVELAN_ROAMING /* Include experimental roaming code */ +#undef WAVELAN_ROAMING_EXT /* Enable roaming wireless extensions */ +#undef SET_PSA_CRC /* Set the CRC in PSA (slower) */ +#define USE_PSA_CONFIG /* Use info from the PSA */ +#undef STRUCT_CHECK /* Verify padding of structures */ +#undef EEPROM_IS_PROTECTED /* Doesn't seem to be necessary */ +#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */ +#undef SET_MAC_ADDRESS /* Experimental */ + +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ +/* Warning : these stuff will slow down the driver... */ +#define WIRELESS_SPY /* Enable spying addresses */ +#undef HISTOGRAM /* Enable histogram of sig level... */ +#endif + +/****************************** DEBUG ******************************/ + +#undef DEBUG_MODULE_TRACE /* Module insertion/removal */ +#undef DEBUG_CALLBACK_TRACE /* Calls made by Linux */ +#undef DEBUG_INTERRUPT_TRACE /* Calls to handler */ +#undef DEBUG_INTERRUPT_INFO /* type of interrupt & so on */ +#define DEBUG_INTERRUPT_ERROR /* problems */ +#undef DEBUG_CONFIG_TRACE /* Trace the config functions */ +#undef DEBUG_CONFIG_INFO /* What's going on... */ +#define DEBUG_CONFIG_ERRORS /* Errors on configuration */ +#undef DEBUG_TX_TRACE /* Transmission calls */ +#undef DEBUG_TX_INFO /* Header of the transmitted packet */ +#undef DEBUG_TX_FAIL /* Normal failure conditions */ +#define DEBUG_TX_ERROR /* Unexpected conditions */ +#undef DEBUG_RX_TRACE /* Transmission calls */ +#undef DEBUG_RX_INFO /* Header of the transmitted packet */ +#undef DEBUG_RX_FAIL /* Normal failure conditions */ +#define DEBUG_RX_ERROR /* Unexpected conditions */ +#undef DEBUG_PACKET_DUMP 32 /* Dump packet on the screen */ +#undef DEBUG_IOCTL_TRACE /* Misc call by Linux */ +#undef DEBUG_IOCTL_INFO /* Various debug info */ +#define DEBUG_IOCTL_ERROR /* What's going wrong */ +#define DEBUG_BASIC_SHOW /* Show basic startup info */ +#undef DEBUG_VERSION_SHOW /* Print version info */ +#undef DEBUG_PSA_SHOW /* Dump psa to screen */ +#undef DEBUG_MMC_SHOW /* Dump mmc to screen */ +#undef DEBUG_SHOW_UNUSED /* Show also unused fields */ +#undef DEBUG_I82593_SHOW /* Show i82593 status */ +#undef DEBUG_DEVICE_SHOW /* Show device parameters */ + +/************************ CONSTANTS & MACROS ************************/ + +#ifdef DEBUG_VERSION_SHOW +static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n"; +#endif + +/* Watchdog temporisation */ +#define WATCHDOG_JIFFIES (256*HZ/100) + +/* Fix a bug in some old wireless extension definitions */ +#ifndef IW_ESSID_MAX_SIZE +#define IW_ESSID_MAX_SIZE 32 +#endif + +/* ------------------------ PRIVATE IOCTL ------------------------ */ + +/* Wireless Extension Backward compatibility - Jean II + * If the new wireless device private ioctl range is not defined, + * default to standard device private ioctl range */ +#ifndef SIOCIWFIRSTPRIV +#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE +#endif /* SIOCIWFIRSTPRIV */ + +#define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ +#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ +#define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */ +#define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */ + +#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */ +#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */ + +/*************************** WaveLAN Roaming **************************/ +#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ + +#define WAVELAN_ROAMING_DEBUG 0 /* 1 = Trace of handover decisions */ + /* 2 = Info on each beacon rcvd... */ +#define MAX_WAVEPOINTS 7 /* Max visible at one time */ +#define WAVEPOINT_HISTORY 5 /* SNR sample history slow search */ +#define WAVEPOINT_FAST_HISTORY 2 /* SNR sample history fast search */ +#define SEARCH_THRESH_LOW 10 /* SNR to enter cell search */ +#define SEARCH_THRESH_HIGH 13 /* SNR to leave cell search */ +#define WAVELAN_ROAMING_DELTA 1 /* Hysteresis value (+/- SNR) */ +#define CELL_TIMEOUT 2*HZ /* in jiffies */ + +#define FAST_CELL_SEARCH 1 /* Boolean values... */ +#define NWID_PROMISC 1 /* for code clarity. */ + +typedef struct wavepoint_beacon +{ + unsigned char dsap, /* Unused */ + ssap, /* Unused */ + ctrl, /* Unused */ + O,U,I, /* Unused */ + spec_id1, /* Unused */ + spec_id2, /* Unused */ + pdu_type, /* Unused */ + seq; /* WavePoint beacon sequence number */ + unsigned short domain_id, /* WavePoint Domain ID */ + nwid; /* WavePoint NWID */ +} wavepoint_beacon; + +typedef struct wavepoint_history +{ + unsigned short nwid; /* WavePoint's NWID */ + int average_slow; /* SNR running average */ + int average_fast; /* SNR running average */ + unsigned char sigqual[WAVEPOINT_HISTORY]; /* Ringbuffer of recent SNR's */ + unsigned char qualptr; /* Index into ringbuffer */ + unsigned char last_seq; /* Last seq. no seen for WavePoint */ + struct wavepoint_history *next; /* Next WavePoint in table */ + struct wavepoint_history *prev; /* Previous WavePoint in table */ + unsigned long last_seen; /* Time of last beacon recvd, jiffies */ +} wavepoint_history; + +struct wavepoint_table +{ + wavepoint_history *head; /* Start of ringbuffer */ + int num_wavepoints; /* No. of WavePoints visible */ + unsigned char locked; /* Table lock */ +}; + +#endif /* WAVELAN_ROAMING */ + +/****************************** TYPES ******************************/ + +/* Shortcuts */ +typedef struct net_device device; +typedef struct net_device_stats en_stats; +typedef struct iw_statistics iw_stats; +typedef struct iw_quality iw_qual; +typedef struct iw_freq iw_freq; +typedef struct net_local net_local; +typedef struct timer_list timer_list; + +/* Basic types */ +typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ + +/* + * Static specific data for the interface. + * + * For each network interface, Linux keep data in two structure. "device" + * keep the generic data (same format for everybody) and "net_local" keep + * the additional specific data. + * Note that some of this specific data is in fact generic (en_stats, for + * example). + */ +struct net_local +{ + dev_node_t node; /* ???? What is this stuff ???? */ + device * dev; /* Reverse link... */ + spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ + dev_link_t * link; /* pcmcia structure */ + en_stats stats; /* Ethernet interface statistics */ + int nresets; /* Number of hw resets */ + u_char configured; /* If it is configured */ + u_char reconfig_82593; /* Need to reconfigure the controller */ + u_char promiscuous; /* Promiscuous mode */ + u_char allmulticast; /* All Multicast mode */ + int mc_count; /* Number of multicast addresses */ + + int stop; /* Current i82593 Stop Hit Register */ + int rfp; /* Last DMA machine receive pointer */ + int overrunning; /* Receiver overrun flag */ + +#ifdef WIRELESS_EXT + iw_stats wstats; /* Wireless specific stats */ +#endif + +#ifdef WIRELESS_SPY + int spy_number; /* Number of addresses to spy */ + mac_addr spy_address[IW_MAX_SPY]; /* The addresses to spy */ + iw_qual spy_stat[IW_MAX_SPY]; /* Statistics gathered */ +#endif /* WIRELESS_SPY */ +#ifdef HISTOGRAM + int his_number; /* Number of intervals */ + u_char his_range[16]; /* Boundaries of interval ]n-1; n] */ + u_long his_sum[16]; /* Sum in interval */ +#endif /* HISTOGRAM */ +#ifdef WAVELAN_ROAMING + u_long domain_id; /* Domain ID we lock on for roaming */ + int filter_domains; /* Check Domain ID of beacon found */ + struct wavepoint_table wavepoint_table; /* Table of visible WavePoints*/ + wavepoint_history * curr_point; /* Current wavepoint */ + int cell_search; /* Searching for new cell? */ + struct timer_list cell_timer; /* Garbage collection */ +#endif /* WAVELAN_ROAMING */ +}; + +/**************************** PROTOTYPES ****************************/ + +#ifdef WAVELAN_ROAMING +/* ---------------------- ROAMING SUBROUTINES -----------------------*/ + +wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp); +wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local *lp); +void wl_del_wavepoint(wavepoint_history *wavepoint, net_local *lp); +void wl_cell_expiry(unsigned long data); +wavepoint_history *wl_best_sigqual(int fast_search, net_local *lp); +void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq); +void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp); +void wv_nwid_filter(unsigned char mode, net_local *lp); +void wv_roam_init(struct net_device *dev); +void wv_roam_cleanup(struct net_device *dev); +#endif /* WAVELAN_ROAMING */ + +/* ----------------------- MISC SUBROUTINES ------------------------ */ +static inline void + wv_splhi(net_local *, /* Disable interrupts */ + unsigned long *); /* flags */ +static inline void + wv_splx(net_local *, /* ReEnable interrupts */ + unsigned long *); /* flags */ +static void + cs_error(client_handle_t, /* Report error to cardmgr */ + int, + int); +/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ +static inline u_char /* data */ + hasr_read(u_long); /* Read the host interface : base address */ +static inline void + hacr_write(u_long, /* Write to host interface : base address */ + u_char), /* data */ + hacr_write_slow(u_long, + u_char); +static void + psa_read(device *, /* Read the Parameter Storage Area */ + int, /* offset in PSA */ + u_char *, /* buffer to fill */ + int), /* size to read */ + psa_write(device *, /* Write to the PSA */ + int, /* Offset in psa */ + u_char *, /* Buffer in memory */ + int); /* Length of buffer */ +static inline void + mmc_out(u_long, /* Write 1 byte to the Modem Manag Control */ + u_short, + u_char), + mmc_write(u_long, /* Write n bytes to the MMC */ + u_char, + u_char *, + int); +static inline u_char /* Read 1 byte from the MMC */ + mmc_in(u_long, + u_short); +static inline void + mmc_read(u_long, /* Read n bytes from the MMC */ + u_char, + u_char *, + int), + fee_wait(u_long, /* Wait for frequency EEprom : base address */ + int, /* Base delay to wait for */ + int); /* Number of time to wait */ +static void + fee_read(u_long, /* Read the frequency EEprom : base address */ + u_short, /* destination offset */ + u_short *, /* data buffer */ + int); /* number of registers */ +/* ---------------------- I82593 SUBROUTINES ----------------------- */ +static int + wv_82593_cmd(device *, /* synchronously send a command to i82593 */ + char *, + int, + int); +static inline int + wv_diag(device *); /* Diagnostique the i82593 */ +static int + read_ringbuf(device *, /* Read a receive buffer */ + int, + char *, + int); +static inline void + wv_82593_reconfig(device *); /* Reconfigure the controller */ +/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ +static inline void + wv_init_info(device *); /* display startup info */ +/* ------------------- IOCTL, STATS & RECONFIG ------------------- */ +static en_stats * + wavelan_get_stats(device *); /* Give stats /proc/net/dev */ +/* ----------------------- PACKET RECEPTION ----------------------- */ +static inline int + wv_start_of_frame(device *, /* Seek beggining of current frame */ + int, /* end of frame */ + int); /* start of buffer */ +static inline void + wv_packet_read(device *, /* Read a packet from a frame */ + int, + int), + wv_packet_rcv(device *); /* Read all packets waiting */ +/* --------------------- PACKET TRANSMISSION --------------------- */ +static inline void + wv_packet_write(device *, /* Write a packet to the Tx buffer */ + void *, + short); +static int + wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ + device *); +/* -------------------- HARDWARE CONFIGURATION -------------------- */ +static inline int + wv_mmc_init(device *); /* Initialize the modem */ +static int + wv_ru_stop(device *), /* Stop the i82593 receiver unit */ + wv_ru_start(device *); /* Start the i82593 receiver unit */ +static int + wv_82593_config(device *); /* Configure the i82593 */ +static inline int + wv_pcmcia_reset(device *); /* Reset the pcmcia interface */ +static int + wv_hw_config(device *); /* Reset & configure the whole hardware */ +static inline void + wv_hw_reset(device *); /* Same, + start receiver unit */ +static inline int + wv_pcmcia_config(dev_link_t *); /* Configure the pcmcia interface */ +static void + wv_pcmcia_release(u_long), /* Remove a device */ + wv_flush_stale_links(void); /* "detach" all possible devices */ +/* ---------------------- INTERRUPT HANDLING ---------------------- */ +static void + wavelan_interrupt(int, /* Interrupt handler */ + void *, + struct pt_regs *); +static void + wavelan_watchdog(device *); /* Transmission watchdog */ +/* ------------------- CONFIGURATION CALLBACKS ------------------- */ +static int + wavelan_open(device *), /* Open the device */ + wavelan_close(device *); /* Close the device */ +static dev_link_t * + wavelan_attach(void); /* Create a new device */ +static void + wavelan_detach(dev_link_t *); /* Destroy a removed device */ +static int + wavelan_event(event_t, /* Manage pcmcia events */ + int, + event_callback_args_t *); + +/**************************** VARIABLES ****************************/ + +static dev_info_t dev_info = "wavelan_cs"; +static dev_link_t *dev_list = NULL; /* Linked list of devices */ + +/* + * Parameters that can be set with 'insmod' + * The exact syntax is 'insmod wavelan_cs.o =' + */ + +/* Bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4 and 3 */ +static int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +/* Shared memory speed, in ns */ +static int mem_speed = 0; + +/* New module interface */ +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(mem_speed, "i"); + +#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ +/* Enable roaming mode ? No ! Please keep this to 0 */ +static int do_roaming = 0; +MODULE_PARM(do_roaming, "i"); +#endif /* WAVELAN_ROAMING */ + +MODULE_LICENSE("GPL"); + +#endif /* WAVELAN_CS_H */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pcmcia/xircom_cb.c linux-2.5/drivers/net/pcmcia/xircom_cb.c --- linux-2.5.5/drivers/net/pcmcia/xircom_cb.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/net/pcmcia/xircom_cb.c Fri Jan 18 22:19:46 2002 @@ -170,7 +170,7 @@ name: "xircom_cb", id_table: xircom_pci_table, probe: xircom_probe, - remove: xircom_remove, + remove: __devexit_p(xircom_remove), }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pcmcia/xircom_tulip_cb.c linux-2.5/drivers/net/pcmcia/xircom_tulip_cb.c --- linux-2.5.5/drivers/net/pcmcia/xircom_tulip_cb.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/net/pcmcia/xircom_tulip_cb.c Fri Jan 18 22:19:46 2002 @@ -1709,7 +1709,7 @@ name: DRV_NAME, id_table: xircom_pci_table, probe: xircom_init_one, - remove: xircom_remove_one, + remove: __devexit_p(xircom_remove_one), #ifdef CONFIG_PM suspend: xircom_suspend, resume: xircom_resume diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pcnet32.c linux-2.5/drivers/net/pcnet32.c --- linux-2.5.5/drivers/net/pcnet32.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/pcnet32.c Sun Mar 3 20:15:15 2002 @@ -22,8 +22,9 @@ *************************************************************************/ #define DRV_NAME "pcnet32" -#define DRV_VERSION "1.25kf" -#define DRV_RELDATE "17.11.2001" +#define DRV_VERSION "1.27a" +#define DRV_RELDATE "10.02.2002" +#define PFX DRV_NAME ": " static const char *version = DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n"; @@ -54,8 +55,6 @@ #include #include -static unsigned int pcnet32_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0}; - /* * PCI device identifiers for "new style" Linux PCI Device Drivers */ @@ -65,13 +64,26 @@ { 0, } }; +MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl); + +int cards_found __initdata; + +/* + * VLB I/O addresses + */ +static unsigned int pcnet32_portlist[] __initdata = + { 0x300, 0x320, 0x340, 0x360, 0 }; + + + static int pcnet32_debug = 1; static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */ +static int pcnet32vlb; /* check for VLB cards ? */ static struct net_device *pcnet32_dev; -static const int max_interrupt_work = 80; -static const int rx_copybreak = 200; +static int max_interrupt_work = 80; +static int rx_copybreak = 200; #define PCNET32_PORT_AUI 0x00 #define PCNET32_PORT_10BT 0x01 @@ -94,21 +106,21 @@ PCNET32_PORT_AUI, /* 1 BNC/AUI */ PCNET32_PORT_AUI, /* 2 AUI/BNC */ PCNET32_PORT_ASEL, /* 3 not supported */ - PCNET32_PORT_10BT | PCNET32_PORT_FD, /* 4 10baseT-FD */ + PCNET32_PORT_10BT | PCNET32_PORT_FD, /* 4 10baseT-FD */ PCNET32_PORT_ASEL, /* 5 not supported */ PCNET32_PORT_ASEL, /* 6 not supported */ PCNET32_PORT_ASEL, /* 7 not supported */ PCNET32_PORT_ASEL, /* 8 not supported */ PCNET32_PORT_MII, /* 9 MII 10baseT */ - PCNET32_PORT_MII | PCNET32_PORT_FD, /* 10 MII 10baseT-FD */ + PCNET32_PORT_MII | PCNET32_PORT_FD, /* 10 MII 10baseT-FD */ PCNET32_PORT_MII, /* 11 MII (autosel) */ PCNET32_PORT_10BT, /* 12 10BaseT */ - PCNET32_PORT_MII | PCNET32_PORT_100, /* 13 MII 100BaseTx */ + PCNET32_PORT_MII | PCNET32_PORT_100, /* 13 MII 100BaseTx */ PCNET32_PORT_MII | PCNET32_PORT_100 | PCNET32_PORT_FD, /* 14 MII 100BaseTx-FD */ PCNET32_PORT_ASEL /* 15 not supported */ }; -#define MAX_UNITS 8 +#define MAX_UNITS 8 /* More are supported, limit only on options */ static int options[MAX_UNITS]; static int full_duplex[MAX_UNITS]; @@ -187,7 +199,19 @@ * v1.25kf Added No Interrupt on successful Tx for some Tx's * v1.26 Converted to pci_alloc_consistent, Jamey Hicks / George France * - * v1.26p Fix oops on rmmod+insmod; plug i/o resource leak - Paul Gortmaker + * - Fixed a few bugs, related to running the controller in 32bit mode. + * 23 Oct, 2000. Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * v1.26p Fix oops on rmmod+insmod; plug i/o resource leak - Paul Gortmaker + * v1.27 improved CSR/PROM address detection, lots of cleanups, + * new pcnet32vlb module option, HP-PARISC support, + * added module parameter descriptions, + * initial ethtool support - Helge Deller + * v1.27a Sun Feb 10 2002 Go Taniguchi + * use alloc_etherdev and register_netdev + * fix pci probe not increment cards_found + * FD auto negotiate error workaround for xSeries250 + * clean up and using new mii module */ @@ -201,13 +225,13 @@ #define PCNET32_LOG_RX_BUFFERS 5 #endif -#define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS)) -#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) -#define TX_RING_LEN_BITS ((PCNET32_LOG_TX_BUFFERS) << 12) - -#define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS)) -#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) -#define RX_RING_LEN_BITS ((PCNET32_LOG_RX_BUFFERS) << 4) +#define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS)) +#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) +#define TX_RING_LEN_BITS ((PCNET32_LOG_TX_BUFFERS) << 12) + +#define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS)) +#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) +#define RX_RING_LEN_BITS ((PCNET32_LOG_RX_BUFFERS) << 4) #define PKT_BUF_SZ 1544 @@ -222,7 +246,7 @@ #define PCNET32_DWIO_RESET 0x18 #define PCNET32_DWIO_BDP 0x1C -#define PCNET32_TOTAL_SIZE 0x20 +#define PCNET32_TOTAL_SIZE 0x20 /* The PCNET32 Rx and Tx ring descriptors. */ struct pcnet32_rx_head { @@ -270,37 +294,36 @@ */ struct pcnet32_private { /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ - struct pcnet32_rx_head rx_ring[RX_RING_SIZE]; - struct pcnet32_tx_head tx_ring[TX_RING_SIZE]; - struct pcnet32_init_block init_block; - dma_addr_t dma_addr; /* DMA address of beginning of this object, returned by pci_alloc_consistent */ - struct pci_dev *pci_dev; /* Pointer to the associated pci device structure */ - const char *name; + struct pcnet32_rx_head rx_ring[RX_RING_SIZE]; + struct pcnet32_tx_head tx_ring[TX_RING_SIZE]; + struct pcnet32_init_block init_block; + dma_addr_t dma_addr; /* DMA address of beginning of this object, + returned by pci_alloc_consistent */ + struct pci_dev *pci_dev; /* Pointer to the associated pci device structure */ + const char *name; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - dma_addr_t tx_dma_addr[TX_RING_SIZE]; - dma_addr_t rx_dma_addr[RX_RING_SIZE]; + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + dma_addr_t tx_dma_addr[TX_RING_SIZE]; + dma_addr_t rx_dma_addr[RX_RING_SIZE]; struct pcnet32_access a; - spinlock_t lock; /* Guard lock */ - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + spinlock_t lock; /* Guard lock */ + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ struct net_device_stats stats; - char tx_full; - int options; - int shared_irq:1, /* shared irq possible */ - ltint:1, -#ifdef DO_DXSUFLO - dxsuflo:1, /* disable transmit stop on uflo */ -#endif - mii:1; /* mii port available */ - struct net_device *next; + char tx_full; + int options; + int shared_irq:1, /* shared irq possible */ + ltint:1, /* enable TxDone-intr inhibitor */ + dxsuflo:1, /* disable transmit stop on uflo */ + mii:1; /* mii port available */ + struct net_device *next; struct mii_if_info mii_if; }; -static int pcnet32_probe_vlbus(int cards_found); +static void pcnet32_probe_vlbus(void); static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); -static int pcnet32_probe1(unsigned long, unsigned char, int, int, struct pci_dev *); +static int pcnet32_probe1(unsigned long, unsigned char, int, struct pci_dev *); static int pcnet32_open(struct net_device *); static int pcnet32_init_ring(struct net_device *); static int pcnet32_start_xmit(struct sk_buff *, struct net_device *); @@ -319,15 +342,6 @@ PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, }; -struct pcnet32_pci_id_info { - const char *name; - u16 vendor_id, device_id, svid, sdid, flags; - int io_size; - int (*probe1) (unsigned long, unsigned char, int, int, struct pci_dev *); -}; - - -MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl); static u16 pcnet32_wio_read_csr (unsigned long addr, int index) { @@ -375,13 +389,13 @@ } static struct pcnet32_access pcnet32_wio = { - pcnet32_wio_read_csr, - pcnet32_wio_write_csr, - pcnet32_wio_read_bcr, - pcnet32_wio_write_bcr, - pcnet32_wio_read_rap, - pcnet32_wio_write_rap, - pcnet32_wio_reset + read_csr: pcnet32_wio_read_csr, + write_csr: pcnet32_wio_write_csr, + read_bcr: pcnet32_wio_read_bcr, + write_bcr: pcnet32_wio_write_bcr, + read_rap: pcnet32_wio_read_rap, + write_rap: pcnet32_wio_write_rap, + reset: pcnet32_wio_reset }; static u16 pcnet32_dwio_read_csr (unsigned long addr, int index) @@ -430,82 +444,61 @@ } static struct pcnet32_access pcnet32_dwio = { - pcnet32_dwio_read_csr, - pcnet32_dwio_write_csr, - pcnet32_dwio_read_bcr, - pcnet32_dwio_write_bcr, - pcnet32_dwio_read_rap, - pcnet32_dwio_write_rap, - pcnet32_dwio_reset - + read_csr: pcnet32_dwio_read_csr, + write_csr: pcnet32_dwio_write_csr, + read_bcr: pcnet32_dwio_read_bcr, + write_bcr: pcnet32_dwio_write_bcr, + read_rap: pcnet32_dwio_read_rap, + write_rap: pcnet32_dwio_write_rap, + reset: pcnet32_dwio_reset }; - -/* only probes for non-PCI devices, the rest are handled by pci_register_driver via pcnet32_probe_pci*/ -static int __init pcnet32_probe_vlbus(int cards_found) + +/* only probes for non-PCI devices, the rest are handled by + * pci_register_driver via pcnet32_probe_pci */ + +static void __devinit +pcnet32_probe_vlbus(void) { - unsigned long ioaddr = 0; // FIXME dev ? dev->base_addr: 0; - unsigned int irq_line = 0; // FIXME dev ? dev->irq : 0; - int *port; + unsigned int *port, ioaddr; - printk(KERN_INFO "pcnet32_probe_vlbus: cards_found=%d\n", cards_found); -#ifndef __powerpc__ - if (ioaddr > 0x1ff) { - if (check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) - return pcnet32_probe1(ioaddr, irq_line, 0, 0, NULL); - else - return -ENODEV; - } else -#endif - if (ioaddr != 0) - return -ENXIO; - - /* now look for PCnet32 VLB cards */ - for (port = pcnet32_portlist; *port; port++) { - unsigned long ioaddr = *port; - - if ( check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) { + /* search for PCnet32 VLB cards at known addresses */ + for (port = pcnet32_portlist; (ioaddr = *port); port++) { + if (!check_region(ioaddr, PCNET32_TOTAL_SIZE)) { /* check if there is really a pcnet chip on that ioaddr */ - if ((inb(ioaddr + 14) == 0x57) && - (inb(ioaddr + 15) == 0x57) && - (pcnet32_probe1(ioaddr, 0, 0, 0, NULL) == 0)) - cards_found++; + if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57)) + pcnet32_probe1(ioaddr, 0, 0, NULL); } } - return cards_found ? 0: -ENODEV; } - static int __devinit pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent) { - static int card_idx; - long ioaddr; - int err = 0; - - printk(KERN_INFO "pcnet32_probe_pci: found device %#08x.%#08x\n", ent->vendor, ent->device); + unsigned long ioaddr; + int err; - if ((err = pci_enable_device(pdev)) < 0) { - printk(KERN_ERR "pcnet32.c: failed to enable device -- err=%d\n", err); + err = pci_enable_device(pdev); + if (err < 0) { + printk(KERN_ERR PFX "failed to enable device -- err=%d\n", err); return err; } pci_set_master(pdev); ioaddr = pci_resource_start (pdev, 0); - printk(KERN_INFO " ioaddr=%#08lx resource_flags=%#08lx\n", ioaddr, pci_resource_flags (pdev, 0)); if (!ioaddr) { - printk (KERN_ERR "no PCI IO resources, aborting\n"); + printk (KERN_ERR PFX "card has no PCI IO resources, aborting\n"); return -ENODEV; } - + if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) { - printk(KERN_ERR "pcnet32.c: architecture does not support 32bit PCI busmaster DMA\n"); + printk(KERN_ERR PFX "architecture does not support 32bit PCI busmaster DMA\n"); return -ENODEV; } - return pcnet32_probe1(ioaddr, pdev->irq, 1, card_idx, pdev); + return pcnet32_probe1(ioaddr, pdev->irq, 1, pdev); } @@ -514,41 +507,43 @@ * pdev will be NULL when called from pcnet32_probe_vlbus. */ static int __devinit -pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx, struct pci_dev *pdev) +pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, + struct pci_dev *pdev) { struct pcnet32_private *lp; - struct resource *res; dma_addr_t lp_dma_addr; - int i,media,fdx = 0, mii = 0, fset = 0; -#ifdef DO_DXSUFLO - int dxsuflo = 0; -#endif - int ltint = 0; + int i, media; + int fdx, mii, fset, dxsuflo, ltint; int chip_version; char *chipname; struct net_device *dev; struct pcnet32_access *a = NULL; + u8 promaddr[6]; /* reset the chip */ pcnet32_dwio_reset(ioaddr); pcnet32_wio_reset(ioaddr); /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */ - if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) { + if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && pcnet32_wio_check(ioaddr)) { a = &pcnet32_wio; } else { - if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { + if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { a = &pcnet32_dwio; } else return -ENODEV; } - chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16); + chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr,89) << 16); if (pcnet32_debug > 2) printk(KERN_INFO " PCnet chip version is %#x.\n", chip_version); if ((chip_version & 0xfff) != 0x003) return -ENODEV; + + /* initialize variables */ + fdx = mii = fset = dxsuflo = ltint = 0; chip_version = (chip_version >> 12) & 0xffff; + switch (chip_version) { case 0x2420: chipname = "PCnet/PCI 79C970"; /* PCI */ @@ -587,23 +582,24 @@ * mode by which the card should operate */ /* switch to home wiring mode */ - media = a->read_bcr (ioaddr, 49); + media = a->read_bcr(ioaddr, 49); #if 0 if (pcnet32_debug > 2) - printk(KERN_DEBUG "pcnet32: pcnet32 media value %#x.\n", media); + printk(KERN_DEBUG PFX "media value %#x.\n", media); media &= ~3; media |= 1; #endif if (pcnet32_debug > 2) - printk(KERN_DEBUG "pcnet32: pcnet32 media reset to %#x.\n", media); - a->write_bcr (ioaddr, 49, media); + printk(KERN_DEBUG PFX "media reset to %#x.\n", media); + a->write_bcr(ioaddr, 49, media); break; case 0x2627: chipname = "PCnet/FAST III 79C975"; /* PCI */ fdx = 1; mii = 1; break; default: - printk(KERN_INFO "pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version); + printk(KERN_INFO PFX "PCnet version %#x, no PCnet32 chip.\n", + chip_version); return -ENODEV; } @@ -618,17 +614,15 @@ { a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800)); a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00); -#ifdef DO_DXSUFLO dxsuflo = 1; -#endif ltint = 1; } - dev = init_etherdev(NULL, 0); - if(dev==NULL) + dev = alloc_etherdev(0); + if(!dev) return -ENOMEM; - printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr); + printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr); /* In most chips, after a chip reset, the ethernet address is read from the * station address PROM at the base address and programmed into the @@ -644,31 +638,28 @@ dev->dev_addr[2*i] = val & 0x0ff; dev->dev_addr[2*i+1] = (val >> 8) & 0x0ff; } - { - u8 promaddr[6]; - for (i = 0; i < 6; i++) { - promaddr[i] = inb(ioaddr + i); - } - if( memcmp( promaddr, dev->dev_addr, 6) ) - { - printk(" warning PROM address does not match CSR address\n"); -#if defined(__i386__) - printk(KERN_WARNING "%s: Probably a Compaq, using the PROM address of", dev->name); - memcpy(dev->dev_addr, promaddr, 6); -#elif defined(__powerpc__) - if (!is_valid_ether_addr(dev->dev_addr) - && is_valid_ether_addr(promaddr)) { - printk("\n" KERN_WARNING "%s: using PROM address:", - dev->name); - memcpy(dev->dev_addr, promaddr, 6); - } + + /* read PROM address and compare with CSR address */ + for (i = 0; i < 6; i++) + promaddr[i] = inb(ioaddr + i); + + if( memcmp( promaddr, dev->dev_addr, 6) + || !is_valid_ether_addr(dev->dev_addr) ) { +#ifndef __powerpc__ + if( is_valid_ether_addr(promaddr) ){ +#else + if( !is_valid_ether_addr(dev->dev_addr) + && is_valid_ether_addr(promaddr)) { #endif - } + printk(" warning: CSR address invalid,\n"); + printk(KERN_INFO " using instead PROM address of"); + memcpy(dev->dev_addr, promaddr, 6); + } } + /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */ if( !is_valid_ether_addr(dev->dev_addr) ) - for (i = 0; i < 6; i++) - dev->dev_addr[i]=0; + memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); for (i = 0; i < 6; i++) printk(" %2.2x", dev->dev_addr[i] ); @@ -697,20 +688,18 @@ } dev->base_addr = ioaddr; - res = request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname); - if (res == NULL) + if (request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname) == NULL) return -EBUSY; /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) { - release_resource(res); + release_region(ioaddr, PCNET32_TOTAL_SIZE); return -ENOMEM; } memset(lp, 0, sizeof(*lp)); lp->dma_addr = lp_dma_addr; lp->pci_dev = pdev; - printk("\n" KERN_INFO "pcnet32: pcnet32_private lp=%p lp_dma_addr=%#08x", lp, lp_dma_addr); spin_lock_init(&lp->lock); @@ -718,26 +707,25 @@ lp->name = chipname; lp->shared_irq = shared; lp->mii_if.full_duplex = fdx; -#ifdef DO_DXSUFLO lp->dxsuflo = dxsuflo; -#endif lp->ltint = ltint; lp->mii = mii; - if (options[card_idx] > sizeof (options_mapping)) + if ((cards_found >= MAX_UNITS) || (options[cards_found] > sizeof(options_mapping))) lp->options = PCNET32_PORT_ASEL; else - lp->options = options_mapping[options[card_idx]]; + lp->options = options_mapping[options[cards_found]]; lp->mii_if.dev = dev; lp->mii_if.mdio_read = mdio_read; lp->mii_if.mdio_write = mdio_write; - if (fdx && !(lp->options & PCNET32_PORT_ASEL) && full_duplex[card_idx]) + if (fdx && !(lp->options & PCNET32_PORT_ASEL) && + ((cards_found>=MAX_UNITS) || full_duplex[cards_found])) lp->options |= PCNET32_PORT_FD; - if (a == NULL) { - printk(KERN_ERR "pcnet32: No access methods\n"); + if (!a) { + printk(KERN_ERR PFX "No access methods\n"); pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); - release_resource(res); + release_region(ioaddr, PCNET32_TOTAL_SIZE); return -ENODEV; } lp->a = *a; @@ -785,13 +773,11 @@ else { printk(", failed to detect IRQ line.\n"); pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); - release_resource(res); + release_region(ioaddr, PCNET32_TOTAL_SIZE); return -ENODEV; } } - if (pcnet32_debug > 0) - printk(KERN_INFO "%s", version); /* The PCNET32-specific entries in the device structure. */ dev->open = &pcnet32_open; @@ -807,11 +793,13 @@ pcnet32_dev = dev; /* Fill in the generic fields of the device structure. */ - ether_setup(dev); + register_netdev(dev); + printk(KERN_INFO "%s: registered as %s\n",dev->name, lp->name); + cards_found++; return 0; } - + static int pcnet32_open(struct net_device *dev) { @@ -856,6 +844,9 @@ val |= 1; if (lp->options == (PCNET32_PORT_FD | PCNET32_PORT_AUI)) val |= 2; + } else if (lp->options & PCNET32_PORT_ASEL) { + /* workaround for xSeries250 */ + val |= 3; } lp->a.write_bcr (ioaddr, 9, val); } @@ -888,6 +879,7 @@ lp->a.write_csr (ioaddr, 3, val); } #endif + if (lp->ltint) { /* Enable TxDone-intr inhibitor */ val = lp->a.read_csr (ioaddr, 5); val |= (1<<14); @@ -922,7 +914,7 @@ if (pcnet32_debug > 2) printk(KERN_DEBUG "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n", dev->name, i, (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block)), - lp->a.read_csr (ioaddr, 0)); + lp->a.read_csr(ioaddr, 0)); MOD_INC_USE_COUNT; @@ -1032,7 +1024,7 @@ /* Transmitter timeout, serious problems. */ printk(KERN_ERR "%s: transmit timed out, status %4.4x, resetting.\n", - dev->name, lp->a.read_csr (ioaddr, 0)); + dev->name, lp->a.read_csr(ioaddr, 0)); lp->a.write_csr (ioaddr, 0, 0x0004); lp->stats.tx_errors++; if (pcnet32_debug > 2) { @@ -1068,7 +1060,7 @@ if (pcnet32_debug > 3) { printk(KERN_DEBUG "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", - dev->name, lp->a.read_csr (ioaddr, 0)); + dev->name, lp->a.read_csr(ioaddr, 0)); } spin_lock_irqsave(&lp->lock, flags); @@ -1135,8 +1127,9 @@ int boguscnt = max_interrupt_work; int must_restart; - if (dev == NULL) { - printk (KERN_DEBUG "pcnet32_interrupt(): irq %d for unknown device.\n", irq); + if (!dev) { + printk (KERN_DEBUG "%s(): irq %d for unknown device\n", + __FUNCTION__, irq); return; } @@ -1207,7 +1200,8 @@ /* We must free the original skb */ if (lp->tx_skbuff[entry]) { - pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry], lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); + pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry], + lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq(lp->tx_skbuff[entry]); lp->tx_skbuff[entry] = 0; lp->tx_dma_addr[entry] = 0; @@ -1215,13 +1209,12 @@ dirty_tx++; } -#ifndef final_version if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { - printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dirty_tx, lp->cur_tx, lp->tx_full); + printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, lp->cur_tx, lp->tx_full); dirty_tx += TX_RING_SIZE; } -#endif + if (lp->tx_full && netif_queue_stopped(dev) && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { @@ -1262,7 +1255,7 @@ /* Clear any other interrupt, and set interrupt enable. */ lp->a.write_csr (ioaddr, 0, 0x7940); - lp->a.write_rap(ioaddr,rap); + lp->a.write_rap (ioaddr,rap); if (pcnet32_debug > 4) printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n", @@ -1315,7 +1308,9 @@ skb_put (skb, pkt_len); lp->rx_skbuff[entry] = newskb; newskb->dev = dev; - lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->tail, newskb->len, PCI_DMA_FROMDEVICE); + lp->rx_dma_addr[entry] = + pci_map_single(lp->pci_dev, newskb->tail, + newskb->len, PCI_DMA_FROMDEVICE); lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]); rx_in_place = 1; } else @@ -1349,6 +1344,7 @@ lp->stats.rx_bytes += skb->len; skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); + dev->last_rx = jiffies; lp->stats.rx_packets++; } } @@ -1445,13 +1441,13 @@ /* set all multicast bits */ if (dev->flags & IFF_ALLMULTI){ - ib->filter [0] = 0xffffffff; - ib->filter [1] = 0xffffffff; + ib->filter[0] = 0xffffffff; + ib->filter[1] = 0xffffffff; return; } /* clear the multicast filter */ - ib->filter [0] = 0; - ib->filter [1] = 0; + ib->filter[0] = 0; + ib->filter[1] = 0; /* Add addresses */ for (i = 0; i < dev->mc_count; i++){ @@ -1648,20 +1644,28 @@ } return -EOPNOTSUPP; } - + static struct pci_driver pcnet32_driver = { - name: DRV_NAME, - probe: pcnet32_probe_pci, - remove: NULL, - id_table: pcnet32_pci_tbl, + name: DRV_NAME, + probe: pcnet32_probe_pci, + id_table: pcnet32_pci_tbl, }; MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, DRV_NAME " debug level (0-6)"); MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM_DESC(max_interrupt_work, DRV_NAME " maximum events handled per interrupt"); MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM_DESC(rx_copybreak, DRV_NAME " copy breakpoint for copy-only-tiny-frames"); MODULE_PARM(tx_start_pt, "i"); +MODULE_PARM_DESC(tx_start_pt, DRV_NAME " transmit start point (0-3)"); +MODULE_PARM(pcnet32vlb, "i"); +MODULE_PARM_DESC(pcnet32vlb, DRV_NAME " Vesa local bus (VLB) support (0/1)"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM_DESC(options, DRV_NAME " initial option setting(s) (0-15)"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM_DESC(full_duplex, DRV_NAME " full duplex setting(s) (1)"); + MODULE_AUTHOR("Thomas Bogendoerfer"); MODULE_DESCRIPTION("Driver for PCnet32 and PCnetPCI based ethercards"); MODULE_LICENSE("GPL"); @@ -1672,36 +1676,25 @@ static int __init pcnet32_init_module(void) { - int cards_found = 0; - int err; + printk(KERN_INFO "%s", version); if (debug > 0) pcnet32_debug = debug; + if ((tx_start_pt >= 0) && (tx_start_pt <= 3)) tx_start = tx_start_pt; - - pcnet32_dev = NULL; + /* find the PCI devices */ -#define USE_PCI_REGISTER_DRIVER -#ifdef USE_PCI_REGISTER_DRIVER - if ((err = pci_module_init(&pcnet32_driver)) < 0 ) - return err; -#else - { - struct pci_device_id *devid = pcnet32_pci_tbl; - for (devid = pcnet32_pci_tbl; devid != NULL && devid->vendor != 0; devid++) { - struct pci_dev *pdev = pci_find_subsys(devid->vendor, devid->device, devid->subvendor, devid->subdevice, NULL); - if (pdev != NULL) { - if (pcnet32_probe_pci(pdev, devid) >= 0) { - cards_found++; - } - } - } - } -#endif - return 0; - /* find any remaining VLbus devices */ - return pcnet32_probe_vlbus(cards_found); + pci_module_init(&pcnet32_driver); + + /* should we find any remaining VLbus devices ? */ + if (pcnet32vlb) + pcnet32_probe_vlbus(); + + if (cards_found) + printk(KERN_INFO PFX "%d cards_found.\n", cards_found); + + return cards_found ? 0 : -ENODEV; } static void __exit pcnet32_cleanup_module(void) @@ -1710,13 +1703,13 @@ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (pcnet32_dev) { - struct pcnet32_private *lp = pcnet32_dev->priv; + struct pcnet32_private *lp = pcnet32_dev->priv; next_dev = lp->next; unregister_netdev(pcnet32_dev); release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); - if (lp->pci_dev != NULL) + if (lp->pci_dev) pci_unregister_driver(&pcnet32_driver); - pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); + pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); kfree(pcnet32_dev); pcnet32_dev = next_dev; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/ppp_async.c linux-2.5/drivers/net/ppp_async.c --- linux-2.5.5/drivers/net/ppp_async.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/net/ppp_async.c Fri Feb 8 02:38:26 2002 @@ -17,7 +17,7 @@ * PPP driver, written by Michael Callahan and Al Longyear, and * subsequently hacked by Paul Mackerras. * - * ==FILEVERSION 20000227== + * ==FILEVERSION 20020125== */ #include @@ -33,7 +33,7 @@ #include #include -#define PPP_VERSION "2.4.1" +#define PPP_VERSION "2.4.2" #define OBUFSIZE 256 @@ -62,6 +62,8 @@ struct sk_buff *rpkt; int lcp_fcs; + atomic_t refcnt; + struct semaphore dead_sem; struct ppp_channel chan; /* interface to generic ppp layer */ unsigned char obuf[OBUFSIZE]; }; @@ -108,6 +110,35 @@ */ /* + * We have a potential race on dereferencing tty->disc_data, + * because the tty layer provides no locking at all - thus one + * cpu could be running ppp_asynctty_receive while another + * calls ppp_asynctty_close, which zeroes tty->disc_data and + * frees the memory that ppp_asynctty_receive is using. The best + * way to fix this is to use a rwlock in the tty struct, but for now + * we use a single global rwlock for all ttys in ppp line discipline. + */ +static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; + +static struct asyncppp *ap_get(struct tty_struct *tty) +{ + struct asyncppp *ap; + + read_lock(&disc_data_lock); + ap = tty->disc_data; + if (ap != NULL) + atomic_inc(&ap->refcnt); + read_unlock(&disc_data_lock); + return ap; +} + +static void ap_put(struct asyncppp *ap) +{ + if (atomic_dec_and_test(&ap->refcnt)) + up(&ap->dead_sem); +} + +/* * Called when a tty is put into PPP line discipline. */ static int @@ -135,6 +166,9 @@ ap->olim = ap->obuf; ap->lcp_fcs = -1; + atomic_set(&ap->refcnt, 1); + init_MUTEX_LOCKED(&ap->dead_sem); + ap->chan.private = ap; ap->chan.ops = &async_ops; ap->chan.mtu = PPP_MRU; @@ -155,19 +189,34 @@ /* * Called when the tty is put into another line discipline - * or it hangs up. - * We assume that while we are in this routine, the tty layer - * won't call any of the other line discipline entries for the - * same tty. + * or it hangs up. We have to wait for any cpu currently + * executing in any of the other ppp_asynctty_* routines to + * finish before we can call ppp_unregister_channel and free + * the asyncppp struct. This routine must be called from + * process context, not interrupt or softirq context. */ static void ppp_asynctty_close(struct tty_struct *tty) { - struct asyncppp *ap = tty->disc_data; + struct asyncppp *ap; + write_lock(&disc_data_lock); + ap = tty->disc_data; + tty->disc_data = 0; + write_unlock(&disc_data_lock); if (ap == 0) return; - tty->disc_data = 0; + + /* + * We have now ensured that nobody can start using ap from now + * on, but we have to wait for all existing users to finish. + * Note that ppp_unregister_channel ensures that no calls to + * our channel ops (i.e. ppp_async_send/ioctl) are in progress + * by the time it returns. + */ + if (!atomic_dec_and_test(&ap->refcnt)) + down(&ap->dead_sem); + ppp_unregister_channel(&ap->chan); if (ap->rpkt != 0) kfree_skb(ap->rpkt); @@ -203,9 +252,11 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct asyncppp *ap = tty->disc_data; + struct asyncppp *ap = ap_get(tty); int err, val; + if (ap == 0) + return -ENXIO; err = -EFAULT; switch (cmd) { case PPPIOCGCHAN: @@ -251,6 +302,7 @@ err = -ENOIOCTLCMD; } + ap_put(ap); return err; } @@ -271,13 +323,14 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf, char *flags, int count) { - struct asyncppp *ap = tty->disc_data; + struct asyncppp *ap = ap_get(tty); if (ap == 0) return; spin_lock_bh(&ap->recv_lock); ppp_async_input(ap, buf, flags, count); spin_unlock_bh(&ap->recv_lock); + ap_put(ap); if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && tty->driver.unthrottle) tty->driver.unthrottle(tty); @@ -286,13 +339,14 @@ static void ppp_asynctty_wakeup(struct tty_struct *tty) { - struct asyncppp *ap = tty->disc_data; + struct asyncppp *ap = ap_get(tty); clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); if (ap == 0) return; if (ppp_async_push(ap)) ppp_output_wakeup(&ap->chan); + ap_put(ap); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/ppp_generic.c linux-2.5/drivers/net/ppp_generic.c --- linux-2.5.5/drivers/net/ppp_generic.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/net/ppp_generic.c Tue Feb 19 16:03:01 2002 @@ -1,7 +1,7 @@ /* * Generic PPP layer for Linux. * - * Copyright 1999-2000 Paul Mackerras. + * Copyright 1999-2002 Paul Mackerras. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -19,7 +19,7 @@ * PPP driver, written by Michael Callahan and Al Longyear, and * subsequently hacked by Paul Mackerras. * - * ==FILEVERSION 20000902== + * ==FILEVERSION 20020217== */ #include @@ -43,10 +43,12 @@ #include #include #include +#include +#include #include #include -#define PPP_VERSION "2.4.1" +#define PPP_VERSION "2.4.2" /* * Network protocols we support. @@ -75,11 +77,11 @@ wait_queue_head_t rwait; /* for poll on reading /dev/ppp */ atomic_t refcnt; /* # refs (incl /dev/ppp attached) */ int hdrlen; /* space to leave for headers */ - struct list_head list; /* link in all_* list */ int index; /* interface unit / channel number */ + int dead; /* unit/channel has been shut down */ }; -#define PF_TO_X(pf, X) ((X *)((char *)(pf)-(unsigned long)(&((X *)0)->file))) +#define PF_TO_X(pf, X) ((X *)((char *)(pf) - offsetof(X, file))) #define PF_TO_PPP(pf) PF_TO_X(pf, struct ppp) #define PF_TO_CHANNEL(pf) PF_TO_X(pf, struct channel) @@ -93,26 +95,27 @@ * It can have 0 or more ppp channels connected to it. */ struct ppp { - struct ppp_file file; /* stuff for read/write/poll */ - struct list_head channels; /* list of attached channels */ - int n_channels; /* how many channels are attached */ - spinlock_t rlock; /* lock for receive side */ - spinlock_t wlock; /* lock for transmit side */ - int mru; /* max receive unit */ - unsigned int flags; /* control bits */ - unsigned int xstate; /* transmit state bits */ - unsigned int rstate; /* receive state bits */ - int debug; /* debug flags */ + struct ppp_file file; /* stuff for read/write/poll 0 */ + struct file *owner; /* file that owns this unit 48 */ + struct list_head channels; /* list of attached channels 4c */ + int n_channels; /* how many channels are attached 54 */ + spinlock_t rlock; /* lock for receive side 58 */ + spinlock_t wlock; /* lock for transmit side 5c */ + int mru; /* max receive unit 60 */ + unsigned int flags; /* control bits 64 */ + unsigned int xstate; /* transmit state bits 68 */ + unsigned int rstate; /* receive state bits 6c */ + int debug; /* debug flags 70 */ struct slcompress *vj; /* state for VJ header compression */ - enum NPmode npmode[NUM_NP]; /* what to do with each net proto */ - struct sk_buff *xmit_pending; /* a packet ready to go out */ - struct compressor *xcomp; /* transmit packet compressor */ - void *xc_state; /* its internal state */ - struct compressor *rcomp; /* receive decompressor */ - void *rc_state; /* its internal state */ - unsigned long last_xmit; /* jiffies when last pkt sent */ - unsigned long last_recv; /* jiffies when last pkt rcvd */ - struct net_device *dev; /* network interface device */ + enum NPmode npmode[NUM_NP]; /* what to do with each net proto 78 */ + struct sk_buff *xmit_pending; /* a packet ready to go out 88 */ + struct compressor *xcomp; /* transmit packet compressor 8c */ + void *xc_state; /* its internal state 90 */ + struct compressor *rcomp; /* receive decompressor 94 */ + void *rc_state; /* its internal state 98 */ + unsigned long last_xmit; /* jiffies when last pkt sent 9c */ + unsigned long last_recv; /* jiffies when last pkt rcvd a0 */ + struct net_device *dev; /* network interface device a4 */ #ifdef CONFIG_PPP_MULTILINK int nxchan; /* next channel to send something on */ u32 nxseq; /* next sequence number to send */ @@ -144,11 +147,13 @@ */ struct channel { struct ppp_file file; /* stuff for read/write/poll */ + struct list_head list; /* link in all/new_channels list */ struct ppp_channel *chan; /* public channel data structure */ + struct rw_semaphore chan_sem; /* protects `chan' during chan ioctl */ spinlock_t downl; /* protects `chan', file.xq dequeue */ struct ppp *ppp; /* ppp unit we're connected to */ struct list_head clist; /* link in list of channels per unit */ - rwlock_t upl; /* protects `ppp' and `ulist' */ + rwlock_t upl; /* protects `ppp' */ #ifdef CONFIG_PPP_MULTILINK u8 avail; /* flag used in multilink stuff */ u8 had_frag; /* >= 1 fragments have been sent */ @@ -166,12 +171,35 @@ */ /* - * all_ppp_lock protects the all_ppp_units. - * It also ensures that finding a ppp unit in the all_ppp_units list + * A cardmap represents a mapping from unsigned integers to pointers, + * and provides a fast "find lowest unused number" operation. + * It uses a broad (32-way) tree with a bitmap at each level. + * It is designed to be space-efficient for small numbers of entries + * and time-efficient for large numbers of entries. + */ +#define CARDMAP_ORDER 5 +#define CARDMAP_WIDTH (1U << CARDMAP_ORDER) +#define CARDMAP_MASK (CARDMAP_WIDTH - 1) + +struct cardmap { + int shift; + unsigned long inuse; + struct cardmap *parent; + void *ptr[CARDMAP_WIDTH]; +}; +static void *cardmap_get(struct cardmap *map, unsigned int nr); +static void cardmap_set(struct cardmap **map, unsigned int nr, void *ptr); +static unsigned int cardmap_find_first_free(struct cardmap *map); +static void cardmap_destroy(struct cardmap **map); + +/* + * all_ppp_sem protects the all_ppp_units mapping. + * It also ensures that finding a ppp unit in the all_ppp_units map * and updating its file.refcnt field is atomic. */ -static spinlock_t all_ppp_lock = SPIN_LOCK_UNLOCKED; -static LIST_HEAD(all_ppp_units); +static DECLARE_MUTEX(all_ppp_sem); +static struct cardmap *all_ppp_units; +static atomic_t ppp_unit_count = ATOMIC_INIT(0); /* * all_channels_lock protects all_channels and last_channel_index, @@ -180,7 +208,9 @@ */ static spinlock_t all_channels_lock = SPIN_LOCK_UNLOCKED; static LIST_HEAD(all_channels); +static LIST_HEAD(new_channels); static int last_channel_index; +static atomic_t channel_count = ATOMIC_INIT(0); /* Get the PPP protocol number from a skb */ #define PPP_PROTO(skb) (((skb)->data[0] << 8) + (skb)->data[1]) @@ -205,10 +235,6 @@ #define seq_after(a, b) ((s32)((a) - (b)) > 0) /* Prototypes. */ -static ssize_t ppp_file_read(struct ppp_file *pf, struct file *file, - char *buf, size_t count); -static ssize_t ppp_file_write(struct ppp_file *pf, const char *buf, - size_t count); static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg); static void ppp_xmit_process(struct ppp *ppp); @@ -235,6 +261,7 @@ static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st); static struct ppp *ppp_create_interface(int unit, int *retp); static void init_ppp_file(struct ppp_file *pf, int kind); +static void ppp_shutdown_interface(struct ppp *ppp); static void ppp_destroy_interface(struct ppp *ppp); static struct ppp *ppp_find_unit(int unit); static struct channel *ppp_find_channel(int unit); @@ -303,7 +330,6 @@ #define ppp_unlock(ppp) do { ppp_recv_unlock(ppp); \ ppp_xmit_unlock(ppp); } while (0) - /* * /dev/ppp device routines. * The /dev/ppp device is used by pppd to control the ppp unit. @@ -323,10 +349,16 @@ static int ppp_release(struct inode *inode, struct file *file) { - struct ppp_file *pf = (struct ppp_file *) file->private_data; + struct ppp_file *pf = file->private_data; + struct ppp *ppp; if (pf != 0) { file->private_data = 0; + if (pf->kind == INTERFACE) { + ppp = PF_TO_PPP(pf); + if (file == ppp->owner) + ppp_shutdown_interface(ppp); + } if (atomic_dec_and_test(&pf->refcnt)) { switch (pf->kind) { case INTERFACE: @@ -344,30 +376,21 @@ static ssize_t ppp_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - struct ppp_file *pf = (struct ppp_file *) file->private_data; - - return ppp_file_read(pf, file, buf, count); -} - -static ssize_t ppp_file_read(struct ppp_file *pf, struct file *file, - char *buf, size_t count) -{ + struct ppp_file *pf = file->private_data; DECLARE_WAITQUEUE(wait, current); ssize_t ret; struct sk_buff *skb = 0; - ret = -ENXIO; if (pf == 0) - goto out; /* not currently attached */ - + return -ENXIO; add_wait_queue(&pf->rwait, &wait); - current->state = TASK_INTERRUPTIBLE; for (;;) { + set_current_state(TASK_INTERRUPTIBLE); skb = skb_dequeue(&pf->rq); if (skb) break; ret = 0; - if (pf->kind == CHANNEL && PF_TO_CHANNEL(pf)->chan == 0) + if (pf->dead) break; ret = -EAGAIN; if (file->f_flags & O_NONBLOCK) @@ -377,7 +400,7 @@ break; schedule(); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&pf->rwait, &wait); if (skb == 0) @@ -400,21 +423,12 @@ static ssize_t ppp_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - struct ppp_file *pf = (struct ppp_file *) file->private_data; - - return ppp_file_write(pf, buf, count); -} - -static ssize_t ppp_file_write(struct ppp_file *pf, const char *buf, - size_t count) -{ + struct ppp_file *pf = file->private_data; struct sk_buff *skb; ssize_t ret; - ret = -ENXIO; if (pf == 0) - goto out; - + return -ENXIO; ret = -ENOMEM; skb = alloc_skb(count + pf->hdrlen, GFP_KERNEL); if (skb == 0) @@ -446,7 +460,7 @@ /* No kernel lock - fine */ static unsigned int ppp_poll(struct file *file, poll_table *wait) { - struct ppp_file *pf = (struct ppp_file *) file->private_data; + struct ppp_file *pf = file->private_data; unsigned int mask; if (pf == 0) @@ -455,28 +469,52 @@ mask = POLLOUT | POLLWRNORM; if (skb_peek(&pf->rq) != 0) mask |= POLLIN | POLLRDNORM; - if (pf->kind == CHANNEL) { - struct channel *pch = PF_TO_CHANNEL(pf); - if (pch->chan == 0) - mask |= POLLHUP; - } + if (pf->dead) + mask |= POLLHUP; return mask; } static int ppp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct ppp_file *pf = (struct ppp_file *) file->private_data; + struct ppp_file *pf = file->private_data; struct ppp *ppp; int err = -EFAULT, val, val2, i; struct ppp_idle idle; struct npioctl npi; - int unit; + int unit, cflags; struct slcompress *vj; if (pf == 0) return ppp_unattached_ioctl(pf, file, cmd, arg); + if (cmd == PPPIOCDETACH) { + /* + * We have to be careful here... if the file descriptor + * has been dup'd, we could have another process in the + * middle of a poll using the same file *, so we had + * better not free the interface data structures - + * instead we fail the ioctl. Even in this case, we + * shut down the interface if we are the owner of it. + * Actually, we should get rid of PPPIOCDETACH, userland + * (i.e. pppd) could achieve the same effect by closing + * this fd and reopening /dev/ppp. + */ + err = -EINVAL; + if (pf->kind == INTERFACE) { + ppp = PF_TO_PPP(pf); + if (file == ppp->owner) + ppp_shutdown_interface(ppp); + } + if (atomic_read(&file->f_count) <= 2) { + ppp_release(inode, file); + err = 0; + } else + printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%d\n", + atomic_read(&file->f_count)); + return err; + } + if (pf->kind == CHANNEL) { struct channel *pch = PF_TO_CHANNEL(pf); struct ppp_channel *chan; @@ -492,20 +530,13 @@ err = ppp_disconnect_channel(pch); break; - case PPPIOCDETACH: - file->private_data = 0; - if (atomic_dec_and_test(&pf->refcnt)) - ppp_destroy_channel(pch); - err = 0; - break; - default: - spin_lock_bh(&pch->downl); + down_read(&pch->chan_sem); chan = pch->chan; err = -ENOTTY; if (chan && chan->ops->ioctl) err = chan->ops->ioctl(chan, cmd, arg); - spin_unlock_bh(&pch->downl); + up_read(&pch->chan_sem); } return err; } @@ -518,13 +549,6 @@ ppp = PF_TO_PPP(pf); switch (cmd) { - case PPPIOCDETACH: - file->private_data = 0; - if (atomic_dec_and_test(&pf->refcnt)) - ppp_destroy_interface(ppp); - err = 0; - break; - case PPPIOCSMRU: if (get_user(val, (int *) arg)) break; @@ -536,10 +560,11 @@ if (get_user(val, (int *) arg)) break; ppp_lock(ppp); - if (ppp->flags & ~val & SC_CCP_OPEN) - ppp_ccp_closed(ppp); + cflags = ppp->flags & ~val; ppp->flags = val & SC_FLAG_BITS; ppp_unlock(ppp); + if (cflags & SC_CCP_OPEN) + ppp_ccp_closed(ppp); err = 0; break; @@ -675,6 +700,7 @@ default: err = -ENOTTY; } + return err; } @@ -694,6 +720,7 @@ if (ppp == 0) break; file->private_data = &ppp->file; + ppp->owner = file; err = -EFAULT; if (put_user(ppp->file.index, (int *) arg)) break; @@ -704,31 +731,29 @@ /* Attach to an existing ppp unit */ if (get_user(unit, (int *) arg)) break; - spin_lock(&all_ppp_lock); + down(&all_ppp_sem); + err = -ENXIO; ppp = ppp_find_unit(unit); - if (ppp != 0) + if (ppp != 0) { atomic_inc(&ppp->file.refcnt); - spin_unlock(&all_ppp_lock); - err = -ENXIO; - if (ppp == 0) - break; - file->private_data = &ppp->file; - err = 0; + file->private_data = &ppp->file; + err = 0; + } + up(&all_ppp_sem); break; case PPPIOCATTCHAN: if (get_user(unit, (int *) arg)) break; spin_lock_bh(&all_channels_lock); + err = -ENXIO; chan = ppp_find_channel(unit); - if (chan != 0) + if (chan != 0) { atomic_inc(&chan->file.refcnt); + file->private_data = &chan->file; + err = 0; + } spin_unlock_bh(&all_channels_lock); - err = -ENXIO; - if (chan == 0) - break; - file->private_data = &chan->file; - err = 0; break; default: @@ -905,15 +930,16 @@ struct sk_buff *skb; ppp_xmit_lock(ppp); - ppp_push(ppp); - while (ppp->xmit_pending == 0 - && (skb = skb_dequeue(&ppp->file.xq)) != 0) - ppp_send_frame(ppp, skb); - /* If there's no work left to do, tell the core net - code that we can accept some more. */ - if (ppp->xmit_pending == 0 && skb_peek(&ppp->file.xq) == 0 - && ppp->dev != 0) - netif_wake_queue(ppp->dev); + if (ppp->dev != 0) { + ppp_push(ppp); + while (ppp->xmit_pending == 0 + && (skb = skb_dequeue(&ppp->file.xq)) != 0) + ppp_send_frame(ppp, skb); + /* If there's no work left to do, tell the core net + code that we can accept some more. */ + if (ppp->xmit_pending == 0 && skb_peek(&ppp->file.xq) == 0) + netif_wake_queue(ppp->dev); + } ppp_xmit_unlock(ppp); } @@ -1526,6 +1552,7 @@ error indication. */ if (len == DECOMP_FATALERROR) ppp->rstate |= SC_DC_FERROR; + kfree_skb(ns); goto err; } @@ -1797,7 +1824,7 @@ { struct channel *pch; - pch = kmalloc(sizeof(struct channel), GFP_ATOMIC); + pch = kmalloc(sizeof(struct channel), GFP_KERNEL); if (pch == 0) return -ENOMEM; memset(pch, 0, sizeof(struct channel)); @@ -1809,11 +1836,13 @@ #ifdef CONFIG_PPP_MULTILINK pch->lastseq = -1; #endif /* CONFIG_PPP_MULTILINK */ + init_rwsem(&pch->chan_sem); spin_lock_init(&pch->downl); pch->upl = RW_LOCK_UNLOCKED; spin_lock_bh(&all_channels_lock); pch->file.index = ++last_channel_index; - list_add(&pch->file.list, &all_channels); + list_add(&pch->list, &new_channels); + atomic_inc(&channel_count); spin_unlock_bh(&all_channels_lock); MOD_INC_USE_COUNT; return 0; @@ -1826,7 +1855,9 @@ { struct channel *pch = chan->ppp; - return pch->file.index; + if (pch != 0) + return pch->file.index; + return -1; } /* @@ -1848,7 +1879,7 @@ /* * Disconnect a channel from the generic layer. - * This can be called from mainline or BH/softirq level. + * This must be called in process context. */ void ppp_unregister_channel(struct ppp_channel *chan) @@ -1863,14 +1894,17 @@ * This ensures that we have returned from any calls into the * the channel's start_xmit or ioctl routine before we proceed. */ + down_write(&pch->chan_sem); spin_lock_bh(&pch->downl); pch->chan = 0; spin_unlock_bh(&pch->downl); + up_write(&pch->chan_sem); ppp_disconnect_channel(pch); - wake_up_interruptible(&pch->file.rwait); spin_lock_bh(&all_channels_lock); - list_del(&pch->file.list); + list_del(&pch->list); spin_unlock_bh(&all_channels_lock); + pch->file.dead = 1; + wake_up_interruptible(&pch->file.rwait); if (atomic_dec_and_test(&pch->file.refcnt)) ppp_destroy_channel(pch); MOD_DEC_USE_COUNT; @@ -1899,9 +1933,9 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg) { int err; - struct compressor *cp; + struct compressor *cp, *ocomp; struct ppp_option_data data; - void *state; + void *state, *ostate; unsigned char ccp_option[CCP_MAX_OPTION_LENGTH]; #ifdef CONFIG_KMOD char modname[32]; @@ -1927,41 +1961,39 @@ #endif /* CONFIG_KMOD */ if (cp == 0) goto out; + /* + * XXX race: the compressor module could get unloaded between + * here and when we do the comp_alloc or decomp_alloc call below. + */ err = -ENOBUFS; if (data.transmit) { - ppp_xmit_lock(ppp); - ppp->xstate &= ~SC_COMP_RUN; - if (ppp->xc_state != 0) { - ppp->xcomp->comp_free(ppp->xc_state); - ppp->xc_state = 0; - } - ppp_xmit_unlock(ppp); - state = cp->comp_alloc(ccp_option, data.length); if (state != 0) { ppp_xmit_lock(ppp); + ppp->xstate &= ~SC_COMP_RUN; + ocomp = ppp->xcomp; + ostate = ppp->xc_state; ppp->xcomp = cp; ppp->xc_state = state; ppp_xmit_unlock(ppp); + if (ostate != 0) + ocomp->comp_free(ostate); err = 0; } } else { - ppp_recv_lock(ppp); - ppp->rstate &= ~SC_DECOMP_RUN; - if (ppp->rc_state != 0) { - ppp->rcomp->decomp_free(ppp->rc_state); - ppp->rc_state = 0; - } - ppp_recv_unlock(ppp); - state = cp->decomp_alloc(ccp_option, data.length); if (state != 0) { ppp_recv_lock(ppp); + ppp->rstate &= ~SC_DECOMP_RUN; + ocomp = ppp->rcomp; + ostate = ppp->rc_state; ppp->rcomp = cp; ppp->rc_state = state; ppp_recv_unlock(ppp); + if (ostate != 0) + ocomp->decomp_free(ostate); err = 0; } } @@ -2059,19 +2091,25 @@ static void ppp_ccp_closed(struct ppp *ppp) { - ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP); + void *xstate, *rstate; + struct compressor *xcomp, *rcomp; - ppp->xstate &= ~SC_COMP_RUN; - if (ppp->xc_state) { - ppp->xcomp->comp_free(ppp->xc_state); - ppp->xc_state = 0; - } + ppp_lock(ppp); + ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP); + ppp->xstate = 0; + xcomp = ppp->xcomp; + xstate = ppp->xc_state; + ppp->xc_state = 0; + ppp->rstate = 0; + rcomp = ppp->rcomp; + rstate = ppp->rc_state; + ppp->rc_state = 0; + ppp_unlock(ppp); - ppp->xstate &= ~SC_DECOMP_RUN; - if (ppp->rc_state) { - ppp->rcomp->decomp_free(ppp->rc_state); - ppp->rc_state = 0; - } + if (xstate) + xcomp->comp_free(xstate); + if (rstate) + rcomp->decomp_free(rstate); } /* List of compressors. */ @@ -2191,39 +2229,27 @@ ppp_create_interface(int unit, int *retp) { struct ppp *ppp; - struct net_device *dev; - struct list_head *list; - int last_unit = -1; - int ret = -EEXIST; + struct net_device *dev = NULL; + int ret = -ENOMEM; int i; - spin_lock(&all_ppp_lock); - list = &all_ppp_units; - while ((list = list->next) != &all_ppp_units) { - ppp = list_entry(list, struct ppp, file.list); - if ((unit < 0 && ppp->file.index > last_unit + 1) - || (unit >= 0 && unit < ppp->file.index)) - break; - if (unit == ppp->file.index) - goto out; /* unit already exists */ - last_unit = ppp->file.index; - } - if (unit < 0) - unit = last_unit + 1; - - /* Create a new ppp structure and link it before `list'. */ - ret = -ENOMEM; - ppp = kmalloc(sizeof(struct ppp), GFP_ATOMIC); + ppp = kmalloc(sizeof(struct ppp), GFP_KERNEL); if (ppp == 0) - goto out; + goto err; + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (dev == 0) + goto err; memset(ppp, 0, sizeof(struct ppp)); - dev = kmalloc(sizeof(struct net_device), GFP_ATOMIC); - if (dev == 0) { - kfree(ppp); - goto out; - } memset(dev, 0, sizeof(struct net_device)); + ret = -EEXIST; + down(&all_ppp_sem); + if (unit < 0) + unit = cardmap_find_first_free(all_ppp_units); + else if (cardmap_get(all_ppp_units, unit) != NULL) + goto err_unlock; /* unit already exists */ + + /* Initialize the new ppp unit */ ppp->file.index = unit; ppp->mru = PPP_MRU; init_ppp_file(&ppp->file, INTERFACE); @@ -2248,19 +2274,26 @@ ret = register_netdevice(dev); rtnl_unlock(); if (ret != 0) { - printk(KERN_ERR "PPP: couldn't register device (%d)\n", ret); - kfree(dev); - kfree(ppp); - goto out; + printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", + dev->name, ret); + goto err_unlock; } - list_add(&ppp->file.list, list->prev); - out: - spin_unlock(&all_ppp_lock); - *retp = ret; - if (ret != 0) - ppp = 0; + atomic_inc(&ppp_unit_count); + cardmap_set(&all_ppp_units, unit, ppp); + up(&all_ppp_sem); + *retp = 0; return ppp; + + err_unlock: + up(&all_ppp_sem); + err: + *retp = ret; + if (ppp) + kfree(ppp); + if (dev) + kfree(dev); + return NULL; } /* @@ -2277,19 +2310,48 @@ } /* - * Free up all the resources used by a ppp interface unit. + * Take down a ppp interface unit - called when the owning file + * (the one that created the unit) is closed or detached. */ -static void ppp_destroy_interface(struct ppp *ppp) +static void ppp_shutdown_interface(struct ppp *ppp) { struct net_device *dev; - int n_channels ; - - spin_lock(&all_ppp_lock); - list_del(&ppp->file.list); - /* Last fd open to this ppp unit is being closed or detached: - mark the interface down, free the ppp unit */ + down(&all_ppp_sem); ppp_lock(ppp); + dev = ppp->dev; + ppp->dev = 0; + ppp_unlock(ppp); + if (dev) { + rtnl_lock(); + dev_close(dev); + unregister_netdevice(dev); + rtnl_unlock(); + } + cardmap_set(&all_ppp_units, ppp->file.index, NULL); + ppp->file.dead = 1; + ppp->owner = NULL; + wake_up_interruptible(&ppp->file.rwait); + up(&all_ppp_sem); +} + +/* + * Free the memory used by a ppp unit. This is only called once + * there are no channels connected to the unit and no file structs + * that reference the unit. + */ +static void ppp_destroy_interface(struct ppp *ppp) +{ + atomic_dec(&ppp_unit_count); + + if (!ppp->file.dead || ppp->n_channels) { + /* "can't happen" */ + printk(KERN_ERR "ppp: destroying ppp struct %p but dead=%d " + "n_channels=%d !\n", ppp, ppp->file.dead, + ppp->n_channels); + return; + } + ppp_ccp_closed(ppp); if (ppp->vj) { slhc_free(ppp->vj); @@ -2310,52 +2372,27 @@ ppp->active_filter.filter = 0; } #endif /* CONFIG_PPP_FILTER */ - dev = ppp->dev; - ppp->dev = 0; - n_channels = ppp->n_channels ; - ppp_unlock(ppp); - - if (dev) { - rtnl_lock(); - dev_close(dev); - unregister_netdevice(dev); - rtnl_unlock(); - } - - /* - * We can't acquire any new channels (since we have the - * all_ppp_lock) so if n_channels is 0, we can free the - * ppp structure. Otherwise we leave it around until the - * last channel disconnects from it. - */ - if (n_channels == 0) - kfree(ppp); - spin_unlock(&all_ppp_lock); + kfree(ppp); } /* * Locate an existing ppp unit. - * The caller should have locked the all_ppp_lock. + * The caller should have locked the all_ppp_sem. */ static struct ppp * ppp_find_unit(int unit) { - struct ppp *ppp; - struct list_head *list; - - list = &all_ppp_units; - while ((list = list->next) != &all_ppp_units) { - ppp = list_entry(list, struct ppp, file.list); - if (ppp->file.index == unit) - return ppp; - } - return 0; + return cardmap_get(all_ppp_units, unit); } /* * Locate an existing ppp channel. * The caller should have locked the all_channels_lock. + * First we look in the new_channels list, then in the + * all_channels list. If found in the new_channels list, + * we move it to the all_channels list. This is for speed + * when we have a lot of channels in use. */ static struct channel * ppp_find_channel(int unit) @@ -2363,9 +2400,18 @@ struct channel *pch; struct list_head *list; + list = &new_channels; + while ((list = list->next) != &new_channels) { + pch = list_entry(list, struct channel, list); + if (pch->file.index == unit) { + list_del(&pch->list); + list_add(&pch->list, &all_channels); + return pch; + } + } list = &all_channels; while ((list = list->next) != &all_channels) { - pch = list_entry(list, struct channel, file.list); + pch = list_entry(list, struct channel, list); if (pch->file.index == unit) return pch; } @@ -2382,19 +2428,16 @@ int ret = -ENXIO; int hdrlen; - spin_lock(&all_ppp_lock); + down(&all_ppp_sem); ppp = ppp_find_unit(unit); if (ppp == 0) goto out; write_lock_bh(&pch->upl); ret = -EINVAL; if (pch->ppp != 0) - goto outwl; - ppp_lock(ppp); - spin_lock_bh(&pch->downl); - if (pch->chan == 0) /* need to check this?? */ - goto outr; + goto outl; + ppp_lock(ppp); if (pch->file.hdrlen > ppp->file.hdrlen) ppp->file.hdrlen = pch->file.hdrlen; hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ @@ -2403,15 +2446,14 @@ list_add_tail(&pch->clist, &ppp->channels); ++ppp->n_channels; pch->ppp = ppp; + atomic_inc(&ppp->file.refcnt); + ppp_unlock(ppp); ret = 0; - outr: - spin_unlock_bh(&pch->downl); - ppp_unlock(ppp); - outwl: + outl: write_unlock_bh(&pch->upl); out: - spin_unlock(&all_ppp_lock); + up(&all_ppp_sem); return ret; } @@ -2423,25 +2465,21 @@ { struct ppp *ppp; int err = -EINVAL; - int dead; write_lock_bh(&pch->upl); ppp = pch->ppp; + pch->ppp = NULL; + write_unlock_bh(&pch->upl); if (ppp != 0) { /* remove it from the ppp unit's list */ - pch->ppp = NULL; ppp_lock(ppp); list_del(&pch->clist); --ppp->n_channels; - dead = ppp->dev == 0 && ppp->n_channels == 0; ppp_unlock(ppp); - if (dead) - /* Last disconnect from a ppp unit - that is already dead: free it. */ - kfree(ppp); + if (atomic_dec_and_test(&ppp->file.refcnt)) + ppp_destroy_interface(ppp); err = 0; } - write_unlock_bh(&pch->upl); return err; } @@ -2450,6 +2488,14 @@ */ static void ppp_destroy_channel(struct channel *pch) { + atomic_dec(&channel_count); + + if (!pch->file.dead) { + /* "can't happen" */ + printk(KERN_ERR "ppp: destroying undead channel %p !\n", + pch); + return; + } skb_queue_purge(&pch->file.xq); skb_queue_purge(&pch->file.rq); kfree(pch); @@ -2458,12 +2504,123 @@ static void __exit ppp_cleanup(void) { /* should never happen */ - if (!list_empty(&all_ppp_units) || !list_empty(&all_channels)) + if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) printk(KERN_ERR "PPP: removing module but units remain!\n"); + cardmap_destroy(&all_ppp_units); if (devfs_unregister_chrdev(PPP_MAJOR, "ppp") != 0) printk(KERN_ERR "PPP: failed to unregister PPP device\n"); devfs_unregister(devfs_handle); } + +/* + * Cardmap implementation. + */ +static void *cardmap_get(struct cardmap *map, unsigned int nr) +{ + struct cardmap *p; + int i; + + for (p = map; p != NULL; ) { + if ((i = nr >> p->shift) >= CARDMAP_WIDTH) + return NULL; + if (p->shift == 0) + return p->ptr[i]; + nr &= ~(CARDMAP_MASK << p->shift); + p = p->ptr[i]; + } + return NULL; +} + +static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr) +{ + struct cardmap *p; + int i; + + p = *pmap; + if (p == NULL || (nr >> p->shift) >= CARDMAP_WIDTH) { + do { + /* need a new top level */ + struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL); + memset(np, 0, sizeof(*np)); + np->ptr[0] = p; + if (p != NULL) { + np->shift = p->shift + CARDMAP_ORDER; + p->parent = np; + } else + np->shift = 0; + p = np; + } while ((nr >> p->shift) >= CARDMAP_WIDTH); + *pmap = p; + } + while (p->shift > 0) { + i = (nr >> p->shift) & CARDMAP_MASK; + if (p->ptr[i] == NULL) { + struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL); + memset(np, 0, sizeof(*np)); + np->shift = p->shift - CARDMAP_ORDER; + np->parent = p; + p->ptr[i] = np; + } + if (ptr == NULL) + clear_bit(i, &p->inuse); + p = p->ptr[i]; + } + i = nr & CARDMAP_MASK; + p->ptr[i] = ptr; + if (ptr != NULL) + set_bit(i, &p->inuse); + else + clear_bit(i, &p->inuse); +} + +static unsigned int cardmap_find_first_free(struct cardmap *map) +{ + struct cardmap *p; + unsigned int nr = 0; + int i; + + if ((p = map) == NULL) + return 0; + for (;;) { + i = find_first_zero_bit(&p->inuse, CARDMAP_WIDTH); + if (i >= CARDMAP_WIDTH) { + if (p->parent == NULL) + return CARDMAP_WIDTH << p->shift; + p = p->parent; + i = (nr >> p->shift) & CARDMAP_MASK; + set_bit(i, &p->inuse); + continue; + } + nr = (nr & (~CARDMAP_MASK << p->shift)) | (i << p->shift); + if (p->shift == 0 || p->ptr[i] == NULL) + return nr; + p = p->ptr[i]; + } +} + +static void cardmap_destroy(struct cardmap **pmap) +{ + struct cardmap *p, *np; + int i; + + for (p = *pmap; p != NULL; p = np) { + if (p->shift != 0) { + for (i = 0; i < CARDMAP_WIDTH; ++i) + if (p->ptr[i] != NULL) + break; + if (i < CARDMAP_WIDTH) { + np = p->ptr[i]; + p->ptr[i] = NULL; + continue; + } + } + np = p->parent; + kfree(p); + } + *pmap = NULL; +} + +/* Module/initialization stuff */ module_init(ppp_init); module_exit(ppp_cleanup); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/ppp_synctty.c linux-2.5/drivers/net/ppp_synctty.c --- linux-2.5.5/drivers/net/ppp_synctty.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/net/ppp_synctty.c Fri Feb 8 02:38:26 2002 @@ -25,11 +25,11 @@ * the generic PPP layer to give it frames to send and to process * received frames. It implements the PPP line discipline. * - * Part of the code in this driver was inspired by the old sync-only + * Part of the code in this driver was inspired by the old async-only * PPP driver, written by Michael Callahan and Al Longyear, and * subsequently hacked by Paul Mackerras. * - * ==FILEVERSION 20000322== + * ==FILEVERSION 20020125== */ #include @@ -41,10 +41,12 @@ #include #include #include +#include #include #include +#include -#define PPP_VERSION "2.4.1" +#define PPP_VERSION "2.4.2" /* Structure for storing local state. */ struct syncppp { @@ -65,6 +67,8 @@ struct sk_buff *rpkt; + atomic_t refcnt; + struct semaphore dead_sem; struct ppp_channel chan; /* interface to generic ppp layer */ }; @@ -161,7 +165,36 @@ */ /* - * Called when a tty is put into line discipline. + * We have a potential race on dereferencing tty->disc_data, + * because the tty layer provides no locking at all - thus one + * cpu could be running ppp_synctty_receive while another + * calls ppp_synctty_close, which zeroes tty->disc_data and + * frees the memory that ppp_synctty_receive is using. The best + * way to fix this is to use a rwlock in the tty struct, but for now + * we use a single global rwlock for all ttys in ppp line discipline. + */ +static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; + +static struct syncppp *sp_get(struct tty_struct *tty) +{ + struct syncppp *ap; + + read_lock(&disc_data_lock); + ap = tty->disc_data; + if (ap != NULL) + atomic_inc(&ap->refcnt); + read_unlock(&disc_data_lock); + return ap; +} + +static void sp_put(struct syncppp *ap) +{ + if (atomic_dec_and_test(&ap->refcnt)) + up(&ap->dead_sem); +} + +/* + * Called when a tty is put into sync-PPP line discipline. */ static int ppp_sync_open(struct tty_struct *tty) @@ -185,6 +218,9 @@ ap->xaccm[3] = 0x60000000U; ap->raccm = ~0U; + atomic_set(&ap->refcnt, 1); + init_MUTEX_LOCKED(&ap->dead_sem); + ap->chan.private = ap; ap->chan.ops = &sync_ops; ap->chan.mtu = PPP_MRU; @@ -206,16 +242,34 @@ /* * Called when the tty is put into another line discipline - * (or it hangs up). + * or it hangs up. We have to wait for any cpu currently + * executing in any of the other ppp_synctty_* routines to + * finish before we can call ppp_unregister_channel and free + * the syncppp struct. This routine must be called from + * process context, not interrupt or softirq context. */ static void ppp_sync_close(struct tty_struct *tty) { - struct syncppp *ap = tty->disc_data; + struct syncppp *ap; + write_lock(&disc_data_lock); + ap = tty->disc_data; + tty->disc_data = 0; + write_unlock(&disc_data_lock); if (ap == 0) return; - tty->disc_data = 0; + + /* + * We have now ensured that nobody can start using ap from now + * on, but we have to wait for all existing users to finish. + * Note that ppp_unregister_channel ensures that no calls to + * our channel ops (i.e. ppp_sync_send/ioctl) are in progress + * by the time it returns. + */ + if (!atomic_dec_and_test(&ap->refcnt)) + down(&ap->dead_sem); + ppp_unregister_channel(&ap->chan); if (ap->rpkt != 0) kfree_skb(ap->rpkt); @@ -251,9 +305,11 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct syncppp *ap = tty->disc_data; + struct syncppp *ap = sp_get(tty); int err, val; + if (ap == 0) + return -ENXIO; err = -EFAULT; switch (cmd) { case PPPIOCGCHAN: @@ -299,6 +355,7 @@ err = -ENOIOCTLCMD; } + sp_put(ap); return err; } @@ -319,13 +376,14 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf, char *flags, int count) { - struct syncppp *ap = tty->disc_data; + struct syncppp *ap = sp_get(tty); if (ap == 0) return; spin_lock_bh(&ap->recv_lock); ppp_sync_input(ap, buf, flags, count); spin_unlock_bh(&ap->recv_lock); + sp_put(ap); if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && tty->driver.unthrottle) tty->driver.unthrottle(tty); @@ -334,13 +392,14 @@ static void ppp_sync_wakeup(struct tty_struct *tty) { - struct syncppp *ap = tty->disc_data; + struct syncppp *ap = sp_get(tty); clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); if (ap == 0) return; if (ppp_sync_push(ap)) ppp_output_wakeup(&ap->chan); + sp_put(ap); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/pppoe.c linux-2.5/drivers/net/pppoe.c --- linux-2.5.5/drivers/net/pppoe.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/net/pppoe.c Thu Feb 14 02:57:58 2002 @@ -5,7 +5,7 @@ * PPPoE --- PPP over Ethernet (RFC 2516) * * - * Version: 0.6.9 + * Version: 0.6.10 * * 220102 : Fix module use count on failure in pppoe_create, pppox_sk -acme * 030700 : Fixed connect logic to allow for disconnect. @@ -32,6 +32,9 @@ * a memory leak. * 081001 : Misc. cleanup (licence string, non-blocking, prevent * reference of device on close). + * 121301 : New ppp channels interface; cannot unregister a channel + * from interrupts. Thus, we mark the socket as a ZOMBIE + * and do the unregistration later. * * Author: Michal Ostrowski * Contributors: @@ -87,11 +90,11 @@ #if 0 -#define CHECKPTR(x,y) { if (!(x) && pppoe_debug &7 ){ printk(KERN_CRIT "PPPoE Invalid pointer : %s , %p\n",#x,(x)); error=-EINVAL; goto y; }} -#define DEBUG(s,args...) if( pppoe_debug & (s) ) printk(KERN_CRIT args ); +#define CHECKPTR(x,y) do { if (!(x) && pppoe_debug &7 ){ printk(KERN_CRIT "PPPoE Invalid pointer : %s , %p\n",#x,(x)); error=-EINVAL; goto y; }} while (0) +#define DEBUG(s,args...) do { if( pppoe_debug & (s) ) printk(KERN_CRIT args ); } while (0) #else -#define CHECKPTR(x,y) do {} while (0); -#define DEBUG(s,args...) do { } while (0); +#define CHECKPTR(x,y) do { } while (0) +#define DEBUG(s,args...) do { } while (0) #endif @@ -275,10 +278,10 @@ lock_sock(sk); - if (sk->state & (PPPOX_CONNECTED | PPPOX_BOUND)) { + if (sk->state & (PPPOX_CONNECTED|PPPOX_BOUND)){ pppox_unbind_sock(sk); dev_put(dev); - sk->state = PPPOX_DEAD; + sk->state = PPPOX_ZOMBIE; sk->state_change(sk); } @@ -441,8 +444,10 @@ * one socket family type, we cannot (easily) distinguish * what kind of SKB it is during backlog rcv. */ - if (sk->lock.users == 0) + if (sk->lock.users == 0) { + sk->state = PPPOX_ZOMBIE; pppox_unbind_sock(sk); + } bh_unlock_sock(sk); sock_put(sk); @@ -719,7 +724,7 @@ struct pppox_opt *relay_po; err = -EBUSY; - if (sk->state & PPPOX_BOUND) + if (sk->state & (PPPOX_BOUND|PPPOX_ZOMBIE|PPPOX_DEAD)) break; err = -ENOTCONN; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/rclanmtl.c linux-2.5/drivers/net/rclanmtl.c --- linux-2.5.5/drivers/net/rclanmtl.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/net/rclanmtl.c Mon Jan 14 22:39:45 2002 @@ -299,21 +299,21 @@ { int result; PPAB pPab; - U32 pciBaseAddr = dev->base_addr; PDPA pDpa = dev->priv; + U32 pciBaseAddr = dev->base_addr; PU8 p_msgbuf = pDpa->PLanApiPA; PU8 p_phymsgbuf = (PU8) virt_to_bus ((void *) p_msgbuf); dprintk - ("InitI2O: Adapter:0x%04ux ATU:0x%08ulx msgbuf:0x%08ulx phymsgbuf:0x%08ulx\n" - "TransmitCallbackFunction:0x%08ulx ReceiveCallbackFunction:0x%08ulx\n", + ("InitI2O: Adapter:0x%x ATU:0x%x msgbuf:0x%x phymsgbuf:0x%x\n" + "TransmitCallbackFunction:0x%x ReceiveCallbackFunction:0x%x\n", pDpa->id, pciBaseAddr, (u32) p_msgbuf, (u32) p_phymsgbuf, (u32) TransmitCallbackFunction, (u32) ReceiveCallbackFunction); /* Check if this interface already initialized - if so, shut it down */ if (pDpa->pPab != NULL) { - printk (KERN_WARNING - "(rcpci45 driver:) pDpa->pPab [%d] != NULL\n", + dprintk (KERN_WARNING + "pDpa->pPab [%d] != NULL\n", pDpa->id); /* RCResetLANCard(pDpa->id, 0, (PU32)NULL, (PFNCALLBACK)NULL); */ pDpa->pPab = NULL; @@ -324,8 +324,8 @@ pPab = kmalloc (sizeof (*pPab), GFP_KERNEL); if (!pPab) { - printk (KERN_ERR - "(rcpci45 driver:) RCInitI2OMsgLayer: Could not allocate memory for PAB struct!\n"); + dprintk (KERN_ERR + "RCInitI2OMsgLayer: Could not allocate memory for PAB struct!\n"); result = RC_RTN_MALLOC_ERROR; goto err_out; } @@ -354,8 +354,7 @@ goto err_out_dealloc; if (pPab->IOPState == I2O_IOP_STATE_OPERATIONAL) { - printk (KERN_INFO - "(rcpci45 driver:) pPab->IOPState == op: resetting adapter\n"); + dprintk (KERN_INFO "pPab->IOPState == op: resetting adapter\n"); RCResetLANCard (dev, 0, (PU32) NULL, (PFNCALLBACK) NULL); } @@ -445,7 +444,7 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock); @@ -502,7 +501,7 @@ dprintk ("RCPostRecvBuffers(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock); @@ -570,13 +569,13 @@ dev); } else if (I2O_LAN_RECEIVE_POST == p8Msg[7]) { /* Receive Packet Reply Msg */ dprintk - ("I2O_RECV_REPLY pPab:0x%08ulx p8Msg:0x%08ulx p32:0x%08ulx\n", + ("I2O_RECV_REPLY pPab:0x%x p8Msg:0x%x p32:0x%x\n", (u32) pPab, (u32) p8Msg, (u32) p32); - dprintk ("msg: 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + dprintk ("msg: 0x%x:0x%x:0x%x:0x%x\n", p32[0], p32[1], p32[2], p32[3]); - dprintk (" 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + dprintk (" 0x%x:0x%x:0x%x:0x%x\n", p32[4], p32[5], p32[6], p32[7]); - dprintk (" 0x%08ulx:0X%08ulx:0x%08ulx:0x%08ulx\n", + dprintk (" 0x%x:0X%x:0x%x:0x%x\n", p32[8], p32[9], p32[10], p32[11]); /* status, count, buckets remaining, packetParmBlock, adapter */ (*pPab->pRecvCallbackFunc) (p8Msg[19], p8Msg[12], @@ -623,8 +622,8 @@ dev); break; default: - printk (KERN_WARNING - "(rcpci45 driver:) Unknown private I2O msg received: 0x%x\n", + dprintk (KERN_WARNING + "Unknown private I2O msg received: 0x%x\n", p32[5]); break; } @@ -658,14 +657,13 @@ PFNWAITCALLBACK WaitCallback) { U32 msgOffset; - volatile U32 timeout; volatile PU32 pMsg; volatile PU32 p32, pReturnAddr; P_NICSTAT pStats; int i; PPAB pPab = ((PDPA) dev->priv)->pPab; -/*dprintk("Get82558Stats() StatsReturnAddr:0x%08ulx\n", StatsReturnAddr); */ +/*dprintk("Get82558Stats() StatsReturnAddr:0x%x\n", StatsReturnAddr); */ if (pPab == NULL) return RC_RTN_ADPTR_NOT_REGISTERED; @@ -677,10 +675,10 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); -/*dprintk("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ +/*dprintk("Get82558Stats - pMsg = 0x%x, InQ msgOffset = 0x%x\n", pMsg, msgOffset);*/ /*dprintk("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -690,30 +688,22 @@ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_NIC_STATS; pMsg[5] = pPab->outMsgBlockPhyAddr; - p32 = (PU32) pPab->outMsgBlockPhyAddr; +// p32 = (PU32) pPab->outMsgBlockPhyAddr; + p32 = (PU32)pPab->pLinOutMsgBlock; pStats = (P_NICSTAT) pPab->pLinOutMsgBlock; pStats->dump_status = 0xFFFFFFFF; /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; - timeout = 100000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (pStats->dump_status != 0xFFFFFFFF) - break; - - if (!timeout--) { - dprintk - ("RCGet82558Stats() Timeout waiting for NIC statistics\n"); + i = 0; + while (pStats->dump_status == 0xFFFFFFFF) { + if (i++ > 0xff) { + dprintk ("Timeout waiting for NIC statistics\n"); return RC_RTN_MSG_REPLY_TIMEOUT; } + udelay(50); } - pReturnAddr = (PU32) StatsReturnAddr; /* copy Nic stats to user's structure */ @@ -732,13 +722,13 @@ RCGetLinkStatus (struct net_device * dev, PU32 ReturnAddr, PFNWAITCALLBACK WaitCallback) { + int i; U32 msgOffset; - volatile U32 timeout; volatile PU32 pMsg; volatile PU32 p32; PPAB pPab = ((PDPA) dev->priv)->pPab; - dprintk ("Get82558LinkStatus() ReturnPhysAddr:0x%08ulx\n", + dprintk ("Get82558LinkStatus() ReturnPhysAddr:0x%x\n", (u32) ReturnAddr); if (pPab == NULL) @@ -751,9 +741,9 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); -/*dprintk("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ +/*dprintk("Get82558LinkStatus - pMsg = 0x%x, InQ msgOffset = 0x%x\n", pMsg, msgOffset);*/ /*dprintk("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -769,20 +759,13 @@ /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; - timeout = 100000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (*p32 != 0xFFFFFFFF) - break; - - if (!timeout--) { + i = 0; + while (*p32 == 0xFFFFFFFF) { + if (i++ > 0xff) { dprintk ("Timeout waiting for link status\n"); return RC_RTN_MSG_REPLY_TIMEOUT; } + udelay(50); } *ReturnAddr = *p32; /* 1 = up 0 = down */ @@ -802,8 +785,7 @@ RC_RETURN RCGetMAC (struct net_device * dev, PFNWAITCALLBACK WaitCallback) { - unsigned timeout; - U32 off; + U32 off, i; PU8 mac = dev->dev_addr; PU32 p; U32 temp[2]; @@ -839,17 +821,13 @@ (uint) p_atu, (uint) off, (uint) p); /* wait for the rcpci45 board to update the info */ - timeout = 1000000; + i = 0; while (0 == p_atu->EtherMacLow) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (!timeout--) { - printk ("rc_getmac: Timeout\n"); + if (i++ > 0xff) { + dprintk ("rc_getmac: Timeout\n"); return RC_RTN_MSG_REPLY_TIMEOUT; - } + } + udelay(50); } /* read the mac address */ @@ -1001,16 +979,16 @@ RCGetPromiscuousMode (struct net_device * dev, PU32 pMode, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; PU32 pMsg; volatile PU32 p32; + U32 msgOffset, i; PPAB pPab = ((PDPA) dev->priv)->pPab; msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { - printk (KERN_WARNING - "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); + dprintk (KERN_WARNING + "RCGetLinkSpeed(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } @@ -1034,23 +1012,15 @@ pPab->p_atu->InQueue = msgOffset; - /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; + i = 0; - if (!timeout--) { - dprintk - ("Timeout waiting for promiscuous mode from adapter\n"); - dprintk ("0x%8x\n", p32[0]); + /* wait for response */ + while (p32[0] == 0xff) { + if (i++ > 0xff) { + dprintk ("Timeout waiting for promiscuous mode\n"); return RC_RTN_NO_LINK_SPEED; } + udelay(50); } /* get mode */ @@ -1115,7 +1085,7 @@ RCGetBroadcastMode (struct net_device * dev, PU32 pMode, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; + U32 msgOffset; PU32 pMsg; volatile PU32 p32; PPAB pPab = ((PDPA) dev->priv)->pPab; @@ -1123,8 +1093,8 @@ msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { - printk (KERN_WARNING - "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); + dprintk (KERN_WARNING + "RCGetLinkSpeed(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } @@ -1149,23 +1119,10 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) { - printk (KERN_WARNING - "(rcpci45 driver:) Timeout waiting for promiscuous mode from adapter\n"); - printk (KERN_WARNING "(rcpci45 driver:) 0x%8x\n", - p32[0]); - return RC_RTN_NO_LINK_SPEED; - } + if (p32[0] == 0xff) { + dprintk (KERN_WARNING + "Timeout waiting for promiscuous mode\n"); + return RC_RTN_NO_LINK_SPEED; } /* get mode */ @@ -1192,7 +1149,7 @@ RCGetLinkSpeed (struct net_device * dev, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; + U32 msgOffset, i; PU32 pMsg; volatile PU32 p32; U8 IOPLinkSpeed; @@ -1201,8 +1158,8 @@ msgOffset = pPab->p_atu->InQueue; if (msgOffset == 0xFFFFFFFF) { - printk (KERN_WARNING - "(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n"); + dprintk (KERN_WARNING + "RCGetLinkSpeed(): Inbound Free Q empty!\n"); return RC_RTN_FREE_Q_EMPTY; } @@ -1227,26 +1184,16 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) { - dprintk ("Timeout waiting for link speed from IOP\n"); - dprintk ("0x%8x\n", p32[0]); + i = 0; + while (p32[0] == 0xff) { + if (i++ > 0xff) { + dprintk ("Timeout waiting for link speed\n"); return RC_RTN_NO_LINK_SPEED; } + udelay(50); } - /* get Link speed */ IOPLinkSpeed = (U8) ((volatile PU8) p32)[0] & 0x0f; - *pLinkSpeedCode = IOPLinkSpeed; return RC_RTN_NO_ERROR; @@ -1304,7 +1251,7 @@ RCGetFirmwareVer (struct net_device * dev, PU8 pFirmString, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; + U32 msgOffset, i; PU32 pMsg; volatile PU32 p32; PPAB pPab = ((PDPA) dev->priv)->pPab; @@ -1336,22 +1283,14 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 1000000; - while (1) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] != 0xff) - break; - - if (!timeout--) { - dprintk ("Timeout waiting for link speed from IOP\n"); + i = 0; + while (p32[0] == 0xff) { + if (i++ > 0xff) { + dprintk ("Timeout waiting for link speed\n"); return RC_RTN_NO_FIRM_VER; } + udelay(50); } - strcpy (pFirmString, (PU8) p32); return RC_RTN_NO_ERROR; } @@ -1403,9 +1342,9 @@ or until timer goes off */ while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) { RCProcI2OMsgQ (dev); - udelay (1000); /* please don't hog the bus!!! */ + mdelay (1); timeout++; - if (timeout > 10000) { + if (timeout > 200) { break; } } @@ -1427,7 +1366,7 @@ RC_RETURN RCResetIOP (struct net_device * dev) { - U32 msgOffset, timeout; + U32 msgOffset, i; PU32 pMsg; PPAB pPab = ((PDPA) dev->priv)->pPab; volatile PU32 p32; @@ -1452,7 +1391,7 @@ pMsg[7] = 0; pMsg[8] = 1; /* return 1 byte */ - /* virual pointer to return buffer - clear first two dwords */ + /* virtual pointer to return buffer - clear first two dwords */ p32 = (volatile PU32) pPab->pLinOutMsgBlock; p32[0] = 0; p32[1] = 0; @@ -1462,17 +1401,13 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 1000000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] || p32[1]) - break; - - if (!timeout--) { + i = 0; + while (!p32[0] && !p32[1]) { + if (i++ > 0xff) { dprintk ("RCResetIOP timeout\n"); return RC_RTN_MSG_REPLY_TIMEOUT; } + udelay(100); } return RC_RTN_NO_ERROR; } @@ -1525,11 +1460,11 @@ or until timer goes off */ while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) { RCProcI2OMsgQ (dev); - udelay (1000); /* please don't hog the bus!!! */ + mdelay (1); timeout++; - if (timeout > 10000) { - printk (KERN_WARNING - "(rcpci45 driver:) RCShutdownLANCard(): timeout\n"); + if (timeout > 200) { + dprintk (KERN_WARNING + "RCShutdownLANCard(): timeout\n"); break; } } @@ -1594,14 +1529,13 @@ RCGetRavlinIPandMask (struct net_device * dev, PU32 pIpAddr, PU32 pNetMask, PFNWAITCALLBACK WaitCallback) { - unsigned timeout; - U32 off; + U32 off, i; PU32 pMsg, p32; PPAB pPab = ((PDPA) dev->priv)->pPab; PATU p_atu; dprintk - ("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", + ("RCGetRavlinIPandMask: pIpAddr is 0x%x, *IpAddr is 0x%x\n", (u32) pIpAddr, *pIpAddr); if (pPab == NULL) @@ -1619,7 +1553,7 @@ pMsg = (PU32) (pPab->pPci45LinBaseAddr + off); dprintk - ("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", + ("RCGetRavlinIPandMask: p_atu 0x%x, off 0x%x, p32 0x%x\n", (u32) p_atu, off, (u32) p32); /* setup private message */ pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1631,25 +1565,21 @@ p_atu->InQueue = off; /* send it to the I2O device */ dprintk - ("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n", + ("RCGetRavlinIPandMask: p_atu 0x%x, off 0x%x, p32 0x%x\n", (u32) p_atu, off, (u32) p32); /* wait for the rcpci45 board to update the info */ - timeout = 100000; + i = 0; while (0xffffffff == *p32) { - if (WaitCallback) - (*WaitCallback) (); - - udelay (10); - - if (!timeout--) { + if (i++ > 0xff) { dprintk ("RCGetRavlinIPandMask: Timeout\n"); return RC_RTN_MSG_REPLY_TIMEOUT; } + udelay(50); } dprintk - ("RCGetRavlinIPandMask: after time out\np32[0] (IpAddr) 0x%08ulx, p32[1] (IPmask) 0x%08ulx\n", + ("RCGetRavlinIPandMask: after time out\np32[0] (IpAddr) 0x%x, p32[1] (IPmask) 0x%x\n", p32[0], p32[1]); /* send IP and mask to user's space */ @@ -1657,7 +1587,7 @@ *pNetMask = p32[1]; dprintk - ("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n", + ("RCGetRavlinIPandMask: pIpAddr is 0x%x, *IpAddr is 0x%x\n", (u32) pIpAddr, *pIpAddr); return RC_RTN_NO_ERROR; @@ -1682,7 +1612,7 @@ static int SendI2OOutboundQInitMsg (PPAB pPab) { - U32 msgOffset, timeout, phyOutQFrames, i; + U32 msgOffset, phyOutQFrames, i; volatile PU32 pMsg; volatile PU32 p32; @@ -1693,11 +1623,11 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); dprintk - ("SendI2OOutboundQInitMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", + ("SendI2OOutboundQInitMsg - pMsg = 0x%x, InQ msgOffset = 0x%x\n", (u32) pMsg, msgOffset); pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6; @@ -1711,7 +1641,7 @@ /* phys address to return status - area right after PAB */ pMsg[7] = pPab->outMsgBlockPhyAddr; - /* virual pointer to return buffer - clear first two dwords */ + /* virtual pointer to return buffer - clear first two dwords */ p32 = (PU32) pPab->pLinOutMsgBlock; p32[0] = 0; @@ -1719,34 +1649,19 @@ pPab->p_atu->InQueue = msgOffset; /* wait for response */ - timeout = 100000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0]) - break; - - if (!timeout--) { - dprintk - ("Timeout wait for InitOutQ InPrgress status from IOP\n"); + i = 0; + while (!p32[0]) { + if (i++ > 0xff) { + printk("rc: InitOutQ timeout\n"); return RC_RTN_NO_I2O_STATUS; } + udelay(50); } - - timeout = 100000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] == I2O_EXEC_OUTBOUND_INIT_COMPLETE) - break; - - if (!timeout--) { - dprintk - ("Timeout wait for InitOutQ Complete status from IOP\n"); - return RC_RTN_NO_I2O_STATUS; - } + if (p32[0] != I2O_EXEC_OUTBOUND_INIT_COMPLETE) { + printk("rc: exec outbound init failed (%x)\n", + p32[0]); + return RC_RTN_NO_I2O_STATUS; } - /* load PCI outbound free Q with MF physical addresses */ phyOutQFrames = pPab->outMsgBlockPhyAddr; @@ -1768,7 +1683,7 @@ static int GetI2OStatus (PPAB pPab) { - U32 msgOffset, timeout; + U32 msgOffset, i; PU32 pMsg; volatile PU32 p32; @@ -1779,7 +1694,7 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1793,51 +1708,41 @@ pMsg[7] = 0; pMsg[8] = 88; /* return 88 bytes */ - /* virual pointer to return buffer - clear first two dwords */ + /* virtual pointer to return buffer - clear first two dwords */ p32 = (volatile PU32) pPab->pLinOutMsgBlock; p32[0] = 0; p32[1] = 0; dprintk - ("GetI2OStatus - pMsg:0x%08ulx, msgOffset:0x%08ulx, [1]:0x%08ulx, [6]:0x%08ulx\n", + ("GetI2OStatus - pMsg:0x%x, msgOffset:0x%x, [1]:0x%x, [6]:0x%x\n", (u32) pMsg, msgOffset, pMsg[1], pMsg[6]); /* post to Inbound Post Q */ pPab->p_atu->InQueue = msgOffset; - dprintk ("Return status to p32 = 0x%08ulx\n", (u32) p32); + dprintk ("Return status to p32 = 0x%x\n", (u32) p32); /* wait for response */ - timeout = 1000000; - while (1) { - udelay (10); /* please don't hog the bus!!! */ - - if (p32[0] && p32[1]) - break; - - if (!timeout--) { + i = 0; + while (!p32[0] || !p32[1]) { + if (i++ > 0xff) { dprintk ("Timeout waiting for status from IOP\n"); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[0], p32[1], p32[2], p32[3]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[4], p32[5], p32[6], p32[7]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", - p32[8], p32[9], p32[10], p32[11]); return RC_RTN_NO_I2O_STATUS; } + udelay(50); } - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], + dprintk ("0x%x:0x%x:0x%x:0x%x\n", p32[0], p32[1], p32[2], p32[3]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], + dprintk ("0x%x:0x%x:0x%x:0x%x\n", p32[4], p32[5], p32[6], p32[7]); - dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[8], p32[9], + dprintk ("0x%x:0x%x:0x%x:0x%x\n", p32[8], p32[9], p32[10], p32[11]); /* get IOP state */ pPab->IOPState = ((volatile PU8) p32)[10]; pPab->InboundMFrameSize = ((volatile PU16) p32)[6]; - dprintk ("IOP state 0x%02x InFrameSize = 0x%04x\n", + dprintk ("IOP state 0x%x InFrameSize = 0x%x\n", pPab->IOPState, pPab->InboundMFrameSize); return RC_RTN_NO_ERROR; } @@ -1862,11 +1767,11 @@ return RC_RTN_FREE_Q_EMPTY; } - /* calc virual address of msg - virual already mapped to physical */ + /* calc virtual address of msg - virtual already mapped to physical */ pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset); dprintk - ("SendEnableSysMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", + ("SendEnableSysMsg - pMsg = 0x%x, InQ msgOffset = 0x%x\n", (u32) pMsg, msgOffset); pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1885,7 +1790,7 @@ ** ========================================================================= ** FillI2OMsgFromTCB() ** -** inputs pMsgU32 - virual pointer (mapped to physical) of message frame +** inputs pMsgU32 - virtual pointer (mapped to physical) of message frame ** pXmitCntrlBlock - pointer to caller buffer control block. ** ** fills in LAN SGL after Transaction Control Word or Bucket Count. @@ -1908,9 +1813,9 @@ nmbrDwords = 0; dprintk ("FillI2OMsgSGLFromTCBX\n"); - dprintk ("TCB 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", + dprintk ("TCB 0x%x:0x%x:0x%x:0x%x:0x%x\n", pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]); - dprintk ("pTCB 0x%08ulx, pMsg 0x%08ulx\n", (u32) pTCB, (u32) pMsg); + dprintk ("pTCB 0x%x, pMsg 0x%x\n", (u32) pTCB, (u32) pMsg); nmbrBuffers = *pTCB++; @@ -1987,11 +1892,11 @@ p32 = (PU32) p8Msg; dprintk - ("VXD: ProcessOutboundI2OMsg - pPab 0x%08ulx, phyAdr 0x%08ulx, linAdr 0x%08ulx\n", + ("VXD: ProcessOutboundI2OMsg - pPab 0x%x, phyAdr 0x%x, linAdr 0x%x\n", (u32) pPab, phyAddrMsg, (u32) p8Msg); - dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1], + dprintk ("msg :0x%x:0x%x:0x%x:0x%x\n", p32[0], p32[1], p32[2], p32[3]); - dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5], + dprintk ("msg :0x%x:0x%x:0x%x:0x%x\n", p32[4], p32[5], p32[6], p32[7]); if (p32[4] >> 24 != I2O_REPLY_STATUS_SUCCESS) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/rclanmtl.h linux-2.5/drivers/net/rclanmtl.h --- linux-2.5.5/drivers/net/rclanmtl.h Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/net/rclanmtl.h Tue Feb 19 00:37:08 2002 @@ -54,10 +54,10 @@ #include /* Debug stuff. Define for debug output */ -#define RCDEBUG +#undef RCDEBUG #ifdef RCDEBUG -#define dprintk(args...) printk(KERN_DEBUG "(rcpci45 driver:) " args) +#define dprintk(args...) printk("rc: " args) #else #define dprintk(args...) { } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/rcpci45.c linux-2.5/drivers/net/rcpci45.c --- linux-2.5.5/drivers/net/rcpci45.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/rcpci45.c Mon Feb 18 22:04:29 2002 @@ -29,6 +29,9 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** +** Pete Popov, Oct 2001: Fixed a few bugs to make the driver functional +** again. Note that this card is not supported or manufactured by +** RedCreek anymore. ** ** Rasmus Andersen, December 2000: Converted to new PCI API and general ** cleanup. @@ -44,7 +47,10 @@ ** ***************************************************************************/ +#include // nuke me later. +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #include #include @@ -64,7 +70,7 @@ #include static char version[] __initdata = - "RedCreek Communications PCI linux driver version 2.03\n"; + "RedCreek Communications PCI linux driver version 2.20\n"; #define RC_LINUX_MODULE #include "rclanmtl.h" @@ -89,6 +95,14 @@ /* RedCreek's OSM default LAN receive Initiator */ #define DEFAULT_RECV_INIT_CONTEXT 0xA17 +/* minimum msg buffer size needed by the card + * Note that the size of this buffer is hard code in the + * ipsec card's firmware. Thus, the size MUST be a minimum + * of 16K. Otherwise the card will end up using memory + * that does not belong to it. + */ +#define MSG_BUF_SIZE 16384 + static U32 DriverControlWord; static void rc_timer (unsigned long); @@ -115,46 +129,32 @@ MODULE_DEVICE_TABLE (pci, rcpci45_pci_table); MODULE_LICENSE("GPL"); -static void __exit +static void __devexit rcpci45_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); PDPA pDpa = dev->priv; if (!dev) { - printk (KERN_ERR - "(rcpci45 driver:) remove non-existent device\n"); + printk (KERN_ERR "%s: remove non-existent device\n", + dev->name); return; } - dprintk ("remove_one: IOP reset: 0x%x\n", RCResetIOP (dev)); - - /* RAA Inspired by starfire.c and yellowfin.c we keep these - * here. */ + RCResetIOP (dev); unregister_netdev (dev); free_irq (dev->irq, dev); iounmap ((void *) dev->base_addr); pci_release_regions (pdev); - kfree (pDpa->PLanApiPA); - kfree (pDpa->pPab); - kfree (pDpa); + if (pDpa->msgbuf) + kfree (pDpa->msgbuf); + if (pDpa->pPab) + kfree (pDpa->pPab); kfree (dev); pci_set_drvdata (pdev, NULL); } static int -RCinit (struct net_device *dev) -{ - dev->open = &RCopen; - dev->hard_start_xmit = &RC_xmit_packet; - dev->stop = &RCclose; - dev->get_stats = &RCget_stats; - dev->do_ioctl = &RCioctl; - dev->set_config = &RCconfig; - return 0; -} - -static int rcpci45_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned long *vaddr; @@ -168,17 +168,17 @@ /* * Allocate and fill new device structure. - * We need enough for struct net_device plus DPA plus the LAN API private - * area, which requires a minimum of 16KB. The top of the allocated - * area will be assigned to struct net_device; the next chunk will be - * assigned to DPA; and finally, the rest will be assigned to the - * the LAN API layer. + * We need enough for struct net_device plus DPA plus the LAN + * API private area, which requires a minimum of 16KB. The top + * of the allocated area will be assigned to struct net_device; + * the next chunk will be assigned to DPA; and finally, the rest + * will be assigned to the the LAN API layer. */ dev = init_etherdev (NULL, sizeof (*pDpa)); if (!dev) { printk (KERN_ERR - "(rcpci45 driver:) unable to allocate in init_etherdev\n"); + "(rcpci45 driver:) init_etherdev alloc failed\n"); error = -ENOMEM; goto err_out; } @@ -186,13 +186,14 @@ error = pci_enable_device (pdev); if (error) { printk (KERN_ERR - "(rcpci45 driver:) %d: unable to enable pci device, aborting\n", + "(rcpci45 driver:) %d: pci enable device error\n", card_idx); goto err_out; } error = -ENOMEM; pci_start = pci_resource_start (pdev, 0); pci_len = pci_resource_len (pdev, 0); + printk("pci_start %x pci_len %x\n", pci_start, pci_len); pci_set_drvdata (pdev, dev); @@ -202,29 +203,30 @@ if (!pci_start || !(pci_resource_flags (pdev, 0) & IORESOURCE_MEM)) { printk (KERN_ERR - "(rcpci45 driver:) No PCI memory resources! Aborting.\n"); + "(rcpci45 driver:) No PCI mem resources! Aborting\n"); error = -EBUSY; goto err_out_free_dev; } /* - * Save the starting address of the LAN API private area. We'll - * pass that to RCInitI2OMsgLayer(). + * pDpa->msgbuf is where the card will dma the I2O + * messages. Thus, we need contiguous physical pages of + * memory. */ - /* RAA FIXME: This size should be a #define somewhere after I - * clear up some questions: What flags are neeeded in the alloc below - * and what needs to be done before the memarea is long word aligned? - * (Look in old code for an approach.) (Also note that the 16K below - * is substantially less than the 32K allocated before (even though - * some of the spacce was used for data structures.) */ - pDpa->msgbuf = kmalloc (16384, GFP_KERNEL); + pDpa->msgbuf = kmalloc (MSG_BUF_SIZE, GFP_DMA|GFP_ATOMIC|GFP_KERNEL); if (!pDpa->msgbuf) { - printk (KERN_ERR "(rcpci45 driver:) Could not allocate %d byte memory for the private msgbuf!\n", 16384); /* RAA FIXME not hardcoded! */ + printk (KERN_ERR "(rcpci45 driver:) \ + Could not allocate %d byte memory for the \ + private msgbuf!\n", MSG_BUF_SIZE); goto err_out_free_dev; } - pDpa->PLanApiPA = (void *) (((long) pDpa->msgbuf + 0xff) & ~0xff); - dprintk ("pDpa->PLanApiPA = 0x%x\n", (uint) pDpa->PLanApiPA); + /* + * Save the starting address of the LAN API private area. We'll + * pass that to RCInitI2OMsgLayer(). + * + */ + pDpa->PLanApiPA = (void *) (((long) pDpa->msgbuf + 0xff) & ~0xff); /* The adapter is accessible through memory-access read/write, not * I/O read/write. Thus, we need to map it to some virtual address @@ -237,17 +239,20 @@ vaddr = (ulong *) ioremap (pci_start, pci_len); if (!vaddr) { printk (KERN_ERR - "(rcpci45 driver:) Unable to remap address range from %lu to %lu\n", + "(rcpci45 driver:) \ + Unable to remap address range from %lu to %lu\n", pci_start, pci_start + pci_len); goto err_out_free_region; } - dprintk ("rcpci45_init_one: 0x%x, priv = 0x%x, vaddr = 0x%x\n", - (uint) dev, (uint) dev->priv, (uint) vaddr); dev->base_addr = (unsigned long) vaddr; dev->irq = pdev->irq; - - dev->init = &RCinit; + dev->open = &RCopen; + dev->hard_start_xmit = &RC_xmit_packet; + dev->stop = &RCclose; + dev->get_stats = &RCget_stats; + dev->do_ioctl = &RCioctl; + dev->set_config = &RCconfig; return 0; /* success */ @@ -260,23 +265,22 @@ kfree (dev); err_out: card_idx--; - return error; + return -ENODEV; } static struct pci_driver rcpci45_driver = { name: "rcpci45", id_table: rcpci45_pci_table, probe: rcpci45_init_one, - remove: rcpci45_remove_one, + remove: __devexit_p(rcpci45_remove_one), }; static int __init rcpci_init_module (void) { int rc = pci_module_init (&rcpci45_driver); - if (!rc) - printk (KERN_INFO "%s", version); + printk (KERN_ERR "%s", version); return rc; } @@ -289,56 +293,56 @@ int requested = 0; int error; - dprintk ("(rcpci45 driver:) RCopen\n"); + MOD_INC_USE_COUNT; + if (pDpa->nexus) { + /* This is not the first time RCopen is called. Thus, + * the interface was previously opened and later closed + * by RCclose(). RCclose() does a Shutdown; to wake up + * the adapter, a reset is mandatory before we can post + * receive buffers. However, if the adapter initiated + * a reboot while the interface was closed -- and interrupts + * were turned off -- we need will need to reinitialize + * the adapter, rather than simply waking it up. + */ + printk (KERN_INFO "Waking up adapter...\n"); + RCResetLANCard (dev, 0, 0, 0); + } else { + pDpa->nexus = 1; + /* + * RCInitI2OMsgLayer is done only once, unless the + * adapter was sent a warm reboot + */ + error = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, + (PFNRXCALLBACK) RCrecv_callback, + (PFNCALLBACK) RCreboot_callback); + if (error) { + printk (KERN_ERR "%s: Unable to init msg layer (%x)\n", + dev->name, error); + goto err_out; + } + if ((error = RCGetMAC (dev, NULL))) { + printk (KERN_ERR "%s: Unable to get adapter MAC\n", + dev->name); + goto err_out; + } + } /* Request a shared interrupt line. */ error = request_irq (dev->irq, RCinterrupt, SA_SHIRQ, dev->name, dev); if (error) { - printk (KERN_ERR "(rcpci45 driver:) %s: unable to get IRQ %d\n", - dev->name, dev->irq); + printk (KERN_ERR "%s: unable to get IRQ %d\n", + dev->name, dev->irq); goto err_out; } - error = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback, - (PFNRXCALLBACK) RCrecv_callback, - (PFNCALLBACK) RCreboot_callback); - if (error) { - printk (KERN_ERR - "(rcpci45 driver:) Unable to initialize msg layer\n"); - goto err_out_free_irq; - } - if ((error = RCGetMAC (dev, NULL))) { - printk (KERN_ERR - "(rcpci45 driver:) Unable to get adapter MAC\n"); - goto err_out_free_irq; - } - DriverControlWord |= WARM_REBOOT_CAPABLE; RCReportDriverCapability (dev, DriverControlWord); printk (KERN_INFO "%s: RedCreek Communications IPSEC VPN adapter\n", dev->name); - /* RAA: Old RCopen starts here */ RCEnableI2OInterrupts (dev); - /* RAA Hmm, how does the comment below jibe with the newly imported - * code above? A FIXME!!*/ - if (pDpa->nexus) { - /* This is not the first time RCopen is called. Thus, - * the interface was previously opened and later closed - * by RCclose(). RCclose() does a Shutdown; to wake up - * the adapter, a reset is mandatory before we can post - * receive buffers. However, if the adapter initiated - * a reboot while the interface was closed -- and interrupts - * were turned off -- we need will need to reinitialize - * the adapter, rather than simply waking it up. - */ - dprintk (KERN_INFO "Waking up adapter...\n"); - RCResetLANCard (dev, 0, 0, 0); - } else - pDpa->nexus = 1; - while (post_buffers) { if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG) requested = MAX_NMBR_POST_BUFFERS_PER_MSG; @@ -348,29 +352,30 @@ if (count < requested) { /* - * Check to see if we were able to post any buffers at all. + * Check to see if we were able to post + * any buffers at all. */ if (post_buffers == MAX_NMBR_RCV_BUFFERS) { - printk (KERN_ERR - "(rcpci45 driver:) Error RCopen: not able to allocate any buffers\r\n"); - return (-ENOMEM); + printk (KERN_ERR "%s: \ + unable to allocate any buffers\n", + dev->name); + goto err_out_free_irq; } - printk (KERN_WARNING - "(rcpci45 driver:) Warning RCopen: not able to allocate all requested buffers\r\n"); + printk (KERN_WARNING "%s: \ + unable to allocate all requested buffers\n", dev->name); break; /* we'll try to post more buffers later */ } else post_buffers -= count; } pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers; pDpa->shutdown = 0; /* just in case */ - dprintk ("RCopen: posted %d buffers\n", (uint) pDpa->numOutRcvBuffers); - MOD_INC_USE_COUNT; netif_start_queue (dev); return 0; err_out_free_irq: free_irq (dev->irq, dev); err_out: + MOD_DEC_USE_COUNT; return error; } @@ -386,15 +391,16 @@ netif_stop_queue (dev); if (pDpa->shutdown || pDpa->reboot) { - dprintk ("RC_xmit_packet: tbusy!\n"); + printk ("RC_xmit_packet: tbusy!\n"); return 1; } /* - * The user is free to reuse the TCB after RCI2OSendPacket() returns, since - * the function copies the necessary info into its own private space. Thus, - * our TCB can be a local structure. The skb, on the other hand, will be - * freed up in our interrupt handler. + * The user is free to reuse the TCB after RCI2OSendPacket() + * returns, since the function copies the necessary info into its + * own private space. Thus, our TCB can be a local structure. + * The skb, on the other hand, will be freed up in our interrupt + * handler. */ ptcb->bcount = 1; @@ -408,11 +414,9 @@ ptcb->b.size = skb->len; ptcb->b.addr = virt_to_bus ((void *) skb->data); - dprintk ("RC xmit: skb = 0x%x, pDpa = 0x%x, id = %d, ptcb = 0x%x\n", - (uint) skb, (uint) pDpa, (uint) pDpa->id, (uint) ptcb); if ((status = RCI2OSendPacket (dev, (U32) NULL, (PRCTCB) ptcb)) != RC_RTN_NO_ERROR) { - dprintk ("RC send error 0x%x\n", (uint) status); + printk ("%s: send error 0x%x\n", dev->name, (uint) status); return 1; } else { dev->trans_start = jiffies; @@ -442,23 +446,20 @@ PDPA pDpa = dev->priv; if (!pDpa) { - printk (KERN_ERR - "(rcpci45 driver:) Fatal error: xmit callback, !pDpa\n"); + printk (KERN_ERR "%s: Fatal Error in xmit callback, !pDpa\n", + dev->name); return; } -/* dprintk("xmit_callback: Status = 0x%x\n", (uint)Status); */ if (Status != I2O_REPLY_STATUS_SUCCESS) - dprintk ("xmit_callback: Status = 0x%x\n", (uint) Status); + printk (KERN_INFO "%s: xmit_callback: Status = 0x%x\n", + dev->name, (uint) Status); if (pDpa->shutdown || pDpa->reboot) - dprintk ("xmit callback: shutdown||reboot\n"); - - dprintk ("xmit_callback: PcktCount = %d, BC = 0x%x\n", - (uint) PcktCount, (uint) BufferContext); + printk (KERN_INFO "%s: xmit callback: shutdown||reboot\n", + dev->name); while (PcktCount--) { skb = (struct sk_buff *) (BufferContext[0]); - dprintk ("skb = 0x%x\n", (uint) skb); BufferContext++; dev_kfree_skb_irq (skb); } @@ -470,19 +471,18 @@ { PDPA pDpa = dev->priv; - dprintk ("RCreset_callback Status 0x%x\n", (uint) Status); + printk ("RCreset_callback Status 0x%x\n", (uint) Status); /* * Check to see why we were called. */ if (pDpa->shutdown) { - printk (KERN_INFO - "(rcpci45 driver:) Shutting down interface\n"); + printk (KERN_INFO "%s: shutting down interface\n", + dev->name); pDpa->shutdown = 0; pDpa->reboot = 0; - MOD_DEC_USE_COUNT; } else if (pDpa->reboot) { - printk (KERN_INFO - "(rcpci45 driver:) reboot, shutdown adapter\n"); + printk (KERN_INFO "%s: reboot, shutdown adapter\n", + dev->name); /* * We don't set any of the flags in RCShutdownLANCard() * and we don't pass a callback routine to it. @@ -491,7 +491,7 @@ */ RCDisableI2OInterrupts (dev); RCShutdownLANCard (dev, 0, 0, 0); - printk (KERN_INFO "(rcpci45 driver:) scheduling timer...\n"); + printk (KERN_INFO "%s: scheduling timer...\n", dev->name); init_timer (&pDpa->timer); pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); /* 4 sec. */ pDpa->timer.data = (unsigned long) dev; @@ -505,12 +505,12 @@ { PDPA pDpa = dev->priv; - dprintk ("RCreboot: rcv buffers outstanding = %d\n", - (uint) pDpa->numOutRcvBuffers); + printk (KERN_INFO "%s: reboot: rcv buffers outstanding = %d\n", + dev->name, (uint) pDpa->numOutRcvBuffers); if (pDpa->shutdown) { - printk (KERN_INFO - "(rcpci45 driver:) skipping reboot sequence -- shutdown already initiated\n"); + printk (KERN_INFO "%s: skip reboot, shutdown initiated\n", + dev->name); return; } pDpa->reboot = 1; @@ -562,12 +562,9 @@ ptcb->bcount = 1; - dprintk ("RCrecv_callback: 0x%x, 0x%x, 0x%x\n", - (uint) PktCount, (uint) BucketsRemain, (uint) PacketDescBlock); - if ((pDpa->shutdown || pDpa->reboot) && !Status) - dprintk ("shutdown||reboot && !Status: PktCount = %d\n", - PktCount); + printk (KERN_INFO "%s: shutdown||reboot && !Status (%d)\n", + dev->name, PktCount); if ((Status != I2O_REPLY_STATUS_SUCCESS) || pDpa->shutdown) { /* @@ -576,76 +573,38 @@ */ if (!pDpa->shutdown && !pDpa->reboot) - printk (KERN_INFO - "(rcpci45 driver:) RCrecv error: status = 0x%x\n", - (uint) Status); + printk (KERN_INFO "%s: recv error status = 0x%x\n", + dev->name, (uint) Status); else - dprintk ("Returning %d buffers, status = 0x%x\n", - PktCount, (uint) Status); + printk (KERN_DEBUG "%s: Returning %d buffs stat 0x%x\n", + dev->name, PktCount, (uint) Status); /* - * TO DO: check the nature of the failure and put the adapter in - * failed mode if it's a hard failure. Send a reset to the adapter - * and free all outstanding memory. + * TO DO: check the nature of the failure and put the + * adapter in failed mode if it's a hard failure. + * Send a reset to the adapter and free all outstanding memory. */ - if (Status == I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER) - dprintk ("RCrecv status ABORT NO DATA TRANSFER\n"); - - /* check for reset status: I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER */ if (PacketDescBlock) { while (PktCount--) { skb = (struct sk_buff *) PacketDescBlock[0]; - dprintk ("free skb 0x%p\n", skb); dev_kfree_skb (skb); pDpa->numOutRcvBuffers--; - PacketDescBlock += BD_SIZE; /* point to next context field */ + /* point to next context field */ + PacketDescBlock += BD_SIZE; } } return; } else { while (PktCount--) { skb = (struct sk_buff *) PacketDescBlock[0]; - if (pDpa->shutdown) - dprintk ("shutdown: skb=0x%x\n", (uint) skb); - - dprintk ("skb = 0x%x: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", - (uint) skb, (uint) skb->data[0], - (uint) skb->data[1], (uint) skb->data[2], - (uint) skb->data[3], (uint) skb->data[4], - (uint) skb->data[5]); - -#ifdef PROMISCUOUS_BY_DEFAULT /* early 2.x firmware */ - if ((memcmp (dev->dev_addr, skb->data, 6)) && - (!broadcast_packet (skb->data))) { - /* - * Re-post the buffer to the adapter. Since the adapter usually - * return 1 to 2 receive buffers at a time, it's not too inefficient - * post one buffer at a time but ... may be that should be - * optimized at some point. - */ - ptcb->b.context = (U32) skb; - ptcb->b.scount = 1; - ptcb->b.size = MAX_ETHER_SIZE; - ptcb->b.addr = virt_to_bus ((void *) skb->data); - - if (RCPostRecvBuffers (dev, (PRCTCB) ptcb) != - RC_RTN_NO_ERROR) { - printk (KERN_WARNING - "(rcpci45 driver:) RCrecv_callback: post buffer failed!\n"); - dev_kfree_skb (skb); - } else - pDpa->numOutRcvBuffers++; - } else -#endif /* PROMISCUOUS_BY_DEFAULT */ - { - len = PacketDescBlock[2]; - skb->dev = dev; - skb_put (skb, len); /* adjust length and tail */ - skb->protocol = eth_type_trans (skb, dev); - netif_rx (skb); /* send the packet to the kernel */ - dev->last_rx = jiffies; - } - pDpa->numOutRcvBuffers--; - PacketDescBlock += BD_SIZE; /* point to next context field */ + len = PacketDescBlock[2]; + skb->dev = dev; + skb_put (skb, len); /* adjust length and tail */ + skb->protocol = eth_type_trans (skb, dev); + netif_rx (skb); /* send the packet to the kernel */ + dev->last_rx = jiffies; + pDpa->numOutRcvBuffers--; + /* point to next context field */ + PacketDescBlock += BD_SIZE; } } @@ -682,11 +641,8 @@ pDpa = dev->priv; if (pDpa->shutdown) - dprintk ("shutdown: service irq\n"); - - dprintk ("RC irq: pDpa = 0x%x, dev = 0x%x, id = %d\n", - (uint) pDpa, (uint) dev, (uint) pDpa->id); - dprintk ("dev = 0x%x\n", (uint) dev); + printk (KERN_DEBUG "%s: shutdown, service irq\n", + dev->name); RCProcI2OMsgQ (dev); } @@ -717,62 +673,60 @@ RCReportDriverCapability (dev, DriverControlWord); RCEnableI2OInterrupts (dev); - if (dev->flags & IFF_UP) { - while (post_buffers) { - if (post_buffers > - MAX_NMBR_POST_BUFFERS_PER_MSG) - requested = - MAX_NMBR_POST_BUFFERS_PER_MSG; - else - requested = post_buffers; - count = - RC_allocate_and_post_buffers (dev, - requested); - post_buffers -= count; - if (count < requested) - break; - } - pDpa->numOutRcvBuffers = - MAX_NMBR_RCV_BUFFERS - post_buffers; - dprintk ("rc: posted %d buffers \r\n", - (uint) pDpa->numOutRcvBuffers); + + if (!(dev->flags & IFF_UP)) { + retry = 0; + return; + } + while (post_buffers) { + if (post_buffers > + MAX_NMBR_POST_BUFFERS_PER_MSG) + requested = + MAX_NMBR_POST_BUFFERS_PER_MSG; + else + requested = post_buffers; + count = + RC_allocate_and_post_buffers (dev, + requested); + post_buffers -= count; + if (count < requested) + break; } - dprintk ("Initialization done.\n"); + pDpa->numOutRcvBuffers = + MAX_NMBR_RCV_BUFFERS - post_buffers; + printk ("Initialization done.\n"); netif_wake_queue (dev); retry = 0; return; case RC_RTN_FREE_Q_EMPTY: retry++; - printk (KERN_WARNING - "(rcpci45 driver:) inbound free q empty\n"); + printk (KERN_WARNING "%s inbound free q empty\n", + dev->name); break; default: retry++; - printk (KERN_WARNING - "(rcpci45 driver:) bad status after reboot: %d\n", - init_status); + printk (KERN_WARNING "%s bad stat after reboot: %d\n", + dev->name, init_status); break; } if (retry > REBOOT_REINIT_RETRY_LIMIT) { - printk (KERN_WARNING - "(rcpci45 driver:) unable to reinitialize adapter after reboot\n"); - printk (KERN_WARNING - "(rcpci45 driver:) decrementing driver and closing interface\n"); + printk (KERN_WARNING "%s unable to reinitialize adapter after reboot\n", dev->name); + printk (KERN_WARNING "%s decrementing driver and closing interface\n", dev->name); RCDisableI2OInterrupts (dev); dev->flags &= ~IFF_UP; MOD_DEC_USE_COUNT; } else { - printk (KERN_INFO - "(rcpci45 driver:) rescheduling timer...\n"); + printk (KERN_INFO "%s: rescheduling timer...\n", + dev->name); init_timer (&pDpa->timer); - pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); /* 3 sec. */ + pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); pDpa->timer.data = (unsigned long) dev; - pDpa->timer.function = &rc_timer; /* timer handler */ + pDpa->timer.function = &rc_timer; add_timer (&pDpa->timer); } } else - printk (KERN_WARNING "(rcpci45 driver:) timer??\n"); + printk (KERN_WARNING "%s: unexpected timer irq\n", dev->name); } static int @@ -780,19 +734,16 @@ { PDPA pDpa = dev->priv; + printk("RCclose\n"); netif_stop_queue (dev); - dprintk ("RCclose\r\n"); - if (pDpa->reboot) { - printk (KERN_INFO - "(rcpci45 driver:) skipping reset -- adapter already in reboot mode\n"); + printk (KERN_INFO "%s skipping reset -- adapter already in reboot mode\n", dev->name); dev->flags &= ~IFF_UP; pDpa->shutdown = 1; + MOD_DEC_USE_COUNT; return 0; } - dprintk ("receive buffers outstanding: %d\n", - (uint) pDpa->numOutRcvBuffers); pDpa->shutdown = 1; @@ -808,6 +759,7 @@ (PFNCALLBACK) RCreset_callback); dev->flags &= ~IFF_UP; + MOD_DEC_USE_COUNT; return 0; } @@ -819,56 +771,42 @@ PDPA pDpa = dev->priv; if (!pDpa) { - dprintk ("RCget_stats: !pDpa\n"); return 0; } else if (!(dev->flags & IFF_UP)) { - dprintk ("RCget_stats: device down\n"); return 0; } memset (&RCstats, 0, sizeof (RCLINKSTATS)); if ((RCGetLinkStatistics (dev, &RCstats, (void *) 0)) == RC_RTN_NO_ERROR) { - dprintk ("TX_good 0x%x\n", (uint) RCstats.TX_good); - dprintk ("TX_maxcol 0x%x\n", (uint) RCstats.TX_maxcol); - dprintk ("TX_latecol 0x%x\n", (uint) RCstats.TX_latecol); - dprintk ("TX_urun 0x%x\n", (uint) RCstats.TX_urun); - dprintk ("TX_crs 0x%x\n", (uint) RCstats.TX_crs); - dprintk ("TX_def 0x%x\n", (uint) RCstats.TX_def); - dprintk ("TX_singlecol 0x%x\n", (uint) RCstats.TX_singlecol); - dprintk ("TX_multcol 0x%x\n", (uint) RCstats.TX_multcol); - dprintk ("TX_totcol 0x%x\n", (uint) RCstats.TX_totcol); - - dprintk ("Rcv_good 0x%x\n", (uint) RCstats.Rcv_good); - dprintk ("Rcv_CRCerr 0x%x\n", (uint) RCstats.Rcv_CRCerr); - dprintk ("Rcv_alignerr 0x%x\n", (uint) RCstats.Rcv_alignerr); - dprintk ("Rcv_reserr 0x%x\n", (uint) RCstats.Rcv_reserr); - dprintk ("Rcv_orun 0x%x\n", (uint) RCstats.Rcv_orun); - dprintk ("Rcv_cdt 0x%x\n", (uint) RCstats.Rcv_cdt); - dprintk ("Rcv_runt 0x%x\n", (uint) RCstats.Rcv_runt); - - pDpa->stats.rx_packets = RCstats.Rcv_good; /* total packets received */ - pDpa->stats.tx_packets = RCstats.TX_good; /* total packets transmitted */ - pDpa->stats.rx_errors = RCstats.Rcv_CRCerr + RCstats.Rcv_alignerr + RCstats.Rcv_reserr + RCstats.Rcv_orun + RCstats.Rcv_cdt + RCstats.Rcv_runt; /* bad packets received */ + /* total packets received */ + pDpa->stats.rx_packets = RCstats.Rcv_good + /* total packets transmitted */; + pDpa->stats.tx_packets = RCstats.TX_good; + + pDpa->stats.rx_errors = RCstats.Rcv_CRCerr + + RCstats.Rcv_alignerr + RCstats.Rcv_reserr + + RCstats.Rcv_orun + RCstats.Rcv_cdt + RCstats.Rcv_runt; - pDpa->stats.tx_errors = RCstats.TX_urun + RCstats.TX_crs + RCstats.TX_def + RCstats.TX_totcol; /* packet transmit problems */ + pDpa->stats.tx_errors = RCstats.TX_urun + RCstats.TX_crs + + RCstats.TX_def + RCstats.TX_totcol; /* * This needs improvement. */ - pDpa->stats.rx_dropped = 0; /* no space in linux buffers */ - pDpa->stats.tx_dropped = 0; /* no space available in linux */ - pDpa->stats.multicast = 0; /* multicast packets received */ + pDpa->stats.rx_dropped = 0; /* no space in linux buffers */ + pDpa->stats.tx_dropped = 0; /* no space available in linux */ + pDpa->stats.multicast = 0; /* multicast packets received */ pDpa->stats.collisions = RCstats.TX_totcol; /* detailed rx_errors: */ pDpa->stats.rx_length_errors = 0; - pDpa->stats.rx_over_errors = RCstats.Rcv_orun; /* receiver ring buff overflow */ - pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr; /* recved pkt with crc error */ - pDpa->stats.rx_frame_errors = 0; /* recv'd frame alignment error */ - pDpa->stats.rx_fifo_errors = 0; /* recv'r fifo overrun */ - pDpa->stats.rx_missed_errors = 0; /* receiver missed packet */ + pDpa->stats.rx_over_errors = RCstats.Rcv_orun; + pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr; + pDpa->stats.rx_frame_errors = 0; + pDpa->stats.rx_fifo_errors = 0; + pDpa->stats.rx_missed_errors = 0; /* detailed tx_errors */ pDpa->stats.tx_aborted_errors = 0; @@ -888,8 +826,6 @@ RCuser_struct RCuser; PDPA pDpa = dev->priv; - dprintk ("RCioctl: cmd = 0x%x\n", cmd); - if (!capable (CAP_NET_ADMIN)) return -EPERM; @@ -913,16 +849,12 @@ switch (RCuser.cmd) { case RCUC_GETFWVER: - printk (KERN_INFO - "(rcpci45 driver:) RC GETFWVER\n"); RCUD_GETFWVER = &RCuser.RCUS_GETFWVER; RCGetFirmwareVer (dev, (PU8) & RCUD_GETFWVER-> FirmString, NULL); break; case RCUC_GETINFO: - printk (KERN_INFO - "(rcpci45 driver:) RC GETINFO\n"); RCUD_GETINFO = &RCuser.RCUS_GETINFO; RCUD_GETINFO->mem_start = dev->base_addr; RCUD_GETINFO->mem_end = @@ -931,8 +863,6 @@ RCUD_GETINFO->irq = dev->irq; break; case RCUC_GETIPANDMASK: - printk (KERN_INFO - "(rcpci45 driver:) RC GETIPANDMASK\n"); RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK; RCGetRavlinIPandMask (dev, (PU32) & @@ -942,8 +872,6 @@ NetMask, NULL); break; case RCUC_GETLINKSTATISTICS: - printk (KERN_INFO - "(rcpci45 driver:) RC GETLINKSTATISTICS\n"); RCUD_GETLINKSTATISTICS = &RCuser.RCUS_GETLINKSTATISTICS; RCGetLinkStatistics (dev, @@ -952,75 +880,39 @@ StatsReturn, NULL); break; case RCUC_GETLINKSTATUS: - printk (KERN_INFO - "(rcpci45 driver:) RC GETLINKSTATUS\n"); RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS; RCGetLinkStatus (dev, (PU32) & RCUD_GETLINKSTATUS-> ReturnStatus, NULL); break; case RCUC_GETMAC: - printk (KERN_INFO - "(rcpci45 driver:) RC GETMAC\n"); RCUD_GETMAC = &RCuser.RCUS_GETMAC; RCGetMAC (dev, NULL); + memcpy(RCUD_GETMAC, dev->dev_addr, 8); break; case RCUC_GETPROM: - printk (KERN_INFO - "(rcpci45 driver:) RC GETPROM\n"); RCUD_GETPROM = &RCuser.RCUS_GETPROM; RCGetPromiscuousMode (dev, (PU32) & RCUD_GETPROM-> PromMode, NULL); break; case RCUC_GETBROADCAST: - printk (KERN_INFO - "(rcpci45 driver:) RC GETBROADCAST\n"); RCUD_GETBROADCAST = &RCuser.RCUS_GETBROADCAST; RCGetBroadcastMode (dev, (PU32) & RCUD_GETBROADCAST-> BroadcastMode, NULL); break; case RCUC_GETSPEED: - printk (KERN_INFO - "(rcpci45 driver:) RC GETSPEED\n"); if (!(dev->flags & IFF_UP)) { - printk (KERN_ERR - "(rcpci45 driver:) RCioctl, GETSPEED error: interface down\n"); return -ENODATA; } RCUD_GETSPEED = &RCuser.RCUS_GETSPEED; RCGetLinkSpeed (dev, (PU32) & RCUD_GETSPEED-> LinkSpeedCode, NULL); - printk (KERN_INFO - "(rcpci45 driver:) RC speed = 0x%u\n", - RCUD_GETSPEED->LinkSpeedCode); break; case RCUC_SETIPANDMASK: - printk (KERN_INFO - "(rcpci45 driver:) RC SETIPANDMASK\n"); RCUD_SETIPANDMASK = &RCuser.RCUS_SETIPANDMASK; - printk (KERN_INFO - "(rcpci45 driver:) RC New IP Addr = %d.%d.%d.%d, ", - (U8) ((RCUD_SETIPANDMASK-> - IpAddr) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - IpAddr >> 8) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - IpAddr >> 16) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - IpAddr >> 24) & 0xff)); - printk (KERN_INFO - "(rcpci45 driver:) RC New Mask = %d.%d.%d.%d\n", - (U8) ((RCUD_SETIPANDMASK-> - NetMask) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - NetMask >> 8) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - NetMask >> 16) & 0xff), - (U8) ((RCUD_SETIPANDMASK-> - NetMask >> 24) & 0xff)); RCSetRavlinIPandMask (dev, (U32) RCUD_SETIPANDMASK-> IpAddr, @@ -1028,61 +920,33 @@ NetMask); break; case RCUC_SETMAC: - printk (KERN_INFO - "(rcpci45 driver:) RC SETMAC\n"); - RCUD_SETMAC = &RCuser.RCUS_SETMAC; - printk (KERN_INFO - "(rcpci45 driver:) RC New MAC addr = %02X:%02X:%02X:%02X:%02X:%02X\n", - (U8) (RCUD_SETMAC->mac[0]), - (U8) (RCUD_SETMAC->mac[1]), - (U8) (RCUD_SETMAC->mac[2]), - (U8) (RCUD_SETMAC->mac[3]), - (U8) (RCUD_SETMAC->mac[4]), - (U8) (RCUD_SETMAC->mac[5])); RCSetMAC (dev, (PU8) & RCUD_SETMAC->mac); break; case RCUC_SETSPEED: - printk (KERN_INFO - "(rcpci45 driver:) RC SETSPEED\n"); RCUD_SETSPEED = &RCuser.RCUS_SETSPEED; RCSetLinkSpeed (dev, (U16) RCUD_SETSPEED-> LinkSpeedCode); - printk (KERN_INFO - "(rcpci45 driver:) RC New speed = 0x%x\n", - RCUD_SETSPEED->LinkSpeedCode); break; case RCUC_SETPROM: - printk (KERN_INFO - "(rcpci45 driver:) RC SETPROM\n"); RCUD_SETPROM = &RCuser.RCUS_SETPROM; RCSetPromiscuousMode (dev, (U16) RCUD_SETPROM-> PromMode); - printk (KERN_INFO - "(rcpci45 driver:) RC New prom mode = 0x%x\n", - RCUD_SETPROM->PromMode); break; case RCUC_SETBROADCAST: - printk (KERN_INFO - "(rcpci45 driver:) RC SETBROADCAST\n"); RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST; RCSetBroadcastMode (dev, (U16) RCUD_SETBROADCAST-> BroadcastMode); - printk (KERN_INFO - "(rcpci45 driver:) RC New broadcast mode = 0x%x\n", - RCUD_SETBROADCAST->BroadcastMode); break; default: - printk (KERN_INFO - "(rcpci45 driver:) RC command default\n"); RCUD_DEFAULT = &RCuser.RCUS_DEFAULT; RCUD_DEFAULT->rc = 0x11223344; break; } - if (copy_to_user - (rq->ifr_data, &RCuser, sizeof (RCuser))) + if (copy_to_user (rq->ifr_data, &RCuser, + sizeof (RCuser))) return -EFAULT; break; } /* RCU_COMMAND */ @@ -1100,15 +964,14 @@ /* * To be completed ... */ - dprintk ("RCconfig\n"); return 0; if (dev->flags & IFF_UP) /* can't act on a running interface */ return -EBUSY; /* Don't allow changing the I/O address */ if (map->base_addr != dev->base_addr) { - printk (KERN_WARNING - "(rcpci45 driver:) Change I/O address not implemented\n"); + printk (KERN_WARNING "%s Change I/O address not implemented\n", + dev->name); return -EOPNOTSUPP; } return 0; @@ -1137,44 +1000,36 @@ if (!numBuffers) return 0; else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG) { - dprintk ("Too many buffers requested!\n"); - dprintk ("attempting to allocate only 32 buffers\n"); + printk (KERN_ERR "%s: Too many buffers requested!\n", + dev->name); numBuffers = 32; } p = (PU32) kmalloc (sizeof (U32) + numBuffers * sizeof (singleB), - GFP_KERNEL); - - dprintk ("TCB = 0x%x\n", (uint) p); + GFP_DMA|GFP_ATOMIC|GFP_KERNEL); if (!p) { - printk (KERN_WARNING - "(rcpci45 driver:) RCopen: unable to allocate TCB\n"); + printk (KERN_WARNING "%s unable to allocate TCB\n", + dev->name); return 0; } p[0] = 0; /* Buffer Count */ - pB = (psingleB) ((U32) p + sizeof (U32)); /* point to the first buffer */ - - dprintk ("p[0] = 0x%x, p = 0x%x, pB = 0x%x\n", (uint) p[0], (uint) p, - (uint) pB); - dprintk ("pB = 0x%x\n", (uint) pB); + pB = (psingleB) ((U32) p + sizeof (U32));/* point to the first buffer */ for (i = 0; i < numBuffers; i++) { skb = dev_alloc_skb (MAX_ETHER_SIZE + 2); if (!skb) { - dprintk - ("Doh! RCopen: unable to allocate enough skbs!\n"); - if (*p != 0) { /* did we allocate any buffers at all? */ - dprintk ("will post only %d buffers \n", - (uint) (*p)); + printk (KERN_WARNING + "%s: unable to allocate enough skbs!\n", + dev->name); + if (*p != 0) { /* did we allocate any buffers */ break; } else { kfree (p); /* Free the TCB */ return 0; } } - dprintk ("post 0x%x\n", (uint) skb); skb_reserve (skb, 2); /* Align IP on 16 byte boundaries */ pB->context = (U32) skb; pB->scount = 1; /* segment count */ @@ -1185,18 +1040,16 @@ } if ((status = RCPostRecvBuffers (dev, (PRCTCB) p)) != RC_RTN_NO_ERROR) { - printk (KERN_WARNING - "(rcpci45 driver:) Post buffer failed with error code 0x%x!\n", - status); - pB = (psingleB) ((U32) p + sizeof (U32)); /* point to the first buffer */ + printk (KERN_WARNING "%s: Post buffer failed, error 0x%x\n", + dev->name, status); + /* point to the first buffer */ + pB = (psingleB) ((U32) p + sizeof (U32)); while (p[0]) { skb = (struct sk_buff *) pB->context; - dprintk ("freeing 0x%x\n", (uint) skb); dev_kfree_skb (skb); p[0]--; pB++; } - dprintk ("freed all buffers, p[0] = %d\n", (uint) p[0]); } res = p[0]; kfree (p); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/rrunner.c linux-2.5/drivers/net/rrunner.c --- linux-2.5.5/drivers/net/rrunner.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/rrunner.c Sun Mar 3 17:54:35 2002 @@ -21,13 +21,15 @@ * ODS/Essential. */ +#include +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #define DEBUG 1 #define RX_DMA_SKBUFF 1 #define PKT_COPY_THRESHOLD 512 -#include #include #include #include @@ -75,13 +77,13 @@ #define rr_mark_net_bh(foo) mark_bh(foo) #define rr_if_busy(dev) dev->tbusy #define rr_if_running(dev) dev->start /* Currently unused. */ -#define rr_if_down(dev) {do{dev->start = 0;}while (0);} +#define rr_if_down(dev) do { dev->start = 0; } while (0) #else #define NET_BH 0 -#define rr_mark_net_bh(foo) {do{} while(0);} +#define rr_mark_net_bh(foo) do { } while(0) #define rr_if_busy(dev) netif_queue_stopped(dev) #define rr_if_running(dev) netif_running(dev) -#define rr_if_down(dev) {do{} while(0);} +#define rr_if_down(dev) do { } while(0) #endif #include "rrunner.h" @@ -271,6 +273,7 @@ #if LINUX_VERSION_CODE > 0x20118 MODULE_AUTHOR("Jes Sorensen "); MODULE_DESCRIPTION("Essential RoadRunner HIPPI driver"); +MODULE_LICENSE("GPL"); #endif int init_module(void) @@ -772,7 +775,7 @@ * Give the FirmWare time to chew on the `get running' command. */ myjif = jiffies + 5 * HZ; - while ((jiffies < myjif) && !rrpriv->fw_running); + while (time_before(jiffies, myjif) && !rrpriv->fw_running); netif_start_queue(dev); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/saa9730.c linux-2.5/drivers/net/saa9730.c --- linux-2.5.5/drivers/net/saa9730.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/net/saa9730.c Sun Mar 3 20:15:15 2002 @@ -685,6 +685,7 @@ len, 0); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); + dev->last_rx = jiffies; } } else { /* We got an error packet. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/sb1000.c linux-2.5/drivers/net/sb1000.c --- linux-2.5.5/drivers/net/sb1000.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/net/sb1000.c Sun Mar 3 17:54:35 2002 @@ -405,7 +405,7 @@ } timeout = jiffies + Sb1000TimeOutJiffies; while (!(inb(ioaddr[1] + 6) & 0x40)) { - if (jiffies >= timeout) { + if (time_after_eq(jiffies, timeout)) { printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n", name); return -ETIME; @@ -423,7 +423,7 @@ timeout = jiffies + Sb1000TimeOutJiffies; while (inb(ioaddr[1] + 6) & 0x80) { - if (jiffies >= timeout) { + if (time_after_eq(jiffies, timeout)) { printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n", name); return -ETIME; @@ -431,7 +431,7 @@ } timeout = jiffies + Sb1000TimeOutJiffies; while (inb(ioaddr[1] + 6) & 0x40) { - if (jiffies >= timeout) { + if (time_after_eq(jiffies, timeout)) { printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n", name); return -ETIME; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/sb1250-mac.c linux-2.5/drivers/net/sb1250-mac.c --- linux-2.5.5/drivers/net/sb1250-mac.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/sb1250-mac.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,2673 @@ +/* + * Copyright (C) 2001 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + This driver is designed for the Broadcom BCM12500 SOC chip's built-in + Ethernet controllers. + + The author may be reached as mpl@broadcom.com +*/ + + +/* A few user-configurable values. + These may be modified when a driver module is loaded. */ + +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ + +/* Used to pass the media type, etc. + Both 'options[]' and 'full_duplex[]' should exist for driver + interoperability. + The media type is usually passed in 'options[]'. +*/ + +#define MAX_UNITS 3 /* More are supported, limit only on options */ +#ifdef MODULE +static int options[MAX_UNITS] = {-1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1}; +#endif + + +/* Operational parameters that usually are not changed. */ + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include +#include + +/* This is only here until the firmware is ready. In that case, + the firmware leaves the ethernet address in the register for us. */ +#ifdef CONFIG_SWARM_STANDALONE +#define SBMAC_ETH0_HWADDR "40:00:00:00:01:00" +#define SBMAC_ETH1_HWADDR "40:00:00:00:01:01" +#define SBMAC_ETH2_HWADDR "40:00:00:00:01:02" +#endif + + +/* These identify the driver base version and may not be removed. */ +#if 0 +static char version1[] __devinitdata = +"sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg (mpl@broadcom.com)\n"; +#endif + + + +MODULE_AUTHOR("Mitch Lichtenberg (mpl@broadcom.com)"); +MODULE_DESCRIPTION("Broadcom BCM12500 SOC GB Ethernet driver"); +MODULE_PARM(debug, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + + +#include +#include +#include +#include +#include + + +/********************************************************************** + * Simple types + ********************************************************************* */ + + +typedef unsigned long sbmac_port_t; +typedef uint64_t sbmac_physaddr_t; +typedef uint64_t sbmac_enetaddr_t; + +typedef enum { sbmac_speed_auto, sbmac_speed_10, + sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t; + +typedef enum { sbmac_duplex_auto, sbmac_duplex_half, + sbmac_duplex_full } sbmac_duplex_t; + +typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame, + sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t; + +typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, + sbmac_state_broken } sbmac_state_t; + + +/********************************************************************** + * Macros + ********************************************************************* */ + + +#define SBDMA_NEXTBUF(d,f) ((((d)->f+1) == (d)->sbdma_dscrtable_end) ? \ + (d)->sbdma_dscrtable : (d)->f+1) + + +#define CACHELINESIZE 32 +#define NUMCACHEBLKS(x) (((x)+CACHELINESIZE-1)/CACHELINESIZE) +#define KMALLOC(x) kmalloc((x),GFP_KERNEL) +#define KFREE(x) kfree(x) +#define KVTOPHYS(x) virt_to_bus((void *)(x)) + + +#define SBMAC_READCSR(t) (in64((unsigned long)(t))) +#define SBMAC_WRITECSR(t,v) (out64(v, (unsigned long)(t))) + +#define PKSEG1(x) ((sbmac_port_t) KSEG1ADDR(x)) + +#define SBMAC_MAX_TXDESCR 32 +#define SBMAC_MAX_RXDESCR 32 + +#define ETHER_ALIGN 2 +#define ETHER_ADDR_LEN 6 +#define ENET_PACKET_SIZE 1518 + +/********************************************************************** + * DMA Descriptor structure + ********************************************************************* */ + +typedef struct sbdmadscr_s { + uint64_t dscr_a; + uint64_t dscr_b; +} sbdmadscr_t; + +typedef unsigned long paddr_t; +typedef unsigned long vaddr_t; + +/********************************************************************** + * DMA Controller structure + ********************************************************************* */ + +typedef struct sbmacdma_s { + + /* + * This stuff is used to identify the channel and the registers + * associated with it. + */ + + struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */ + int sbdma_channel; /* channel number */ + int sbdma_txdir; /* direction (1=transmit) */ + int sbdma_maxdescr; /* total # of descriptors in ring */ + sbmac_port_t sbdma_config0; /* DMA config register 0 */ + sbmac_port_t sbdma_config1; /* DMA config register 1 */ + sbmac_port_t sbdma_dscrbase; /* Descriptor base address */ + sbmac_port_t sbdma_dscrcnt; /* Descriptor count register */ + sbmac_port_t sbdma_curdscr; /* current descriptor address */ + + /* + * This stuff is for maintenance of the ring + */ + + sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */ + sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */ + + struct sk_buff **sbdma_ctxtable; /* context table, one per descr */ + + paddr_t sbdma_dscrtable_phys; /* and also the phys addr */ + sbdmadscr_t *sbdma_addptr; /* next dscr for sw to add */ + sbdmadscr_t *sbdma_remptr; /* next dscr for sw to remove */ + +} sbmacdma_t; + + +/********************************************************************** + * Ethernet softc structure + ********************************************************************* */ + +struct sbmac_softc { + + /* + * Linux-specific things + */ + + struct net_device *sbm_dev; /* pointer to linux device */ + spinlock_t sbm_lock; /* spin lock */ + struct timer_list sbm_timer; /* for monitoring MII */ + struct net_device_stats sbm_stats; + int sbm_devflags; /* current device flags */ + + int sbm_phy_oldbmsr; + int sbm_phy_oldanlpar; + int sbm_phy_oldk1stsr; + int sbm_phy_oldlinkstat; + int sbm_buffersize; + + unsigned char sbm_phys[2]; + + /* + * Controller-specific things + */ + + sbmac_port_t sbm_base; /* MAC's base address */ + sbmac_state_t sbm_state; /* current state */ + + sbmac_port_t sbm_macenable; /* MAC Enable Register */ + sbmac_port_t sbm_maccfg; /* MAC Configuration Register */ + sbmac_port_t sbm_fifocfg; /* FIFO configuration register */ + sbmac_port_t sbm_framecfg; /* Frame configuration register */ + sbmac_port_t sbm_rxfilter; /* receive filter register */ + sbmac_port_t sbm_isr; /* Interrupt status register */ + sbmac_port_t sbm_imr; /* Interrupt mask register */ + sbmac_port_t sbm_mdio; /* MDIO register */ + + sbmac_speed_t sbm_speed; /* current speed */ + sbmac_duplex_t sbm_duplex; /* current duplex */ + sbmac_fc_t sbm_fc; /* current flow control setting */ + + u_char sbm_hwaddr[ETHER_ADDR_LEN]; + + sbmacdma_t sbm_txdma; /* for now, only use channel 0 */ + sbmacdma_t sbm_rxdma; + +}; + + +/********************************************************************** + * Externs + ********************************************************************* */ + +/********************************************************************** + * Prototypes + ********************************************************************* */ + +static void sbdma_initctx(sbmacdma_t *d, + struct sbmac_softc *s, + int chan, + int txrx, + int maxdescr); +static void sbdma_channel_start(sbmacdma_t *d); +static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m); +static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m); +static void sbdma_emptyring(sbmacdma_t *d); +static void sbdma_fillring(sbmacdma_t *d); +static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d); +static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d); +static int sbmac_initctx(struct sbmac_softc *s); +static void sbmac_channel_start(struct sbmac_softc *s); +static void sbmac_channel_stop(struct sbmac_softc *s); +static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t); +static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff); +/*static void sbmac_init_and_start(struct sbmac_softc *sc);*/ +static uint64_t sbmac_addr2reg(unsigned char *ptr); +static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs); +static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev); +static void sbmac_setmulti(struct sbmac_softc *sc); +static int sbmac_init(struct net_device *dev); +static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed); +static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc); + +static int sbmac_open(struct net_device *dev); +static void sbmac_timer(unsigned long data); +static void sbmac_tx_timeout (struct net_device *dev); +static struct net_device_stats *sbmac_get_stats(struct net_device *dev); +static void sbmac_set_rx_mode(struct net_device *dev); +static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int sbmac_close(struct net_device *dev); +static int sbmac_mii_poll(struct sbmac_softc *s,int noisy); + +static void sbmac_mii_sync(struct sbmac_softc *s); +static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt); +static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx); +static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, + unsigned int regval); + + +/********************************************************************** + * Globals + ********************************************************************* */ + + +/********************************************************************** + * MDIO constants + ********************************************************************* */ + +#define MII_COMMAND_START 0x01 +#define MII_COMMAND_READ 0x02 +#define MII_COMMAND_WRITE 0x01 +#define MII_COMMAND_ACK 0x02 + +#define BMCR_RESET 0x8000 +#define BMCR_LOOPBACK 0x4000 +#define BMCR_SPEED0 0x2000 +#define BMCR_ANENABLE 0x1000 +#define BMCR_POWERDOWN 0x0800 +#define BMCR_ISOLATE 0x0400 +#define BMCR_RESTARTAN 0x0200 +#define BMCR_DUPLEX 0x0100 +#define BMCR_COLTEST 0x0080 +#define BMCR_SPEED1 0x0040 +#define BMCR_SPEED1000 (BMCR_SPEED1|BMCR_SPEED0) +#define BMCR_SPEED100 (BMCR_SPEED0) +#define BMCR_SPEED10 0 + +#define BMSR_100BT4 0x8000 +#define BMSR_100BT_FDX 0x4000 +#define BMSR_100BT_HDX 0x2000 +#define BMSR_10BT_FDX 0x1000 +#define BMSR_10BT_HDX 0x0800 +#define BMSR_100BT2_FDX 0x0400 +#define BMSR_100BT2_HDX 0x0200 +#define BMSR_1000BT_XSR 0x0100 +#define BMSR_PRESUP 0x0040 +#define BMSR_ANCOMPLT 0x0020 +#define BMSR_REMFAULT 0x0010 +#define BMSR_AUTONEG 0x0008 +#define BMSR_LINKSTAT 0x0004 +#define BMSR_JABDETECT 0x0002 +#define BMSR_EXTCAPAB 0x0001 + +#define PHYIDR1 0x2000 +#define PHYIDR2 0x5C60 + +#define ANAR_NP 0x8000 +#define ANAR_RF 0x2000 +#define ANAR_ASYPAUSE 0x0800 +#define ANAR_PAUSE 0x0400 +#define ANAR_T4 0x0200 +#define ANAR_TXFD 0x0100 +#define ANAR_TXHD 0x0080 +#define ANAR_10FD 0x0040 +#define ANAR_10HD 0x0020 +#define ANAR_PSB 0x0001 + +#define ANLPAR_NP 0x8000 +#define ANLPAR_ACK 0x4000 +#define ANLPAR_RF 0x2000 +#define ANLPAR_ASYPAUSE 0x0800 +#define ANLPAR_PAUSE 0x0400 +#define ANLPAR_T4 0x0200 +#define ANLPAR_TXFD 0x0100 +#define ANLPAR_TXHD 0x0080 +#define ANLPAR_10FD 0x0040 +#define ANLPAR_10HD 0x0020 +#define ANLPAR_PSB 0x0001 /* 802.3 */ + +#define ANER_PDF 0x0010 +#define ANER_LPNPABLE 0x0008 +#define ANER_NPABLE 0x0004 +#define ANER_PAGERX 0x0002 +#define ANER_LPANABLE 0x0001 + +#define ANNPTR_NP 0x8000 +#define ANNPTR_MP 0x2000 +#define ANNPTR_ACK2 0x1000 +#define ANNPTR_TOGTX 0x0800 +#define ANNPTR_CODE 0x0008 + +#define ANNPRR_NP 0x8000 +#define ANNPRR_MP 0x2000 +#define ANNPRR_ACK3 0x1000 +#define ANNPRR_TOGTX 0x0800 +#define ANNPRR_CODE 0x0008 + +#define K1TCR_TESTMODE 0x0000 +#define K1TCR_MSMCE 0x1000 +#define K1TCR_MSCV 0x0800 +#define K1TCR_RPTR 0x0400 +#define K1TCR_1000BT_FDX 0x200 +#define K1TCR_1000BT_HDX 0x100 + +#define K1STSR_MSMCFLT 0x8000 +#define K1STSR_MSCFGRES 0x4000 +#define K1STSR_LRSTAT 0x2000 +#define K1STSR_RRSTAT 0x1000 +#define K1STSR_LP1KFD 0x0800 +#define K1STSR_LP1KHD 0x0400 +#define K1STSR_LPASMDIR 0x0200 + +#define K1SCR_1KX_FDX 0x8000 +#define K1SCR_1KX_HDX 0x4000 +#define K1SCR_1KT_FDX 0x2000 +#define K1SCR_1KT_HDX 0x1000 + +#define STRAP_PHY1 0x0800 +#define STRAP_NCMODE 0x0400 +#define STRAP_MANMSCFG 0x0200 +#define STRAP_ANENABLE 0x0100 +#define STRAP_MSVAL 0x0080 +#define STRAP_1KHDXADV 0x0010 +#define STRAP_1KFDXADV 0x0008 +#define STRAP_100ADV 0x0004 +#define STRAP_SPEEDSEL 0x0000 +#define STRAP_SPEED100 0x0001 + +#define PHYSUP_SPEED1000 0x10 +#define PHYSUP_SPEED100 0x08 +#define PHYSUP_SPEED10 0x00 +#define PHYSUP_LINKUP 0x04 +#define PHYSUP_FDX 0x02 + +#define MII_BMCR 0x00 /* Basic mode control register (rw) */ +#define MII_BMSR 0x01 /* Basic mode status register (ro) */ +#define MII_K1STSR 0x0A /* 1K Status Register (ro) */ +#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */ + + +#define M_MAC_MDIO_DIR_OUTPUT 0 /* for clarity */ + + +/********************************************************************** + * SBMAC_MII_SYNC(s) + * + * Synchronize with the MII - send a pattern of bits to the MII + * that will guarantee that it is ready to accept a command. + * + * Input parameters: + * s - sbmac structure + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbmac_mii_sync(struct sbmac_softc *s) +{ + int cnt; + uint64_t bits; + + bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT; + + SBMAC_WRITECSR(s->sbm_mdio,bits); + + for (cnt = 0; cnt < 32; cnt++) { + SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC); + SBMAC_WRITECSR(s->sbm_mdio,bits); + } +} + +/********************************************************************** + * SBMAC_MII_SENDDATA(s,data,bitcnt) + * + * Send some bits to the MII. The bits to be sent are right- + * justified in the 'data' parameter. + * + * Input parameters: + * s - sbmac structure + * data - data to send + * bitcnt - number of bits to send + ********************************************************************* */ + +static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt) +{ + int i; + uint64_t bits; + unsigned int curmask; + + bits = M_MAC_MDIO_DIR_OUTPUT; + SBMAC_WRITECSR(s->sbm_mdio,bits); + + curmask = 1 << (bitcnt - 1); + + for (i = 0; i < bitcnt; i++) { + if (data & curmask) bits |= M_MAC_MDIO_OUT; + else bits &= ~M_MAC_MDIO_OUT; + SBMAC_WRITECSR(s->sbm_mdio,bits); + SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC); + SBMAC_WRITECSR(s->sbm_mdio,bits); + curmask >>= 1; + } +} + + + +/********************************************************************** + * SBMAC_MII_READ(s,phyaddr,regidx) + * + * Read a PHY register. + * + * Input parameters: + * s - sbmac structure + * phyaddr - PHY's address + * regidx = index of register to read + * + * Return value: + * value read, or 0 if an error occured. + ********************************************************************* */ + +static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx) +{ + int idx; + int error; + int regval; + + /* + * Synchronize ourselves so that the PHY knows the next + * thing coming down is a command + */ + + sbmac_mii_sync(s); + + /* + * Send the data to the PHY. The sequence is + * a "start" command (2 bits) + * a "read" command (2 bits) + * the PHY addr (5 bits) + * the register index (5 bits) + */ + + sbmac_mii_senddata(s,MII_COMMAND_START, 2); + sbmac_mii_senddata(s,MII_COMMAND_READ, 2); + sbmac_mii_senddata(s,phyaddr, 5); + sbmac_mii_senddata(s,regidx, 5); + + /* + * Switch the port around without a clock transition. + */ + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT); + + /* + * Send out a clock pulse to signal we want the status + */ + + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC); + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT); + + /* + * If an error occured, the PHY will signal '1' back + */ + error = SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN; + + /* + * Issue an 'idle' clock pulse, but keep the direction + * the same. + */ + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC); + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT); + + regval = 0; + + for (idx = 0; idx < 16; idx++) { + regval <<= 1; + + if (error == 0) { + if (SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN) regval |= 1; + } + + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC); + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT); + } + + /* Switch back to output */ + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT); + + if (error == 0) return regval; + return 0; +} + + +/********************************************************************** + * SBMAC_MII_WRITE(s,phyaddr,regidx,regval) + * + * Write a value to a PHY register. + * + * Input parameters: + * s - sbmac structure + * phyaddr - PHY to use + * regidx - register within the PHY + * regval - data to write to register + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx, + unsigned int regval) +{ + + sbmac_mii_sync(s); + + sbmac_mii_senddata(s,MII_COMMAND_START,2); + sbmac_mii_senddata(s,MII_COMMAND_WRITE,2); + sbmac_mii_senddata(s,phyaddr, 5); + sbmac_mii_senddata(s,regidx, 5); + sbmac_mii_senddata(s,MII_COMMAND_ACK,2); + sbmac_mii_senddata(s,regval,16); + + SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT); +} + + + +/********************************************************************** + * SBDMA_INITCTX(d,s,chan,txrx,maxdescr) + * + * Initialize a DMA channel context. Since there are potentially + * eight DMA channels per MAC, it's nice to do this in a standard + * way. + * + * Input parameters: + * d - sbmacdma_t structure (DMA channel context) + * s - sbmac_softc structure (pointer to a MAC) + * chan - channel number (0..1 right now) + * txrx - Identifies DMA_TX or DMA_RX for channel direction + * maxdescr - number of descriptors + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbdma_initctx(sbmacdma_t *d, + struct sbmac_softc *s, + int chan, + int txrx, + int maxdescr) +{ + /* + * Save away interesting stuff in the structure + */ + + d->sbdma_eth = s; + d->sbdma_channel = chan; + d->sbdma_txdir = txrx; + + /* + * initialize register pointers + */ + + d->sbdma_config0 = + PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0)); + d->sbdma_config1 = + PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0)); + d->sbdma_dscrbase = + PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE)); + d->sbdma_dscrcnt = + PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT)); + d->sbdma_curdscr = + PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR)); + + /* + * Allocate memory for the ring + */ + + d->sbdma_maxdescr = maxdescr; + + d->sbdma_dscrtable = (sbdmadscr_t *) + KMALLOC(d->sbdma_maxdescr*sizeof(sbdmadscr_t)); + + memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t)); + + d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr; + + d->sbdma_dscrtable_phys = KVTOPHYS(d->sbdma_dscrtable); + + /* + * And context table + */ + + d->sbdma_ctxtable = (struct sk_buff **) + KMALLOC(d->sbdma_maxdescr*sizeof(struct sk_buff *)); + + memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *)); + +} + +/********************************************************************** + * SBDMA_CHANNEL_START(d) + * + * Initialize the hardware registers for a DMA channel. + * + * Input parameters: + * d - DMA channel to init (context must be previously init'd + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbdma_channel_start(sbmacdma_t *d) +{ + /* + * Turn on the DMA channel + */ + + SBMAC_WRITECSR(d->sbdma_config1,0); + + SBMAC_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys); + + SBMAC_WRITECSR(d->sbdma_config0, + V_DMA_RINGSZ(d->sbdma_maxdescr) | + 0); + + /* + * Initialize ring pointers + */ + + d->sbdma_addptr = d->sbdma_dscrtable; + d->sbdma_remptr = d->sbdma_dscrtable; +} + + +static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset) +{ + unsigned long addr; + unsigned long newaddr; + + addr = (unsigned long) skb->data; + + newaddr = (addr + power2 - 1) & ~(power2 - 1); + + skb_reserve(skb,newaddr-addr+offset); +} + + +/********************************************************************** + * SBDMA_ADD_RCVBUFFER(d,sb) + * + * Add a buffer to the specified DMA channel. For receive channels, + * this queues a buffer for inbound packets. + * + * Input parameters: + * d - DMA channel descriptor + * sb - sk_buff to add, or NULL if we should allocate one + * + * Return value: + * 0 if buffer could not be added (ring is full) + * 1 if buffer added successfully + ********************************************************************* */ + + +static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) +{ + sbdmadscr_t *dsc; + sbdmadscr_t *nextdsc; + struct sk_buff *sb_new = NULL; + int pktsize = ENET_PACKET_SIZE; + + /* get pointer to our current place in the ring */ + + dsc = d->sbdma_addptr; + nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr); + + /* + * figure out if the ring is full - if the next descriptor + * is the same as the one that we're going to remove from + * the ring, the ring is full + */ + + if (nextdsc == d->sbdma_remptr) { + return -ENOSPC; + } + + /* + * Allocate a sk_buff if we don't already have one. + * If we do have an sk_buff, reset it so that it's empty. + * + * Note: sk_buffs don't seem to be guaranteed to have any sort + * of alignment when they are allocated. Therefore, allocate enough + * extra space to make sure that: + * + * 1. the data does not start in the middle of a cache line. + * 2. The data does not end in the middle of a cache line + * 3. The buffer can be aligned such that the IP addresses are + * naturally aligned. + * + * Remember, the SB1250's MAC writes whole cache lines at a time, + * without reading the old contents first. So, if the sk_buff's + * data portion starts in the middle of a cache line, the SB1250 + * DMA will trash the beginning (and ending) portions. + */ + + if (sb == NULL) { + sb_new = dev_alloc_skb(ENET_PACKET_SIZE + CACHELINESIZE*2 + ETHER_ALIGN); + if (sb_new == NULL) { + printk(KERN_INFO "%s: sk_buff allocation failed\n", + d->sbdma_eth->sbm_dev->name); + return -ENOBUFS; + } + + sbdma_align_skb(sb_new,CACHELINESIZE,ETHER_ALIGN); + + /* mark skbuff owned by our device */ + sb_new->dev = d->sbdma_eth->sbm_dev; + } + else { + sb_new = sb; + /* + * nothing special to reinit buffer, it's already aligned + * and sb->tail already points to a good place. + */ + } + + /* + * fill in the descriptor + */ + + dsc->dscr_a = KVTOPHYS(sb_new->tail) | + V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | + M_DMA_DSCRA_INTERRUPT; + + /* receiving: no options */ + dsc->dscr_b = 0; + + /* + * fill in the context + */ + + d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb_new; + + /* + * point at next packet + */ + + d->sbdma_addptr = nextdsc; + + /* + * Give the buffer to the DMA engine. + */ + + SBMAC_WRITECSR(d->sbdma_dscrcnt,1); + + return 0; /* we did it */ +} + +/********************************************************************** + * SBDMA_ADD_TXBUFFER(d,sb) + * + * Add a transmit buffer to the specified DMA channel, causing a + * transmit to start. + * + * Input parameters: + * d - DMA channel descriptor + * sb - sk_buff to add + * + * Return value: + * 0 transmit queued successfully + * otherwise error code + ********************************************************************* */ + + +static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb) +{ + sbdmadscr_t *dsc; + sbdmadscr_t *nextdsc; + uint64_t phys; + uint64_t ncb; + int length; + + /* get pointer to our current place in the ring */ + + dsc = d->sbdma_addptr; + nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr); + + /* + * figure out if the ring is full - if the next descriptor + * is the same as the one that we're going to remove from + * the ring, the ring is full + */ + + if (nextdsc == d->sbdma_remptr) { + return -ENOSPC; + } + + /* + * Under Linux, it's not necessary to copy/coalesce buffers + * like it is on NetBSD. We think they're all contiguous, + * but that may not be true for GBE. + */ + + length = sb->len; + + /* + * fill in the descriptor. Note that the number of cache + * blocks in the descriptor is the number of blocks + * *spanned*, so we need to add in the offset (if any) + * while doing the calculation. + */ + + phys = KVTOPHYS(sb->data); + ncb = NUMCACHEBLKS(length+(phys & (CACHELINESIZE-1))); + + dsc->dscr_a = phys | + V_DMA_DSCRA_A_SIZE(ncb) | + M_DMA_DSCRA_INTERRUPT | + M_DMA_ETHTX_SOP; + + /* transmitting: set outbound options and length */ + + dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_APPENDCRC_APPENDPAD) | + V_DMA_DSCRB_PKT_SIZE(length); + + /* + * fill in the context + */ + + d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb; + + /* + * point at next packet + */ + + d->sbdma_addptr = nextdsc; + + /* + * Give the buffer to the DMA engine. + */ + + SBMAC_WRITECSR(d->sbdma_dscrcnt,1); + + return 0; /* we did it */ +} + + + + +/********************************************************************** + * SBDMA_EMPTYRING(d) + * + * Free all allocated sk_buffs on the specified DMA channel; + * + * Input parameters: + * d - DMA channel + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbdma_emptyring(sbmacdma_t *d) +{ + int idx; + struct sk_buff *sb; + + for (idx = 0; idx < d->sbdma_maxdescr; idx++) { + sb = d->sbdma_ctxtable[idx]; + if (sb) { + dev_kfree_skb(sb); + d->sbdma_ctxtable[idx] = NULL; + } + } +} + + +/********************************************************************** + * SBDMA_FILLRING(d) + * + * Fill the specified DMA channel (must be receive channel) + * with sk_buffs + * + * Input parameters: + * d - DMA channel + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbdma_fillring(sbmacdma_t *d) +{ + int idx; + + for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) { + if (sbdma_add_rcvbuffer(d,NULL) != 0) break; + } +} + + +/********************************************************************** + * SBDMA_RX_PROCESS(sc,d) + * + * Process "completed" receive buffers on the specified DMA channel. + * Note that this isn't really ideal for priority channels, since + * it processes all of the packets on a given channel before + * returning. + * + * Input parameters: + * sc - softc structure + * d - DMA channel context + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) +{ + int curidx; + int hwidx; + sbdmadscr_t *dsc; + struct sk_buff *sb; + int len; + + for (;;) { + /* + * figure out where we are (as an index) and where + * the hardware is (also as an index) + * + * This could be done faster if (for example) the + * descriptor table was page-aligned and contiguous in + * both virtual and physical memory -- you could then + * just compare the low-order bits of the virtual address + * (sbdma_remptr) and the physical address (sbdma_curdscr CSR) + */ + + curidx = d->sbdma_remptr - d->sbdma_dscrtable; + hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - + d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); + + /* + * If they're the same, that means we've processed all + * of the descriptors up to (but not including) the one that + * the hardware is working on right now. + */ + + if (curidx == hwidx) break; + + /* + * Otherwise, get the packet's sk_buff ptr back + */ + + dsc = &(d->sbdma_dscrtable[curidx]); + sb = d->sbdma_ctxtable[curidx]; + d->sbdma_ctxtable[curidx] = NULL; + + len = (int)G_DMA_DSCRB_PKT_SIZE(dsc->dscr_b) - 4; + + /* + * Check packet status. If good, process it. + * If not, silently drop it and put it back on the + * receive ring. + */ + + if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) { + + /* + * Set length into the packet + */ + skb_put(sb,len); + + /* + * Add a new buffer to replace the old one. If we fail + * to allocate a buffer, we're going to drop this + * packet and put it right back on the receive ring. + */ + + if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) { + sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */ + } + else { + /* + * Buffer has been replaced on the receive ring. + * Pass the buffer to the kernel + */ + sc->sbm_stats.rx_bytes += len; + sc->sbm_stats.rx_packets++; + sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev); + netif_rx(sb); + } + } + else { + /* + * Packet was mangled somehow. Just drop it and + * put it back on the receive ring. + */ + sbdma_add_rcvbuffer(d,sb); + } + + + /* + * .. and advance to the next buffer. + */ + + d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); + + } +} + + + +/********************************************************************** + * SBDMA_TX_PROCESS(sc,d) + * + * Process "completed" transmit buffers on the specified DMA channel. + * This is normally called within the interrupt service routine. + * Note that this isn't really ideal for priority channels, since + * it processes all of the packets on a given channel before + * returning. + * + * Input parameters: + * sc - softc structure + * d - DMA channel context + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) +{ + int curidx; + int hwidx; + sbdmadscr_t *dsc; + struct sk_buff *sb; + unsigned long flags; + + spin_lock_irqsave(&(sc->sbm_lock), flags); + + for (;;) { + /* + * figure out where we are (as an index) and where + * the hardware is (also as an index) + * + * This could be done faster if (for example) the + * descriptor table was page-aligned and contiguous in + * both virtual and physical memory -- you could then + * just compare the low-order bits of the virtual address + * (sbdma_remptr) and the physical address (sbdma_curdscr CSR) + */ + + curidx = d->sbdma_remptr - d->sbdma_dscrtable; + { + /* XXX This is gross, ugly, and only here because justin hacked it + in to fix a problem without really understanding it. + + It seems that, for whatever reason, this routine is invoked immediately upon the enabling of interrupts. + So then the Read below returns zero, making hwidx a negative number, and anti-hilarity + ensues. + + I'm guessing there's a proper fix involving clearing out interrupt state from old packets + before enabling interrupts, but I'm not sure. + + Anyways, this hack seems to work, and is Good Enough for 11 PM. :) + + -Justin + */ + + uint64_t tmp = SBMAC_READCSR(d->sbdma_curdscr); + if (!tmp) { + break; + } + hwidx = (int) (((tmp & M_DMA_CURDSCR_ADDR) - + d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); + } + /* + * If they're the same, that means we've processed all + * of the descriptors up to (but not including) the one that + * the hardware is working on right now. + */ + + if (curidx == hwidx) break; + + /* + * Otherwise, get the packet's sk_buff ptr back + */ + + dsc = &(d->sbdma_dscrtable[curidx]); + sb = d->sbdma_ctxtable[curidx]; + d->sbdma_ctxtable[curidx] = NULL; + + /* + * Stats + */ + + sc->sbm_stats.tx_bytes += sb->len; + sc->sbm_stats.tx_packets++; + + /* + * for transmits, we just free buffers. + */ + + dev_kfree_skb_irq(sb); + + /* + * .. and advance to the next buffer. + */ + + d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); + + } + + /* + * Decide if we should wake up the protocol or not. + * Other drivers seem to do this when we reach a low + * watermark on the transmit queue. + */ + + netif_wake_queue(d->sbdma_eth->sbm_dev); + + spin_unlock_irqrestore(&(sc->sbm_lock), flags); + +} + + + +/********************************************************************** + * SBMAC_INITCTX(s) + * + * Initialize an Ethernet context structure - this is called + * once per MAC on the 1250. Memory is allocated here, so don't + * call it again from inside the ioctl routines that bring the + * interface up/down + * + * Input parameters: + * s - sbmac context structure + * + * Return value: + * 0 + ********************************************************************* */ + +static int sbmac_initctx(struct sbmac_softc *s) +{ + + /* + * figure out the addresses of some ports + */ + + s->sbm_macenable = PKSEG1(s->sbm_base + R_MAC_ENABLE); + s->sbm_maccfg = PKSEG1(s->sbm_base + R_MAC_CFG); + s->sbm_fifocfg = PKSEG1(s->sbm_base + R_MAC_THRSH_CFG); + s->sbm_framecfg = PKSEG1(s->sbm_base + R_MAC_FRAMECFG); + s->sbm_rxfilter = PKSEG1(s->sbm_base + R_MAC_ADFILTER_CFG); + s->sbm_isr = PKSEG1(s->sbm_base + R_MAC_STATUS); + s->sbm_imr = PKSEG1(s->sbm_base + R_MAC_INT_MASK); + s->sbm_mdio = PKSEG1(s->sbm_base + R_MAC_MDIO); + + s->sbm_phys[0] = 1; + s->sbm_phys[1] = 0; + + s->sbm_phy_oldbmsr = 0; + s->sbm_phy_oldanlpar = 0; + s->sbm_phy_oldk1stsr = 0; + s->sbm_phy_oldlinkstat = 0; + + /* + * Initialize the DMA channels. Right now, only one per MAC is used + * Note: Only do this _once_, as it allocates memory from the kernel! + */ + + sbdma_initctx(&(s->sbm_txdma),s,0,DMA_TX,SBMAC_MAX_TXDESCR); + sbdma_initctx(&(s->sbm_rxdma),s,0,DMA_RX,SBMAC_MAX_RXDESCR); + + /* + * initial state is OFF + */ + + s->sbm_state = sbmac_state_off; + + /* + * Initial speed is (XXX TEMP) 10MBit/s HDX no FC + */ + + s->sbm_speed = sbmac_speed_10; + s->sbm_duplex = sbmac_duplex_half; + s->sbm_fc = sbmac_fc_disabled; + + return 0; +} + + +static void sbdma_uninitctx(struct sbmacdma_s *d) +{ + if (d->sbdma_dscrtable) { + KFREE(d->sbdma_dscrtable); + d->sbdma_dscrtable = NULL; + } + + if (d->sbdma_ctxtable) { + KFREE(d->sbdma_ctxtable); + d->sbdma_ctxtable = NULL; + } +} + + +static void sbmac_uninitctx(struct sbmac_softc *sc) +{ + sbdma_uninitctx(&(sc->sbm_txdma)); + sbdma_uninitctx(&(sc->sbm_rxdma)); +} + + +/********************************************************************** + * SBMAC_CHANNEL_START(s) + * + * Start packet processing on this MAC. + * + * Input parameters: + * s - sbmac structure + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbmac_channel_start(struct sbmac_softc *s) +{ + uint64_t reg; + sbmac_port_t port; + uint64_t cfg,fifo,framecfg; + int idx; + + /* + * Don't do this if running + */ + + if (s->sbm_state == sbmac_state_on) return; + + /* + * Bring the controller out of reset, but leave it off. + */ + + SBMAC_WRITECSR(s->sbm_macenable,0); + + /* + * Ignore all received packets + */ + + SBMAC_WRITECSR(s->sbm_rxfilter,0); + + /* + * Calculate values for various control registers. + */ + + cfg = M_MAC_RETRY_EN | + M_MAC_TX_HOLD_SOP_EN | + V_MAC_TX_PAUSE_CNT_16K | + M_MAC_AP_STAT_EN | + M_MAC_FAST_SYNC | + M_MAC_SS_EN | + 0; + + fifo = V_MAC_TX_WR_THRSH(4) | /* Must be '4' or '8' */ + V_MAC_TX_RD_THRSH(4) | + V_MAC_TX_RL_THRSH(4) | + V_MAC_RX_PL_THRSH(4) | + V_MAC_RX_RD_THRSH(4) | /* Must be '4' */ + V_MAC_RX_PL_THRSH(4) | + V_MAC_RX_RL_THRSH(8) | + 0; + + framecfg = V_MAC_MIN_FRAMESZ_DEFAULT | + V_MAC_MAX_FRAMESZ_DEFAULT | + V_MAC_BACKOFF_SEL(1); + + + /* + * Clear out the hash address map + */ + + port = PKSEG1(s->sbm_base + R_MAC_HASH_BASE); + for (idx = 0; idx < MAC_HASH_COUNT; idx++) { + SBMAC_WRITECSR(port,0); + port += sizeof(uint64_t); + } + + /* + * Clear out the exact-match table + */ + + port = PKSEG1(s->sbm_base + R_MAC_ADDR_BASE); + for (idx = 0; idx < MAC_ADDR_COUNT; idx++) { + SBMAC_WRITECSR(port,0); + port += sizeof(uint64_t); + } + + /* + * Clear out the DMA Channel mapping table registers + */ + + port = PKSEG1(s->sbm_base + R_MAC_CHUP0_BASE); + for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) { + SBMAC_WRITECSR(port,0); + port += sizeof(uint64_t); + } + + + port = PKSEG1(s->sbm_base + R_MAC_CHLO0_BASE); + for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) { + SBMAC_WRITECSR(port,0); + port += sizeof(uint64_t); + } + + /* + * Program the hardware address. It goes into the hardware-address + * register as well as the first filter register. + */ + + reg = sbmac_addr2reg(s->sbm_hwaddr); + + port = PKSEG1(s->sbm_base + R_MAC_ADDR_BASE); + SBMAC_WRITECSR(port,reg); + port = PKSEG1(s->sbm_base + R_MAC_ETHERNET_ADDR); + +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS + /* + * Pass1 SB1250s do not receive packets addressed to the + * destination address in the R_MAC_ETHERNET_ADDR register. + * Set the value to zero. + */ + SBMAC_WRITECSR(port,0); +#else + SBMAC_WRITECSR(port,reg); +#endif + + /* + * Set the receive filter for no packets, and write values + * to the various config registers + */ + + SBMAC_WRITECSR(s->sbm_rxfilter,0); + SBMAC_WRITECSR(s->sbm_imr,0); + SBMAC_WRITECSR(s->sbm_framecfg,framecfg); + SBMAC_WRITECSR(s->sbm_fifocfg,fifo); + SBMAC_WRITECSR(s->sbm_maccfg,cfg); + + /* + * Initialize DMA channels (rings should be ok now) + */ + + sbdma_channel_start(&(s->sbm_rxdma)); + sbdma_channel_start(&(s->sbm_txdma)); + + /* + * Configure the speed, duplex, and flow control + */ + + sbmac_set_speed(s,s->sbm_speed); + sbmac_set_duplex(s,s->sbm_duplex,s->sbm_fc); + + /* + * Fill the receive ring + */ + + sbdma_fillring(&(s->sbm_rxdma)); + + /* + * Turn on the rest of the bits in the enable register + */ + + SBMAC_WRITECSR(s->sbm_macenable, + M_MAC_RXDMA_EN0 | + M_MAC_TXDMA_EN0 | + M_MAC_RX_ENABLE | + M_MAC_TX_ENABLE); + + + + /* + * Accept any kind of interrupt on TX and RX DMA channel 0 + */ + SBMAC_WRITECSR(s->sbm_imr, + (M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | + (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)); + + /* + * Enable receiving unicasts and broadcasts + */ + + SBMAC_WRITECSR(s->sbm_rxfilter,M_MAC_UCAST_EN | M_MAC_BCAST_EN); + + /* + * we're running now. + */ + + s->sbm_state = sbmac_state_on; + + /* + * Program multicast addresses + */ + + sbmac_setmulti(s); + + /* + * If channel was in promiscuous mode before, turn that on + */ + + if (s->sbm_devflags & IFF_PROMISC) { + sbmac_promiscuous_mode(s,1); + } + +} + + +/********************************************************************** + * SBMAC_CHANNEL_STOP(s) + * + * Stop packet processing on this MAC. + * + * Input parameters: + * s - sbmac structure + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbmac_channel_stop(struct sbmac_softc *s) +{ + uint64_t ctl; + + /* don't do this if already stopped */ + + if (s->sbm_state == sbmac_state_off) return; + + /* don't accept any packets, disable all interrupts */ + + SBMAC_WRITECSR(s->sbm_rxfilter,0); + SBMAC_WRITECSR(s->sbm_imr,0); + + /* Turn off ticker */ + + /* XXX */ + + /* turn off receiver and transmitter */ + + ctl = SBMAC_READCSR(s->sbm_macenable); + ctl &= ~(M_MAC_RXDMA_EN0 | M_MAC_TXDMA_EN0); + SBMAC_WRITECSR(s->sbm_macenable,ctl); + + /* We're stopped now. */ + + s->sbm_state = sbmac_state_off; + + + /* Empty the receive and transmit rings */ + + sbdma_emptyring(&(s->sbm_rxdma)); + sbdma_emptyring(&(s->sbm_txdma)); + +} + +/********************************************************************** + * SBMAC_SET_CHANNEL_STATE(state) + * + * Set the channel's state ON or OFF + * + * Input parameters: + * state - new state + * + * Return value: + * old state + ********************************************************************* */ +static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc, + sbmac_state_t state) +{ + sbmac_state_t oldstate = sc->sbm_state; + + /* + * If same as previous state, return + */ + + if (state == oldstate) { + return oldstate; + } + + /* + * If new state is ON, turn channel on + */ + + if (state == sbmac_state_on) { + sbmac_channel_start(sc); + } + else { + sbmac_channel_stop(sc); + } + + /* + * Return previous state + */ + + return oldstate; +} + + +/********************************************************************** + * SBMAC_PROMISCUOUS_MODE(sc,onoff) + * + * Turn on or off promiscuous mode + * + * Input parameters: + * sc - softc + * onoff - 1 to turn on, 0 to turn off + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff) +{ + uint64_t reg; + + if (sc->sbm_state != sbmac_state_on) return; + + if (onoff) { + reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg |= M_MAC_ALLPKT_EN; + SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + } + else { + reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg &= ~M_MAC_ALLPKT_EN; + SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + } +} + + + +#if 0 +/********************************************************************** + * SBMAC_INIT_AND_START(sc) + * + * Stop the channel and restart it. This is generally used + * when we have to do something to the channel that requires + * a swift kick. + * + * Input parameters: + * sc - softc + ********************************************************************* */ + +static void sbmac_init_and_start(struct sbmac_softc *sc) +{ + unsigned long flags; + + spin_lock_irqsave(&(sc->sbm_lock),flags); + + sbmac_set_channel_state(sc,sbmac_state_on); + + spin_unlock_irqrestore(&(sc->sbm_lock),flags); +} +#endif + + +/********************************************************************** + * SBMAC_ADDR2REG(ptr) + * + * Convert six bytes into the 64-bit register value that + * we typically write into the SBMAC's address/mcast registers + * + * Input parameters: + * ptr - pointer to 6 bytes + * + * Return value: + * register value + ********************************************************************* */ + +static uint64_t sbmac_addr2reg(unsigned char *ptr) +{ + uint64_t reg = 0; + + ptr += 6; + + reg |= (uint64_t) *(--ptr); + reg <<= 8; + reg |= (uint64_t) *(--ptr); + reg <<= 8; + reg |= (uint64_t) *(--ptr); + reg <<= 8; + reg |= (uint64_t) *(--ptr); + reg <<= 8; + reg |= (uint64_t) *(--ptr); + reg <<= 8; + reg |= (uint64_t) *(--ptr); + + return reg; +} + + +/********************************************************************** + * SBMAC_SET_SPEED(s,speed) + * + * Configure LAN speed for the specified MAC. + * Warning: must be called when MAC is off! + * + * Input parameters: + * s - sbmac structure + * speed - speed to set MAC to (see sbmac_speed_t enum) + * + * Return value: + * 1 if successful + * 0 indicates invalid parameters + ********************************************************************* */ + +static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed) +{ + uint64_t cfg; + uint64_t framecfg; + + /* + * Save new current values + */ + + s->sbm_speed = speed; + + if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */ + + /* + * Read current register values + */ + + cfg = SBMAC_READCSR(s->sbm_maccfg); + framecfg = SBMAC_READCSR(s->sbm_framecfg); + + /* + * Mask out the stuff we want to change + */ + + cfg &= ~(M_MAC_BURST_EN | M_MAC_SPEED_SEL); + framecfg &= ~(M_MAC_IFG_RX | M_MAC_IFG_TX | M_MAC_IFG_THRSH | + M_MAC_SLOT_SIZE); + + /* + * Now add in the new bits + */ + + switch (speed) { + case sbmac_speed_10: + framecfg |= V_MAC_IFG_RX_10 | + V_MAC_IFG_TX_10 | + K_MAC_IFG_THRSH_10 | + V_MAC_SLOT_SIZE_10; + cfg |= V_MAC_SPEED_SEL_10MBPS; + break; + + case sbmac_speed_100: + framecfg |= V_MAC_IFG_RX_100 | + V_MAC_IFG_TX_100 | + V_MAC_IFG_THRSH_100 | + V_MAC_SLOT_SIZE_100; + cfg |= V_MAC_SPEED_SEL_100MBPS ; + break; + + case sbmac_speed_1000: + framecfg |= V_MAC_IFG_RX_1000 | + V_MAC_IFG_TX_1000 | + V_MAC_IFG_THRSH_1000 | + V_MAC_SLOT_SIZE_1000; + cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN; + break; + + case sbmac_speed_auto: /* XXX not implemented */ + /* fall through */ + default: + return 0; + } + + /* + * Send the bits back to the hardware + */ + + SBMAC_WRITECSR(s->sbm_framecfg,framecfg); + SBMAC_WRITECSR(s->sbm_maccfg,cfg); + + return 1; + +} + +/********************************************************************** + * SBMAC_SET_DUPLEX(s,duplex,fc) + * + * Set Ethernet duplex and flow control options for this MAC + * Warning: must be called when MAC is off! + * + * Input parameters: + * s - sbmac structure + * duplex - duplex setting (see sbmac_duplex_t) + * fc - flow control setting (see sbmac_fc_t) + * + * Return value: + * 1 if ok + * 0 if an invalid parameter combination was specified + ********************************************************************* */ + +static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc) +{ + uint64_t cfg; + + /* + * Save new current values + */ + + s->sbm_duplex = duplex; + s->sbm_fc = fc; + + if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */ + + /* + * Read current register values + */ + + cfg = SBMAC_READCSR(s->sbm_maccfg); + + /* + * Mask off the stuff we're about to change + */ + + cfg &= ~(M_MAC_FC_SEL | M_MAC_FC_CMD | M_MAC_HDX_EN); + + + switch (duplex) { + case sbmac_duplex_half: + switch (fc) { + case sbmac_fc_disabled: + cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_DISABLED; + break; + + case sbmac_fc_collision: + cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENABLED; + break; + + case sbmac_fc_carrier: + cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR; + break; + + case sbmac_fc_auto: /* XXX not implemented */ + /* fall through */ + case sbmac_fc_frame: /* not valid in half duplex */ + default: /* invalid selection */ + return 0; + } + break; + + case sbmac_duplex_full: + switch (fc) { + case sbmac_fc_disabled: + cfg |= V_MAC_FC_CMD_DISABLED; + break; + + case sbmac_fc_frame: + cfg |= V_MAC_FC_CMD_ENABLED; + break; + + case sbmac_fc_collision: /* not valid in full duplex */ + case sbmac_fc_carrier: /* not valid in full duplex */ + case sbmac_fc_auto: /* XXX not implemented */ + /* fall through */ + default: + return 0; + } + break; + case sbmac_duplex_auto: + /* XXX not implemented */ + break; + } + + /* + * Send the bits back to the hardware + */ + + SBMAC_WRITECSR(s->sbm_maccfg,cfg); + + return 1; +} + + + + +/********************************************************************** + * SBMAC_INTR() + * + * Interrupt handler for MAC interrupts + * + * Input parameters: + * MAC structure + * + * Return value: + * nothing + ********************************************************************* */ +static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) +{ + struct net_device *dev = (struct net_device *) dev_instance; + struct sbmac_softc *sc = (struct sbmac_softc *) (dev->priv); + uint64_t isr; + + for (;;) { + + /* + * Read the ISR (this clears the bits in the real register) + */ + + isr = SBMAC_READCSR(sc->sbm_isr); + + if (isr == 0) break; + + /* + * Transmits on channel 0 + */ + + if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) { + sbdma_tx_process(sc,&(sc->sbm_txdma)); + } + + /* + * Receives on channel 0 + */ + + if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) { + sbdma_rx_process(sc,&(sc->sbm_rxdma)); + } + } + +} + + +/********************************************************************** + * SBMAC_START_TX(skb,dev) + * + * Start output on the specified interface. Basically, we + * queue as many buffers as we can until the ring fills up, or + * we run off the end of the queue, whichever comes first. + * + * Input parameters: + * + * + * Return value: + * nothing + ********************************************************************* */ +static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + + /* lock eth irq */ + spin_lock_irq (&sc->sbm_lock); + + /* + * Put the buffer on the transmit ring. If we + * don't have room, stop the queue. + */ + + if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) { + /* XXX save skb that we could not send */ + netif_stop_queue(dev); + } + + dev->trans_start = jiffies; + + spin_unlock_irq (&sc->sbm_lock); + + return 0; +} + +/********************************************************************** + * SBMAC_SETMULTI(sc) + * + * Reprogram the multicast table into the hardware, given + * the list of multicasts associated with the interface + * structure. + * + * Input parameters: + * sc - softc + * + * Return value: + * nothing + ********************************************************************* */ + +static void sbmac_setmulti(struct sbmac_softc *sc) +{ + uint64_t reg; + sbmac_port_t port; + int idx; + struct dev_mc_list *mclist; + struct net_device *dev = sc->sbm_dev; + + /* + * Clear out entire multicast table. We do this by nuking + * the entire hash table and all the direct matches except + * the first one, which is used for our station address + */ + + for (idx = 1; idx < MAC_ADDR_COUNT; idx++) { + port = PKSEG1(sc->sbm_base + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t))); + SBMAC_WRITECSR(port,0); + } + + for (idx = 0; idx < MAC_HASH_COUNT; idx++) { + port = PKSEG1(sc->sbm_base + R_MAC_HASH_BASE+(idx*sizeof(uint64_t))); + SBMAC_WRITECSR(port,0); + } + + /* + * Clear the filter to say we don't want any multicasts. + */ + + reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg &= ~(M_MAC_MCAST_INV | M_MAC_MCAST_EN); + SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + + if (dev->flags & IFF_ALLMULTI) { + /* + * Enable ALL multicasts. Do this by inverting the + * multicast enable bit. + */ + reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg |= (M_MAC_MCAST_INV | M_MAC_MCAST_EN); + SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + return; + } + + + /* + * Progam new multicast entries. For now, only use the + * perfect filter. In the future we'll need to use the + * hash filter if the perfect filter overflows + */ + + /* XXX only using perfect filter for now, need to use hash + * XXX if the table overflows */ + + idx = 1; /* skip station address */ + mclist = dev->mc_list; + while (mclist && (idx < MAC_ADDR_COUNT)) { + reg = sbmac_addr2reg(mclist->dmi_addr); + port = PKSEG1(sc->sbm_base + + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t))); + SBMAC_WRITECSR(port,reg); + idx++; + mclist = mclist->next; + } + + /* + * Enable the "accept multicast bits" if we programmed at least one + * multicast. + */ + + if (idx > 1) { + reg = SBMAC_READCSR(sc->sbm_rxfilter); + reg |= M_MAC_MCAST_EN; + SBMAC_WRITECSR(sc->sbm_rxfilter,reg); + } +} + + + +#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) +/********************************************************************** + * SBMAC_PARSE_XDIGIT(str) + * + * Parse a hex digit, returning its value + * + * Input parameters: + * str - character + * + * Return value: + * hex value, or -1 if invalid + ********************************************************************* */ + +static int sbmac_parse_xdigit(char str) +{ + int digit; + + if ((str >= '0') && (str <= '9')) digit = str - '0'; + else if ((str >= 'a') && (str <= 'f')) digit = str - 'a' + 10; + else if ((str >= 'A') && (str <= 'F')) digit = str - 'A' + 10; + else return -1; + + return digit; +} + +/********************************************************************** + * SBMAC_PARSE_HWADDR(str,hwaddr) + * + * Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte + * Ethernet address. + * + * Input parameters: + * str - string + * hwaddr - pointer to hardware address + * + * Return value: + * 0 if ok, else -1 + ********************************************************************* */ + +static int sbmac_parse_hwaddr(char *str,u_char *hwaddr) +{ + int digit1,digit2; + int idx = 6; + + while (*str && (idx > 0)) { + digit1 = sbmac_parse_xdigit(*str); + if (digit1 < 0) return -1; + str++; + if (!*str) return -1; + + if ((*str == ':') || (*str == '-')) { + digit2 = digit1; + digit1 = 0; + } + else { + digit2 = sbmac_parse_xdigit(*str); + if (digit2 < 0) return -1; + str++; + } + + *hwaddr++ = (digit1 << 4) | digit2; + idx--; + + if (*str == '-') str++; + if (*str == ':') str++; + } + return 0; +} +#endif + +/********************************************************************** + * SBMAC_INIT(dev) + * + * Attach routine - init hardware and hook ourselves into linux + * + * Input parameters: + * dev - net_device structure + * + * Return value: + * status + ********************************************************************* */ + +static int sbmac_init(struct net_device *dev) +{ + struct sbmac_softc *sc; + u_char *eaddr; + uint64_t ea_reg; + int idx; + + sc = (struct sbmac_softc *)dev->priv; + + /* Determine controller base address */ + + sc->sbm_base = (sbmac_port_t) dev->base_addr; + sc->sbm_dev = dev; + + eaddr = sc->sbm_hwaddr; + + /* + * Read the ethernet address. The firwmare left this programmed + * for us in the ethernet address register for each mac. + */ + + ea_reg = SBMAC_READCSR(PKSEG1(sc->sbm_base + R_MAC_ETHERNET_ADDR)); + SBMAC_WRITECSR(PKSEG1(sc->sbm_base + R_MAC_ETHERNET_ADDR), 0); + for (idx = 0; idx < 6; idx++) { + eaddr[idx] = (uint8_t) (ea_reg & 0xFF); + ea_reg >>= 8; + } + + + for (idx = 0; idx < 6; idx++) { + dev->dev_addr[idx] = eaddr[idx]; + } + + + /* + * Init packet size + */ + + sc->sbm_buffersize = ENET_PACKET_SIZE + CACHELINESIZE*2 + ETHER_ALIGN; + + /* + * Initialize context (get pointers to registers and stuff), then + * allocate the memory for the descriptor tables. + */ + + sbmac_initctx(sc); + + + /* + * Display Ethernet address (this is called during the config process + * so we need to finish off the config message that was being displayed) + */ + printk(KERN_INFO + "%s: SB1250 Ethernet at 0x%08lX, address: %02X-%02X-%02X-%02X-%02X-%02X\n", + dev->name, + (unsigned long) sc->sbm_base, + eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]); + + /* + * Set up Linux device callins + */ + + spin_lock_init(&(sc->sbm_lock)); + + ether_setup(dev); + dev->open = sbmac_open; + dev->hard_start_xmit = sbmac_start_tx; + dev->stop = sbmac_close; + dev->get_stats = sbmac_get_stats; + dev->set_multicast_list = sbmac_set_rx_mode; + dev->do_ioctl = sbmac_mii_ioctl; + dev->tx_timeout = sbmac_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + return 0; + +} + + +static int sbmac_open(struct net_device *dev) +{ + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + + MOD_INC_USE_COUNT; + + if (debug > 1) { + printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq); + } + + /* + * map/route interrupt + */ + + if (request_irq(dev->irq, &sbmac_intr, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + /* + * Configure default speed + */ + + sbmac_mii_poll(sc,1); + + /* + * Turn on the channel + */ + + sbmac_set_channel_state(sc,sbmac_state_on); + + /* + * XXX Station address is in dev->dev_addr + */ + + if (dev->if_port == 0) + dev->if_port = 0; + + netif_start_queue(dev); + + sbmac_set_rx_mode(dev); + + /* Set the timer to check for link beat. */ + init_timer(&sc->sbm_timer); + sc->sbm_timer.expires = jiffies + 2; + sc->sbm_timer.data = (unsigned long)dev; + sc->sbm_timer.function = &sbmac_timer; + add_timer(&sc->sbm_timer); + + return 0; +} + + + +static int sbmac_mii_poll(struct sbmac_softc *s,int noisy) +{ + int bmsr,bmcr,k1stsr,anlpar; + int chg; + char buffer[100]; + char *p = buffer; + + /* Read the mode status and mode control registers. */ + bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR); + bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR); + + /* get the link partner status */ + anlpar = sbmac_mii_read(s,s->sbm_phys[0],MII_ANLPAR); + + /* if supported, read the 1000baseT register */ + if (bmsr & BMSR_1000BT_XSR) { + k1stsr = sbmac_mii_read(s,s->sbm_phys[0],MII_K1STSR); + } + else { + k1stsr = 0; + } + + chg = 0; + + if ((bmsr & BMSR_LINKSTAT) == 0) { + /* + * If link status is down, clear out old info so that when + * it comes back up it will force us to reconfigure speed + */ + s->sbm_phy_oldbmsr = 0; + s->sbm_phy_oldanlpar = 0; + s->sbm_phy_oldk1stsr = 0; + return 0; + } + + if ((s->sbm_phy_oldbmsr != bmsr) || + (s->sbm_phy_oldanlpar != anlpar) || + (s->sbm_phy_oldk1stsr != k1stsr)) { + if (debug > 1) { + printk(KERN_DEBUG "%s: bmsr:%x/%x anlpar:%x/%x k1stsr:%x/%x\n", + s->sbm_dev->name, + s->sbm_phy_oldbmsr,bmsr, + s->sbm_phy_oldanlpar,anlpar, + s->sbm_phy_oldk1stsr,k1stsr); + } + s->sbm_phy_oldbmsr = bmsr; + s->sbm_phy_oldanlpar = anlpar; + s->sbm_phy_oldk1stsr = k1stsr; + chg = 1; + } + + if (chg == 0) return 0; + + p += sprintf(p,"Link speed: "); + + if (k1stsr & K1STSR_LP1KFD) { + s->sbm_speed = sbmac_speed_1000; + s->sbm_duplex = sbmac_duplex_full; + s->sbm_fc = sbmac_fc_frame; + p += sprintf(p,"1000BaseT FDX"); + } + else if (k1stsr & K1STSR_LP1KHD) { + s->sbm_speed = sbmac_speed_1000; + s->sbm_duplex = sbmac_duplex_half; + s->sbm_fc = sbmac_fc_disabled; + p += sprintf(p,"1000BaseT HDX"); + } + else if (anlpar & ANLPAR_TXFD) { + s->sbm_speed = sbmac_speed_100; + s->sbm_duplex = sbmac_duplex_full; + s->sbm_fc = (anlpar & ANLPAR_PAUSE) ? sbmac_fc_frame : sbmac_fc_disabled; + p += sprintf(p,"100BaseT FDX"); + } + else if (anlpar & ANLPAR_TXHD) { + s->sbm_speed = sbmac_speed_100; + s->sbm_duplex = sbmac_duplex_half; + s->sbm_fc = sbmac_fc_disabled; + p += sprintf(p,"100BaseT HDX"); + } + else if (anlpar & ANLPAR_10FD) { + s->sbm_speed = sbmac_speed_10; + s->sbm_duplex = sbmac_duplex_full; + s->sbm_fc = sbmac_fc_frame; + p += sprintf(p,"10BaseT FDX"); + } + else if (anlpar & ANLPAR_10HD) { + s->sbm_speed = sbmac_speed_10; + s->sbm_duplex = sbmac_duplex_half; + s->sbm_fc = sbmac_fc_collision; + p += sprintf(p,"10BaseT HDX"); + } + else { + p += sprintf(p,"Unknown"); + } + + if (noisy) { + printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer); + } + + return 1; +} + + + + +static void sbmac_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + int next_tick = HZ; + int mii_status; + + spin_lock_irq (&sc->sbm_lock); + + /* make IFF_RUNNING follow the MII status bit "Link established" */ + mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR); + + if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) { + sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT; + if (mii_status & BMSR_LINKSTAT) { + netif_carrier_on(dev); + } + else { + netif_carrier_off(dev); + } + } + + /* + * Poll the PHY to see what speed we should be running at + */ + + if (sbmac_mii_poll(sc,1)) { + if (sc->sbm_state != sbmac_state_off) { + /* + * something changed, restart the channel + */ + if (debug > 1) { + printk("%s: restarting channel because speed changed\n", + sc->sbm_dev->name); + } + sbmac_channel_stop(sc); + sbmac_channel_start(sc); + } + } + + spin_unlock_irq (&sc->sbm_lock); + + sc->sbm_timer.expires = jiffies + next_tick; + add_timer(&sc->sbm_timer); +} + + +static void sbmac_tx_timeout (struct net_device *dev) +{ + struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv; + + spin_lock_irq (&sc->sbm_lock); + + + dev->trans_start = jiffies; + sc->sbm_stats.tx_errors++; + + spin_unlock_irq (&sc->sbm_lock); + + printk (KERN_WARNING "%s: Transmit timed out\n",dev->name); +} + + + + +static struct net_device_stats *sbmac_get_stats(struct net_device *dev) +{ + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + unsigned long flags; + + spin_lock_irqsave(&sc->sbm_lock, flags); + + /* XXX update other stats here */ + + spin_unlock_irqrestore(&sc->sbm_lock, flags); + + return &sc->sbm_stats; +} + + + +static void sbmac_set_rx_mode(struct net_device *dev) +{ + unsigned long flags; + int msg_flag = 0; + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + + spin_lock_irqsave(&sc->sbm_lock, flags); + if ((dev->flags ^ sc->sbm_devflags) & IFF_PROMISC) { + /* + * Promiscuous changed. + */ + + if (dev->flags & IFF_PROMISC) { + /* Unconditionally log net taps. */ + msg_flag = 1; + sbmac_promiscuous_mode(sc,1); + } + else { + msg_flag = 2; + sbmac_promiscuous_mode(sc,0); + } + } + spin_unlock_irqrestore(&sc->sbm_lock, flags); + + if (msg_flag) { + printk(KERN_NOTICE "%s: Promiscuous mode %sabled.\n", dev->name,(msg_flag==1)?"en":"dis"); + } + + /* + * Program the multicasts. Do this every time. + */ + + sbmac_setmulti(sc); + +} + +static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + u16 *data = (u16 *)&rq->ifr_data; + unsigned long flags; + int retval; + + spin_lock_irqsave(&sc->sbm_lock, flags); + retval = 0; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = sc->sbm_phys[0] & 0x1f; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = sbmac_mii_read(sc, data[0] & 0x1f, data[1] & 0x1f); + break; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) { + retval = -EPERM; + break; + } + if (debug > 1) { + printk(KERN_DEBUG "%s: sbmac_mii_ioctl: write %02X %02X %02X\n",dev->name, + data[0],data[1],data[2]); + } + sbmac_mii_write(sc, data[0] & 0x1f, data[1] & 0x1f, data[2]); + break; + default: + retval = -EOPNOTSUPP; + } + + spin_unlock_irqrestore(&sc->sbm_lock, flags); + return retval; +} + +static int sbmac_close(struct net_device *dev) +{ + struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + unsigned long flags; + + sbmac_set_channel_state(sc,sbmac_state_off); + + del_timer_sync(&sc->sbm_timer); + + spin_lock_irqsave(&sc->sbm_lock, flags); + + netif_stop_queue(dev); + + if (debug > 1) { + printk(KERN_DEBUG "%s: Shutting down ethercard\n",dev->name); + } + + spin_unlock_irqrestore(&sc->sbm_lock, flags); + + /* Make sure there is no irq-handler running on a different CPU. */ + synchronize_irq(); + + free_irq(dev->irq, dev); + + sbdma_emptyring(&(sc->sbm_txdma)); + sbdma_emptyring(&(sc->sbm_rxdma)); + + MOD_DEC_USE_COUNT; + + return 0; +} + + + +#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) +static void +sbmac_setup_hwaddr(int chan,char *addr) +{ + uint8_t eaddr[6]; + uint64_t val; + sbmac_port_t port; + + port = A_MAC_CHANNEL_BASE(chan); + sbmac_parse_hwaddr(addr,eaddr); + val = sbmac_addr2reg(eaddr); + SBMAC_WRITECSR(PKSEG1(port+R_MAC_ETHERNET_ADDR),val); + val = SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR)); +} +#endif + +static struct net_device *dev_sbmac[MAX_UNITS] = {0,0,0}; + +static int __init +sbmac_init_module(void) +{ + int idx; + int macidx = 0; + struct net_device *dev; + sbmac_port_t port; + + /* + * For bringup when not using the firmware, we can pre-fill + * the MAC addresses using the environment variables + * specified in this file (or maybe from the config file?) + */ +#ifdef SBMAC_ETH0_HWADDR + sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR); +#endif +#ifdef SBMAC_ETH1_HWADDR + sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR); +#endif +#ifdef SBMAC_ETH2_HWADDR + sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR); +#endif + + /* + * Walk through the Ethernet controllers and find + * those who have their MAC addresses set. + */ + + for (idx = 0; idx < MAX_UNITS; idx++) { + + /* + * This is the base address of the MAC. + */ + + port = A_MAC_CHANNEL_BASE(idx); + + /* + * The R_MAC_ETHERNET_ADDR register will be set to some nonzero + * value for us by the firmware if we're going to use this MAC. + * If we find a zero, skip this MAC. + */ + + if (SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR)) == 0) { + continue; + } + + /* + * Okay, cool. Initialize this MAC. + */ + + dev = init_etherdev(NULL,sizeof(struct sbmac_softc)); + if (!dev) break; /* problems, get out now. */ + dev->irq = K_INT_MAC_0 + idx; + dev->base_addr = port; + dev->mem_end = 0; + /*dev->init = sbmac_init;*/ + sbmac_init(dev); + + dev_sbmac[macidx] = dev; + macidx++; + + } + + /* + * Should we care, 'macidx' is the total number of enabled MACs. + */ + + return 0; +} + + +static void __exit +sbmac_cleanup_module(void) +{ + int idx; + struct net_device *dev; + for (idx = 0; idx < MAX_UNITS; idx++) { + dev = dev_sbmac[idx]; + if (dev == NULL) continue; + if (dev->priv != NULL) { + struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv; + + unregister_netdev(dev); + + sbmac_uninitctx(sc); + + KFREE(sc); + } + KFREE(dev); + dev_sbmac[idx] = NULL; + } +} + +module_init(sbmac_init_module); +module_exit(sbmac_cleanup_module); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/sgiseeq.c linux-2.5/drivers/net/sgiseeq.c --- linux-2.5.5/drivers/net/sgiseeq.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/net/sgiseeq.c Sun Mar 3 17:54:35 2002 @@ -1,10 +1,10 @@ -/* $Id: sgiseeq.c,v 1.17 2000/03/27 23:02:57 ralf Exp $ - * +/* * sgiseeq.c: Seeq8003 ethernet driver for SGI machines. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ #include +#include #include #include #include @@ -450,20 +450,22 @@ unsigned long flags; int err; - save_flags(flags); cli(); - if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, (void *) dev)) { + __save_and_cli(flags); + + err = -EAGAIN; + if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) { printk("Seeq8003: Can't get irq %d\n", dev->irq); - restore_flags(flags); - return -EAGAIN; + goto out; } - err = init_seeq(dev, sp, sregs); if (err) - return err; + goto out; netif_start_queue(dev); - restore_flags(flags); - return 0; + +out: + __restore_flags(flags); + return err; } static int sgiseeq_close(struct net_device *dev) @@ -720,3 +722,5 @@ (struct sgiseeq_regs *) (KSEG1ADDR(0x1fbd4000)), &hpc3c0->ethregs, SGI_ENET_IRQ); } + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/sis900.c linux-2.5/drivers/net/sis900.c --- linux-2.5.5/drivers/net/sis900.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/net/sis900.c Fri Jan 18 22:19:46 2002 @@ -2129,7 +2129,7 @@ name: SIS900_MODULE_NAME, id_table: sis900_pci_tbl, probe: sis900_probe, - remove: sis900_remove, + remove: __devexit_p(sis900_remove), }; static int __init sis900_init_module(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/sonic.c linux-2.5/drivers/net/sonic.c --- linux-2.5.5/drivers/net/sonic.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/net/sonic.c Sun Mar 3 17:54:35 2002 @@ -620,3 +620,5 @@ return 0; } + +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/starfire.c linux-2.5/drivers/net/starfire.c --- linux-2.5.5/drivers/net/starfire.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/starfire.c Fri Jan 18 22:19:47 2002 @@ -1982,7 +1982,7 @@ static struct pci_driver starfire_driver = { name: DRV_NAME, probe: starfire_init_one, - remove: starfire_remove_one, + remove: __devexit_p(starfire_remove_one), id_table: starfire_pci_tbl, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/strip.c linux-2.5/drivers/net/strip.c --- linux-2.5.5/drivers/net/strip.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/net/strip.c Sun Mar 3 20:15:15 2002 @@ -2080,6 +2080,7 @@ #ifdef EXT_COUNTERS strip_info->rx_bytes += packetlen; #endif + skb->dev->last_rx = jiffies; netif_rx(skb); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/sundance.c linux-2.5/drivers/net/sundance.c --- linux-2.5.5/drivers/net/sundance.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/net/sundance.c Fri Feb 8 14:36:29 2002 @@ -1463,7 +1463,7 @@ name: DRV_NAME, id_table: sundance_pci_tbl, probe: sundance_probe1, - remove: sundance_remove1, + remove: __devexit_p(sundance_remove1), }; static int __init sundance_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/sungem.c linux-2.5/drivers/net/sungem.c --- linux-2.5.5/drivers/net/sungem.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/net/sungem.c Tue Feb 26 21:24:49 2002 @@ -99,11 +99,6 @@ #define GEM_MODULE_NAME "gem" #define PFX GEM_MODULE_NAME ": " -/* Until this gets merged from 2.4.x... */ -#ifndef PCI_DEVICE_ID_APPLE_UNI_N_GMACP -#define PCI_DEVICE_ID_APPLE_UNI_N_GMACP 0x0024 -#endif - static struct pci_device_id gem_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_GEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, @@ -296,16 +291,26 @@ static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) { u32 rxmac_stat = readl(gp->regs + MAC_RXSTAT); + int ret = 0; if (netif_msg_intr(gp)) printk(KERN_DEBUG "%s: rxmac interrupt, rxmac_stat: 0x%x\n", gp->dev->name, rxmac_stat); if (rxmac_stat & MAC_RXSTAT_OFLW) { - printk(KERN_ERR "%s: RX MAC fifo overflow.\n", - dev->name); + u32 smac = readl(gp->regs + MAC_SMACHINE); + + printk(KERN_ERR "%s: RX MAC fifo overflow smac[%08x].\n", + dev->name, smac); gp->net_stats.rx_over_errors++; gp->net_stats.rx_fifo_errors++; + + if (((smac >> 24) & 0x7) == 0x7) { + /* Due to a bug, the chip is hung in this case + * and a full reset is necessary. + */ + ret = 1; + } } if (rxmac_stat & MAC_RXSTAT_ACE) @@ -320,7 +325,7 @@ /* We do not track MAC_RXSTAT_FCE and MAC_RXSTAT_VCE * events. */ - return 0; + return ret; } static int gem_mac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) @@ -480,7 +485,7 @@ return 0; do_reset: - gp->reset_task_pending = 1; + gp->reset_task_pending = 2; schedule_task(&gp->reset_task); return 1; @@ -1182,7 +1187,8 @@ /* Reset the chip & rings */ gem_stop(gp); gem_init_rings(gp, 0); - gem_init_hw(gp, 0); + gem_init_hw(gp, + (gp->reset_task_pending == 2)); netif_wake_queue(gp->dev); } @@ -2835,7 +2841,7 @@ name: GEM_MODULE_NAME, id_table: gem_pci_tbl, probe: gem_init_one, - remove: gem_remove_one, + remove: __devexit_p(gem_remove_one), #ifdef CONFIG_PM suspend: gem_suspend, resume: gem_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tc35815.c linux-2.5/drivers/net/tc35815.c --- linux-2.5.5/drivers/net/tc35815.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/tc35815.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,1779 @@ +/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Based on skelton.c by Donald Becker. + * Copyright (C) 2000-2001 Toshiba Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +static const char *version = + "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n"; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +/* + * The name of the card. Is used for messages and in the requests for + * io regions, irqs and dma channels + */ +static const char* cardname = "TC35815CF"; +#define TC35815_PROC_ENTRY "net/tc35815" + +#define TC35815_MODULE_NAME "TC35815CF" +#define TX_TIMEOUT (4*HZ) + +/* First, a few definitions that the brave might change. */ + +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef TC35815_DEBUG +#define TC35815_DEBUG 1 +#endif +static unsigned int tc35815_debug = TC35815_DEBUG; + +#define GATHER_TXINT /* On-Demand Tx Interrupt */ + +#define vtonocache(p) KSEG1ADDR(virt_to_phys(p)) + +/* + * Registers + */ +struct tc35815_regs { + volatile __u32 DMA_Ctl; /* 0x00 */ + volatile __u32 TxFrmPtr; + volatile __u32 TxThrsh; + volatile __u32 TxPollCtr; + volatile __u32 BLFrmPtr; + volatile __u32 RxFragSize; + volatile __u32 Int_En; + volatile __u32 FDA_Bas; + volatile __u32 FDA_Lim; /* 0x20 */ + volatile __u32 Int_Src; + volatile __u32 unused0[2]; + volatile __u32 PauseCnt; + volatile __u32 RemPauCnt; + volatile __u32 TxCtlFrmStat; + volatile __u32 unused1; + volatile __u32 MAC_Ctl; /* 0x40 */ + volatile __u32 CAM_Ctl; + volatile __u32 Tx_Ctl; + volatile __u32 Tx_Stat; + volatile __u32 Rx_Ctl; + volatile __u32 Rx_Stat; + volatile __u32 MD_Data; + volatile __u32 MD_CA; + volatile __u32 CAM_Adr; /* 0x60 */ + volatile __u32 CAM_Data; + volatile __u32 CAM_Ena; + volatile __u32 PROM_Ctl; + volatile __u32 PROM_Data; + volatile __u32 Algn_Cnt; + volatile __u32 CRC_Cnt; + volatile __u32 Miss_Cnt; +}; + +/* + * Bit assignments + */ +/* DMA_Ctl bit asign ------------------------------------------------------- */ +#define DMA_IntMask 0x00040000 /* 1:Interupt mask */ +#define DMA_SWIntReq 0x00020000 /* 1:Software Interrupt request */ +#define DMA_TxWakeUp 0x00010000 /* 1:Transmit Wake Up */ +#define DMA_RxBigE 0x00008000 /* 1:Receive Big Endian */ +#define DMA_TxBigE 0x00004000 /* 1:Transmit Big Endian */ +#define DMA_TestMode 0x00002000 /* 1:Test Mode */ +#define DMA_PowrMgmnt 0x00001000 /* 1:Power Management */ +#define DMA_DmBurst_Mask 0x000001fc /* DMA Burst size */ + +/* RxFragSize bit asign ---------------------------------------------------- */ +#define RxFrag_EnPack 0x00008000 /* 1:Enable Packing */ +#define RxFrag_MinFragMask 0x00000ffc /* Minimum Fragment */ + +/* MAC_Ctl bit asign ------------------------------------------------------- */ +#define MAC_Link10 0x00008000 /* 1:Link Status 10Mbits */ +#define MAC_EnMissRoll 0x00002000 /* 1:Enable Missed Roll */ +#define MAC_MissRoll 0x00000400 /* 1:Missed Roll */ +#define MAC_Loop10 0x00000080 /* 1:Loop 10 Mbps */ +#define MAC_Conn_Auto 0x00000000 /*00:Connection mode (Automatic) */ +#define MAC_Conn_10M 0x00000020 /*01: (10Mbps endec)*/ +#define MAC_Conn_Mll 0x00000040 /*10: (Mll clock) */ +#define MAC_MacLoop 0x00000010 /* 1:MAC Loopback */ +#define MAC_FullDup 0x00000008 /* 1:Full Duplex 0:Half Duplex */ +#define MAC_Reset 0x00000004 /* 1:Software Reset */ +#define MAC_HaltImm 0x00000002 /* 1:Halt Immediate */ +#define MAC_HaltReq 0x00000001 /* 1:Halt request */ + +/* PROM_Ctl bit asign ------------------------------------------------------ */ +#define PROM_Busy 0x00008000 /* 1:Busy (Start Operation) */ +#define PROM_Read 0x00004000 /*10:Read operation */ +#define PROM_Write 0x00002000 /*01:Write operation */ +#define PROM_Erase 0x00006000 /*11:Erase operation */ + /*00:Enable or Disable Writting, */ + /* as specified in PROM_Addr. */ +#define PROM_Addr_Ena 0x00000030 /*11xxxx:PROM Write enable */ + /*00xxxx: disable */ + +/* CAM_Ctl bit asign ------------------------------------------------------- */ +#define CAM_CompEn 0x00000010 /* 1:CAM Compare Enable */ +#define CAM_NegCAM 0x00000008 /* 1:Reject packets CAM recognizes,*/ + /* accept other */ +#define CAM_BroadAcc 0x00000004 /* 1:Broadcast assept */ +#define CAM_GroupAcc 0x00000002 /* 1:Multicast assept */ +#define CAM_StationAcc 0x00000001 /* 1:unicast accept */ + +/* CAM_Ena bit asign ------------------------------------------------------- */ +#define CAM_ENTRY_MAX 21 /* CAM Data entry max count */ +#define CAM_Ena_Mask ((1<= 2 */ +#define RX_FD_NUM 250 /* >= 32 */ +#define TX_FD_NUM 128 + +struct TxFD { + struct FDesc fd; + struct BDesc bd; + struct BDesc unused; +}; + +struct RxFD { + struct FDesc fd; + struct BDesc bd[0]; /* variable length */ +}; + +struct FrFD { + struct FDesc fd; + struct BDesc bd[RX_BUF_PAGES]; +}; + + +extern unsigned long tc_readl(volatile __u32 *addr); +extern void tc_writel(unsigned long data, volatile __u32 *addr); + +dma_addr_t priv_dma_handle; + +/* Information that need to be kept for each board. */ +struct tc35815_local { + struct net_device *next_module; + + /* statistics */ + struct net_device_stats stats; + struct { + int max_tx_qlen; + int tx_ints; + int rx_ints; + } lstats; + + int tbusy; + int option; +#define TC35815_OPT_AUTO 0x00 +#define TC35815_OPT_10M 0x01 +#define TC35815_OPT_100M 0x02 +#define TC35815_OPT_FULLDUP 0x04 + int linkspeed; /* 10 or 100 */ + int fullduplex; + + /* + * Transmitting: Batch Mode. + * 1 BD in 1 TxFD. + * Receiving: Packing Mode. + * 1 circular FD for Free Buffer List. + * RX_BUG_PAGES BD in Free Buffer FD. + * One Free Buffer BD has PAGE_SIZE data buffer. + */ + struct pci_dev *pdev; + dma_addr_t fd_buf_dma_handle; + void * fd_buf; /* for TxFD, TxFD, FrFD */ + struct TxFD *tfd_base; + int tfd_start; + int tfd_end; + struct RxFD *rfd_base; + struct RxFD *rfd_limit; + struct RxFD *rfd_cur; + struct FrFD *fbl_ptr; + unsigned char fbl_curid; + dma_addr_t data_buf_dma_handle[RX_BUF_PAGES]; + void * data_buf[RX_BUF_PAGES]; /* packing */ +}; + +/* Index to functions, as function prototypes. */ + +static int __init tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq); + +static int tc35815_open(struct net_device *dev); +static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev); +static void tc35815_tx_timeout(struct net_device *dev); +static void tc35815_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void tc35815_rx(struct net_device *dev); +static void tc35815_txdone(struct net_device *dev); +static int tc35815_close(struct net_device *dev); +static struct net_device_stats *tc35815_get_stats(struct net_device *dev); +static void tc35815_set_multicast_list(struct net_device *dev); + +static void tc35815_chip_reset(struct net_device *dev); +static void tc35815_chip_init(struct net_device *dev); +static void tc35815_phy_chip_init(struct net_device *dev); +static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data); + +/* A list of all installed tc35815 devices. */ +static struct net_device *root_tc35815_dev = NULL; + +/* + * PCI device identifiers for "new style" Linux PCI Device Drivers + */ +static struct pci_device_id tc35815_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + +MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl); + +int +tc35815_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int called = 0; + int err = 0; + int ret; + + if (called) + return -ENODEV; + called++; + + if (!pci_present()) + return -ENODEV; + + if (pdev) { + unsigned int pci_memaddr; + unsigned int pci_irq_line; + + printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device); + + pci_memaddr = pci_resource_start (pdev, 1); + + printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0)); + + if (!pci_memaddr) { + printk(KERN_WARNING "no PCI MEM resources, aborting\n"); + return -ENODEV; + } + pci_irq_line = pdev->irq; + /* irq disabled. */ + if (pci_irq_line == 0) { + printk(KERN_WARNING "no PCI irq, aborting\n"); + return -ENODEV; + } + + ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line); + + if (!ret) { + if ((err = pci_enable_device(pdev)) < 0) { + printk(KERN_ERR "tc35815_probe: failed to enable device -- err=%d\n", err); + return err; + } + pci_set_master(pdev); + } + + return ret; + } + return -ENODEV; +} + +static int __init tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq) +{ + static unsigned version_printed = 0; + int i; + struct tc35815_local *lp; + struct tc35815_regs *tr; + struct net_device *dev; + + /* Allocate a new 'dev' if needed. */ + dev = init_etherdev(NULL, 0); + if (dev == NULL) + return -ENOMEM; + + if (tc35815_debug && version_printed++ == 0) + printk(KERN_DEBUG "%s", version); + + printk(KERN_INFO "%s: %s found at %#x, irq %d\n", + dev->name, cardname, base_addr, irq); + + /* Fill in the 'dev' fields. */ + dev->irq = irq; + dev->base_addr = (unsigned long)ioremap(base_addr, + sizeof(struct tc35815_regs)); + tr = (struct tc35815_regs*)dev->base_addr; + + tc35815_chip_reset(dev); + + /* Retrieve and print the ethernet address. */ + while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) + ; + for (i = 0; i < 6; i += 2) { + unsigned short data; + tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl); + while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) + ; + data = tc_readl(&tr->PROM_Data); + dev->dev_addr[i] = data & 0xff; + dev->dev_addr[i+1] = data >> 8; + } + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i]); + printk("\n"); + + /* Initialize the device structure. */ + if (dev->priv == NULL) { + dev->priv = kmalloc(sizeof(struct tc35815_local), GFP_KERNEL); + if (dev->priv == NULL) + return -ENODEV; + } + lp = dev->priv; + + lp->pdev = pdev; + + memset(lp, 0, sizeof(struct tc35815_local)); + + lp->next_module = root_tc35815_dev; + root_tc35815_dev = dev; + + if (dev->mem_start > 0) { + lp->option = dev->mem_start; + if ((lp->option & TC35815_OPT_10M) && + (lp->option & TC35815_OPT_100M)) { + /* if both speed speficied, auto select. */ + lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M); + } + } + //XXX fixme + lp->option |= TC35815_OPT_10M; + + /* do auto negotiation */ + tc35815_phy_chip_init(dev); + printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n", + dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half"); + + dev->open = tc35815_open; + dev->stop = tc35815_close; + dev->tx_timeout = tc35815_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->hard_start_xmit = tc35815_send_packet; + dev->get_stats = tc35815_get_stats; + dev->set_multicast_list = tc35815_set_multicast_list; + +#if 0 /* XXX called in init_etherdev */ + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); +#endif + + return 0; +} + + +static int +tc35815_init_queues(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + int i; + unsigned long fd_addr; + + if (!lp->fd_buf) { + if (sizeof(struct FDesc) + + sizeof(struct BDesc) * RX_BUF_PAGES + + sizeof(struct FDesc) * RX_FD_NUM + + sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) { + printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name); + return -ENOMEM; + } + + if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0) + return -ENOMEM; + for (i = 0; i < RX_BUF_PAGES; i++) { + if ((lp->data_buf[i] = (void *)get_free_page(GFP_KERNEL)) == 0) { + while (--i >= 0) { + free_page((unsigned long)lp->data_buf[i]); + lp->data_buf[i] = 0; + } + free_page((unsigned long)lp->fd_buf); + lp->fd_buf = 0; + return -ENOMEM; + } +#ifdef __mips__ + dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM); +#endif + } +#ifdef __mips__ + dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM); +#endif + } else { + clear_page(lp->fd_buf); +#ifdef __mips__ + dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM); +#endif + } +#ifdef __mips__ + fd_addr = (unsigned long)vtonocache(lp->fd_buf); +#else + fd_addr = (unsigned long)lp->fd_buf; +#endif + + /* Free Descriptors (for Receive) */ + lp->rfd_base = (struct RxFD *)fd_addr; + fd_addr += sizeof(struct RxFD) * RX_FD_NUM; + for (i = 0; i < RX_FD_NUM; i++) { + lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD); + } + lp->rfd_cur = lp->rfd_base; + lp->rfd_limit = (struct RxFD *)(fd_addr - + sizeof(struct FDesc) - + sizeof(struct BDesc) * 30); + + /* Transmit Descriptors */ + lp->tfd_base = (struct TxFD *)fd_addr; + fd_addr += sizeof(struct TxFD) * TX_FD_NUM; + for (i = 0; i < TX_FD_NUM; i++) { + lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1])); + lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); + lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0); + } + lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0])); + lp->tfd_start = 0; + lp->tfd_end = 0; + + /* Buffer List (for Receive) */ + lp->fbl_ptr = (struct FrFD *)fd_addr; + lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr)); + lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD); + for (i = 0; i < RX_BUF_PAGES; i++) { + lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i])); + /* BDID is index of FrFD.bd[] */ + lp->fbl_ptr->bd[i].BDCtl = + cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE); + } + lp->fbl_curid = 0; + + return 0; +} + +static void +tc35815_clear_queues(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + int i; + + for (i = 0; i < TX_FD_NUM; i++) { + struct sk_buff *skb = (struct sk_buff *) + le32_to_cpu(lp->tfd_base[i].fd.FDSystem); + if (skb) + dev_kfree_skb_any(skb); + lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); + } + + tc35815_init_queues(dev); +} + +static void +tc35815_free_queues(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + int i; + + if (lp->tfd_base) { + for (i = 0; i < TX_FD_NUM; i++) { + struct sk_buff *skb = (struct sk_buff *) + le32_to_cpu(lp->tfd_base[i].fd.FDSystem); + if (skb) + dev_kfree_skb_any(skb); + lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); + } + } + + lp->rfd_base = NULL; + lp->rfd_base = NULL; + lp->rfd_limit = NULL; + lp->rfd_cur = NULL; + lp->fbl_ptr = NULL; + + for (i = 0; i < RX_BUF_PAGES; i++) { + if (lp->data_buf[i]) + free_page((unsigned long)lp->data_buf[i]); + lp->data_buf[i] = 0; + } + if (lp->fd_buf) + __free_pages(lp->fd_buf, FD_PAGE_ORDER); + lp->fd_buf = NULL; +} + +static void +dump_txfd(struct TxFD *fd) +{ + printk("TxFD(%p): %08x %08x %08x %08x\n", fd, + le32_to_cpu(fd->fd.FDNext), + le32_to_cpu(fd->fd.FDSystem), + le32_to_cpu(fd->fd.FDStat), + le32_to_cpu(fd->fd.FDCtl)); + printk("BD: "); + printk(" %08x %08x", + le32_to_cpu(fd->bd.BuffData), + le32_to_cpu(fd->bd.BDCtl)); + printk("\n"); +} + +static int +dump_rxfd(struct RxFD *fd) +{ + int i, bd_count = (le32_to_cpu(fd->fd.FDCtl) & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT; + if (bd_count > 8) + bd_count = 8; + printk("RxFD(%p): %08x %08x %08x %08x\n", fd, + le32_to_cpu(fd->fd.FDNext), + le32_to_cpu(fd->fd.FDSystem), + le32_to_cpu(fd->fd.FDStat), + le32_to_cpu(fd->fd.FDCtl)); + if (le32_to_cpu(fd->fd.FDCtl) & FD_CownsFD) + return 0; + printk("BD: "); + for (i = 0; i < bd_count; i++) + printk(" %08x %08x", + le32_to_cpu(fd->bd[i].BuffData), + le32_to_cpu(fd->bd[i].BDCtl)); + printk("\n"); + return bd_count; +} + +static void +dump_frfd(struct FrFD *fd) +{ + int i; + printk("FrFD(%p): %08x %08x %08x %08x\n", fd, + le32_to_cpu(fd->fd.FDNext), + le32_to_cpu(fd->fd.FDSystem), + le32_to_cpu(fd->fd.FDStat), + le32_to_cpu(fd->fd.FDCtl)); + printk("BD: "); + for (i = 0; i < RX_BUF_PAGES; i++) + printk(" %08x %08x", + le32_to_cpu(fd->bd[i].BuffData), + le32_to_cpu(fd->bd[i].BDCtl)); + printk("\n"); +} + +static void +panic_queues(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + int i; + + printk("TxFD base %p, start %d, end %d\n", + lp->tfd_base, lp->tfd_start, lp->tfd_end); + printk("RxFD base %p limit %p cur %p\n", + lp->rfd_base, lp->rfd_limit, lp->rfd_cur); + printk("FrFD %p\n", lp->fbl_ptr); + for (i = 0; i < TX_FD_NUM; i++) + dump_txfd(&lp->tfd_base[i]); + for (i = 0; i < RX_FD_NUM; i++) { + int bd_count = dump_rxfd(&lp->rfd_base[i]); + i += (bd_count + 1) / 2; /* skip BDs */ + } + dump_frfd(lp->fbl_ptr); + panic("%s: Illegal queue state.", dev->name); +} + +static void print_buf(char *add, int length) +{ + int i; + int len = length; + + printk("print_buf(%08x)(%x)\n", (unsigned int) add,length); + + if (len > 100) + len = 100; + for (i = 0; i < len; i++) { + printk(" %2.2X", (unsigned char) add[i]); + if (!(i % 16)) + printk("\n"); + } + printk("\n"); +} + +static void print_eth(char *add) +{ + int i; + + printk("print_eth(%08x)\n", (unsigned int) add); + for (i = 0; i < 6; i++) + printk(" %2.2X", (unsigned char) add[i + 6]); + printk(" =>"); + for (i = 0; i < 6; i++) + printk(" %2.2X", (unsigned char) add[i]); + printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]); +} + +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is non-reboot way to recover if something goes wrong. + */ +static int +tc35815_open(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + /* + * This is used if the interrupt line can turned off (shared). + * See 3c503.c for an example of selecting the IRQ at config-time. + */ + + if (dev->irq == 0 || + request_irq(dev->irq, &tc35815_interrupt, SA_SHIRQ, cardname, dev)) { + return -EAGAIN; + } + + tc35815_chip_reset(dev); + + if (tc35815_init_queues(dev) != 0) { + free_irq(dev->irq, dev); + return -EAGAIN; + } + + /* Reset the hardware here. Don't forget to set the station address. */ + tc35815_chip_init(dev); + + lp->tbusy = 0; + netif_start_queue(dev); + + MOD_INC_USE_COUNT; + + return 0; +} + +static void tc35815_tx_timeout(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; + int flags; + + save_and_cli(flags); + printk(KERN_WARNING "%s: transmit timed out, status %#x\n", + dev->name, tc_readl(&tr->Tx_Stat)); + /* Try to restart the adaptor. */ + tc35815_chip_reset(dev); + tc35815_clear_queues(dev); + tc35815_chip_init(dev); + lp->tbusy=0; + restore_flags(flags); + dev->trans_start = jiffies; + netif_wake_queue(dev); +} + +static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; + + if (netif_queue_stopped(dev)) { + /* + * If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + printk(KERN_WARNING "%s: transmit timed out, status %#x\n", + dev->name, tc_readl(&tr->Tx_Stat)); + /* Try to restart the adaptor. */ + tc35815_chip_reset(dev); + tc35815_clear_queues(dev); + tc35815_chip_init(dev); + lp->tbusy=0; + dev->trans_start = jiffies; + netif_wake_queue(dev); + } + + /* + * Block a timer-based transmit from overlapping. This could better be + * done with atomic_swap(1, lp->tbusy), but set_bit() works as well. + */ + if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) { + printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); + dev_kfree_skb_any(skb); + } else { + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = skb->data; + struct TxFD *txfd = &lp->tfd_base[lp->tfd_start]; + int flags; + lp->stats.tx_bytes += skb->len; + + +#ifdef __mips__ + dma_cache_wback_inv((unsigned long)buf, length); +#endif + + save_and_cli(flags); + + /* failsafe... */ + if (lp->tfd_start != lp->tfd_end) + tc35815_txdone(dev); + + + txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf)); + + txfd->bd.BDCtl = cpu_to_le32(length); + txfd->fd.FDSystem = cpu_to_le32((__u32)skb); + txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT)); + + if (lp->tfd_start == lp->tfd_end) { + /* Start DMA Transmitter. */ + txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL); +#ifdef GATHER_TXINT + txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); +#endif + if (tc35815_debug > 2) { + printk("%s: starting TxFD.\n", dev->name); + dump_txfd(txfd); + if (tc35815_debug > 3) + print_eth(buf); + } + tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr); + } else { + txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL); + if (tc35815_debug > 2) { + printk("%s: queueing TxFD.\n", dev->name); + dump_txfd(txfd); + if (tc35815_debug > 3) + print_eth(buf); + } + } + lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM; + + dev->trans_start = jiffies; + + if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) { + /* we can send another packet */ + lp->tbusy = 0; + netif_start_queue(dev); + } else { + netif_stop_queue(dev); + if (tc35815_debug > 1) + printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name); + } + restore_flags(flags); + } + + return 0; +} + +#define FATAL_ERROR_INT \ + (Int_IntPCI | Int_DmParErr | Int_IntNRAbt) +static void tc35815_fatal_error_interrupt(struct net_device *dev, int status) +{ + static int count; + printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):", + dev->name, status); + + if (status & Int_IntPCI) + printk(" IntPCI"); + if (status & Int_DmParErr) + printk(" DmParErr"); + if (status & Int_IntNRAbt) + printk(" IntNRAbt"); + printk("\n"); + if (count++ > 100) + panic("%s: Too many fatal errors.", dev->name); + printk(KERN_WARNING "%s: Resetting %s...\n", dev->name, cardname); + /* Try to restart the adaptor. */ + tc35815_chip_reset(dev); + tc35815_clear_queues(dev); + tc35815_chip_init(dev); +} + +/* + * The typical workload of the driver: + * Handle the network interface interrupts. + */ +static void tc35815_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + struct tc35815_regs *tr; + struct tc35815_local *lp; + int status, boguscount = 0; + + if (dev == NULL) { + printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); + return; + } + + tr = (struct tc35815_regs*)dev->base_addr; + lp = (struct tc35815_local *)dev->priv; + + do { + status = tc_readl(&tr->Int_Src); + if (status == 0) + break; + tc_writel(status, &tr->Int_Src); /* write to clear */ + + /* Fatal errors... */ + if (status & FATAL_ERROR_INT) { + tc35815_fatal_error_interrupt(dev, status); + break; + } + /* recoverable errors */ + if (status & Int_IntFDAEx) { + /* disable FDAEx int. (until we make rooms...) */ + tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En); + printk(KERN_WARNING + "%s: Free Descriptor Area Exhausted (%#x).\n", + dev->name, status); + lp->stats.rx_dropped++; + } + if (status & Int_IntBLEx) { + /* disable BLEx int. (until we make rooms...) */ + tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En); + printk(KERN_WARNING + "%s: Buffer List Exhausted (%#x).\n", + dev->name, status); + lp->stats.rx_dropped++; + } + if (status & Int_IntExBD) { + printk(KERN_WARNING + "%s: Excessive Buffer Descriptiors (%#x).\n", + dev->name, status); + lp->stats.rx_length_errors++; + } + /* normal notification */ + if (status & Int_IntMacRx) { + /* Got a packet(s). */ + lp->lstats.rx_ints++; + tc35815_rx(dev); + } + if (status & Int_IntMacTx) { + lp->lstats.tx_ints++; + tc35815_txdone(dev); + } + } while (++boguscount < 20) ; + + return; +} + +/* We have a good packet(s), get it/them out of the buffers. */ +static void +tc35815_rx(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + unsigned int fdctl; + int i; + int buf_free_count = 0; + int fd_free_count = 0; + + while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) { + int status = le32_to_cpu(lp->rfd_cur->fd.FDStat); + int pkt_len = fdctl & FD_FDLength_MASK; + struct RxFD *next_rfd; + int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT; + + if (tc35815_debug > 2) + dump_rxfd(lp->rfd_cur); + if (status & Rx_Good) { + /* Malloc up new buffer. */ + struct sk_buff *skb; + unsigned char *data; + int cur_bd, offset; + + lp->stats.rx_bytes += pkt_len; + + skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */ + if (skb == NULL) { + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", + dev->name); + lp->stats.rx_dropped++; + break; + } + skb_reserve(skb, 2); /* 16 bit alignment */ + skb->dev = dev; + + data = skb_put(skb, pkt_len); + + /* copy from receive buffer */ + cur_bd = 0; + offset = 0; + while (offset < pkt_len && cur_bd < bd_count) { + int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) & + BD_BuffLength_MASK; + void *rxbuf = + bus_to_virt(le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData)); +#ifdef __mips__ + dma_cache_inv((unsigned long)rxbuf, len); +#endif + memcpy(data + offset, rxbuf, len); + offset += len; + cur_bd++; + } + // print_buf(data,pkt_len); + if (tc35815_debug > 3) + print_eth(data); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + lp->stats.rx_packets++; + } else { + lp->stats.rx_errors++; + /* WORKAROUND: LongErr and CRCErr means Overflow. */ + if ((status & Rx_LongErr) && (status & Rx_CRCErr)) { + status &= ~(Rx_LongErr|Rx_CRCErr); + status |= Rx_Over; + } + if (status & Rx_LongErr) lp->stats.rx_length_errors++; + if (status & Rx_Over) lp->stats.rx_fifo_errors++; + if (status & Rx_CRCErr) lp->stats.rx_crc_errors++; + if (status & Rx_Align) lp->stats.rx_frame_errors++; + } + + if (bd_count > 0) { + /* put Free Buffer back to controller */ + int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl); + unsigned char id = + (bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT; + if (id >= RX_BUF_PAGES) { + printk("%s: invalid BDID.\n", dev->name); + panic_queues(dev); + } + /* free old buffers */ + while (lp->fbl_curid != id) { + bdctl = le32_to_cpu(lp->fbl_ptr->bd[lp->fbl_curid].BDCtl); + if (bdctl & BD_CownsBD) { + printk("%s: Freeing invalid BD.\n", + dev->name); + panic_queues(dev); + } + /* pass BD to controler */ + /* Note: BDLength was modified by chip. */ + lp->fbl_ptr->bd[lp->fbl_curid].BDCtl = + cpu_to_le32(BD_CownsBD | + (lp->fbl_curid << BD_RxBDID_SHIFT) | + PAGE_SIZE); + lp->fbl_curid = + (lp->fbl_curid + 1) % RX_BUF_PAGES; + if (tc35815_debug > 2) { + printk("%s: Entering new FBD %d\n", + dev->name, lp->fbl_curid); + dump_frfd(lp->fbl_ptr); + } + buf_free_count++; + } + } + + /* put RxFD back to controller */ + next_rfd = bus_to_virt(le32_to_cpu(lp->rfd_cur->fd.FDNext)); +#ifdef __mips__ + next_rfd = (struct RxFD *)vtonocache(next_rfd); +#endif + if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) { + printk("%s: RxFD FDNext invalid.\n", dev->name); + panic_queues(dev); + } + for (i = 0; i < (bd_count + 1) / 2 + 1; i++) { + /* pass FD to controler */ + lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead); /* for debug */ + lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD); + lp->rfd_cur++; + fd_free_count++; + } + + lp->rfd_cur = next_rfd; + } + + /* re-enable BL/FDA Exhaust interupts. */ + if (fd_free_count) { + tc_writel(tc_readl(&tr->Int_En) | Int_FDAExEn, &tr->Int_En); + if (buf_free_count) + tc_writel(tc_readl(&tr->Int_En) | Int_BLExEn, &tr->Int_En); + } +} + +#ifdef NO_CHECK_CARRIER +#define TX_STA_ERR (Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr) +#else +#define TX_STA_ERR (Tx_ExColl|Tx_Under|Tx_Defer|Tx_NCarr|Tx_LateColl|Tx_TxPar|Tx_SQErr) +#endif + +static void +tc35815_check_tx_stat(struct net_device *dev, int status) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + const char *msg = NULL; + + /* count collisions */ + if (status & Tx_ExColl) + lp->stats.collisions += 16; + if (status & Tx_TxColl_MASK) + lp->stats.collisions += status & Tx_TxColl_MASK; + + /* WORKAROUND: ignore LostCrS in full duplex operation */ + if (lp->fullduplex) + status &= ~Tx_NCarr; + + if (!(status & TX_STA_ERR)) { + /* no error. */ + lp->stats.tx_packets++; + return; + } + + lp->stats.tx_errors++; + if (status & Tx_ExColl) { + lp->stats.tx_aborted_errors++; + msg = "Excessive Collision."; + } + if (status & Tx_Under) { + lp->stats.tx_fifo_errors++; + msg = "Tx FIFO Underrun."; + } + if (status & Tx_Defer) { + lp->stats.tx_fifo_errors++; + msg = "Excessive Deferral."; + } +#ifndef NO_CHECK_CARRIER + if (status & Tx_NCarr) { + lp->stats.tx_carrier_errors++; + msg = "Lost Carrier Sense."; + } +#endif + if (status & Tx_LateColl) { + lp->stats.tx_aborted_errors++; + msg = "Late Collision."; + } + if (status & Tx_TxPar) { + lp->stats.tx_fifo_errors++; + msg = "Transmit Parity Error."; + } + if (status & Tx_SQErr) { + lp->stats.tx_heartbeat_errors++; + msg = "Signal Quality Error."; + } + if (msg) + printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status); +} + +static void +tc35815_txdone(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + struct TxFD *txfd; + unsigned int fdctl; + int num_done = 0; + + txfd = &lp->tfd_base[lp->tfd_end]; + while (lp->tfd_start != lp->tfd_end && + !((fdctl = le32_to_cpu(txfd->fd.FDCtl)) & FD_CownsFD)) { + int status = le32_to_cpu(txfd->fd.FDStat); + struct sk_buff *skb; + unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext); + + if (tc35815_debug > 2) { + printk("%s: complete TxFD.\n", dev->name); + dump_txfd(txfd); + } + tc35815_check_tx_stat(dev, status); + + skb = (struct sk_buff *)le32_to_cpu(txfd->fd.FDSystem); + if (skb) { + dev_kfree_skb_any(skb); + } + txfd->fd.FDSystem = cpu_to_le32(0); + + num_done++; + lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM; + txfd = &lp->tfd_base[lp->tfd_end]; + if ((fdnext & ~FD_Next_EOL) != virt_to_bus(txfd)) { + printk("%s: TxFD FDNext invalid.\n", dev->name); + panic_queues(dev); + } + if (fdnext & FD_Next_EOL) { + /* DMA Transmitter has been stopping... */ + if (lp->tfd_end != lp->tfd_start) { + int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM; + struct TxFD* txhead = &lp->tfd_base[head]; + int qlen = (lp->tfd_start + TX_FD_NUM + - lp->tfd_end) % TX_FD_NUM; + + if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) { + printk("%s: TxFD FDCtl invalid.\n", dev->name); + panic_queues(dev); + } + /* log max queue length */ + if (lp->lstats.max_tx_qlen < qlen) + lp->lstats.max_tx_qlen = qlen; + + + /* start DMA Transmitter again */ + txhead->fd.FDNext |= cpu_to_le32(FD_Next_EOL); +#ifdef GATHER_TXINT + txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); +#endif + if (tc35815_debug > 2) { + printk("%s: start TxFD on queue.\n", + dev->name); + dump_txfd(txfd); + } + tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr); + } + break; + } + } + + if (num_done > 0 && lp->tbusy) { + lp->tbusy = 0; + netif_start_queue(dev); + } +} + +/* The inverse routine to tc35815_open(). */ +static int +tc35815_close(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + + lp->tbusy = 1; + netif_stop_queue(dev); + + /* Flush the Tx and disable Rx here. */ + + tc35815_chip_reset(dev); + free_irq(dev->irq, dev); + + tc35815_free_queues(dev); + + MOD_DEC_USE_COUNT; + + return 0; +} + +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ +static struct net_device_stats *tc35815_get_stats(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + unsigned long flags; + + if (netif_running(dev)) { + save_and_cli(flags); + /* Update the statistics from the device registers. */ + lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt); + restore_flags(flags); + } + + return &lp->stats; +} + +static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned char *addr) +{ + int cam_index = index * 6; + unsigned long cam_data; + unsigned long saved_addr; + saved_addr = tc_readl(&tr->CAM_Adr); + + if (tc35815_debug > 1) { + int i; + printk(KERN_DEBUG "%s: CAM %d:", cardname, index); + for (i = 0; i < 6; i++) + printk(" %02x", addr[i]); + printk("\n"); + } + if (index & 1) { + /* read modify write */ + tc_writel(cam_index - 2, &tr->CAM_Adr); + cam_data = tc_readl(&tr->CAM_Data) & 0xffff0000; + cam_data |= addr[0] << 8 | addr[1]; + tc_writel(cam_data, &tr->CAM_Data); + /* write whole word */ + tc_writel(cam_index + 2, &tr->CAM_Adr); + cam_data = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5]; + tc_writel(cam_data, &tr->CAM_Data); + } else { + /* write whole word */ + tc_writel(cam_index, &tr->CAM_Adr); + cam_data = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; + tc_writel(cam_data, &tr->CAM_Data); + /* read modify write */ + tc_writel(cam_index + 4, &tr->CAM_Adr); + cam_data = tc_readl(&tr->CAM_Data) & 0x0000ffff; + cam_data |= addr[4] << 24 | (addr[5] << 16); + tc_writel(cam_data, &tr->CAM_Data); + } + + if (tc35815_debug > 2) { + int i; + for (i = cam_index / 4; i < cam_index / 4 + 2; i++) { + tc_writel(i * 4, &tr->CAM_Adr); + printk("CAM 0x%x: %08x", + i * 4, tc_readl(&tr->CAM_Data)); + } + } + tc_writel(saved_addr, &tr->CAM_Adr); +} + + +/* + * Set or clear the multicast filter for this adaptor. + * num_addrs == -1 Promiscuous mode, receive all packets + * num_addrs == 0 Normal mode, clear multicast list + * num_addrs > 0 Multicast mode, receive normal and MC packets, + * and do best-effort filtering. + */ +static void +tc35815_set_multicast_list(struct net_device *dev) +{ + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + + if (dev->flags&IFF_PROMISC) + { + /* Enable promiscuous mode */ + tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl); + } + else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > CAM_ENTRY_MAX - 3) + { + /* CAM 0, 1, 20 are reserved. */ + /* Disable promiscuous mode, use normal mode. */ + tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl); + } + else if(dev->mc_count) + { + struct dev_mc_list* cur_addr = dev->mc_list; + int i; + int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE); + + tc_writel(0, &tr->CAM_Ctl); + /* Walk the address list, and load the filter */ + for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) { + if (!cur_addr) + break; + /* entry 0,1 is reserved. */ + tc35815_set_cam_entry(tr, i + 2, cur_addr->dmi_addr); + ena_bits |= CAM_Ena_Bit(i + 2); + } + tc_writel(ena_bits, &tr->CAM_Ena); + tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl); + } + else { + tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena); + tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl); + } +} + +static unsigned long tc_phy_read(struct tc35815_regs *tr, int phy, int phy_reg) +{ + unsigned long data; + int flags; + save_and_cli(flags); + tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA); + while (tc_readl(&tr->MD_CA) & MD_CA_Busy) + ; + data = tc_readl(&tr->MD_Data); + restore_flags(flags); + return data; +} + +static void tc_phy_write(unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg) +{ + int flags; + save_and_cli(flags); + tc_writel(d, &tr->MD_Data); + tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA); + while (tc_readl(&tr->MD_CA) & MD_CA_Busy) + ; + restore_flags(flags); +} + +static void tc35815_phy_chip_init(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + static int first = 1; + unsigned short ctl; + + if (first) { + unsigned short id0, id1; + int count; + first = 0; + + /* first data written to the PHY will be an ID number */ + tc_phy_write(0, tr, 0, MII_CONTROL); /* ID:0 */ +#if 0 + tc_phy_write(MIICNTL_RESET, tr, 0, MII_CONTROL); + printk(KERN_INFO "%s: Resetting PHY...", dev->name); + while (tc_phy_read(tr, 0, MII_CONTROL) & MIICNTL_RESET) + ; + printk("\n"); + tc_phy_write(MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0, + MII_CONTROL); +#endif + id0 = tc_phy_read(tr, 0, MII_PHY_ID0); + id1 = tc_phy_read(tr, 0, MII_PHY_ID1); + printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name, + id0, id1); + if (lp->option & TC35815_OPT_10M) { + lp->linkspeed = 10; + lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0; + } else if (lp->option & TC35815_OPT_100M) { + lp->linkspeed = 100; + lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0; + } else { + /* auto negotiation */ + unsigned long neg_result; + tc_phy_write(MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL); + printk(KERN_INFO "%s: Auto Negotiation...", dev->name); + count = 0; + while (!(tc_phy_read(tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) { + if (count++ > 5000) { + printk(" failed. Assume 10Mbps\n"); + lp->linkspeed = 10; + lp->fullduplex = 0; + goto done; + } + if (count % 512 == 0) + printk("."); + mdelay(1); + } + printk(" done.\n"); + neg_result = tc_phy_read(tr, 0, MII_ANLPAR); + if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX)) + lp->linkspeed = 100; + else + lp->linkspeed = 10; + if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX)) + lp->fullduplex = 1; + else + lp->fullduplex = 0; + done: + ; + } + } + + ctl = 0; + if (lp->linkspeed == 100) + ctl |= MIICNTL_SPEED; + if (lp->fullduplex) + ctl |= MIICNTL_FDX; + tc_phy_write(ctl, tr, 0, MII_CONTROL); + + if (lp->fullduplex) { + tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl); + } +} + +static void tc35815_chip_reset(struct net_device *dev) +{ + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + + /* reset the controller */ + tc_writel(MAC_Reset, &tr->MAC_Ctl); + while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) + ; + + tc_writel(0, &tr->MAC_Ctl); + + /* initialize registers to default value */ + tc_writel(0, &tr->DMA_Ctl); + tc_writel(0, &tr->TxThrsh); + tc_writel(0, &tr->TxPollCtr); + tc_writel(0, &tr->RxFragSize); + tc_writel(0, &tr->Int_En); + tc_writel(0, &tr->FDA_Bas); + tc_writel(0, &tr->FDA_Lim); + tc_writel(0xffffffff, &tr->Int_Src); /* Write 1 to clear */ + tc_writel(0, &tr->CAM_Ctl); + tc_writel(0, &tr->Tx_Ctl); + tc_writel(0, &tr->Rx_Ctl); + tc_writel(0, &tr->CAM_Ena); + (void)tc_readl(&tr->Miss_Cnt); /* Read to clear */ + +} + +static void tc35815_chip_init(struct net_device *dev) +{ + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + int flags; + unsigned long txctl = TX_CTL_CMD; + + tc35815_phy_chip_init(dev); + + /* load station address to CAM */ + tc35815_set_cam_entry(tr, CAM_ENTRY_SOURCE, dev->dev_addr); + + /* Enable CAM (broadcast and unicast) */ + tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena); + tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl); + + save_and_cli(flags); + + tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl); + + tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize); /* Packing */ + tc_writel(0, &tr->TxPollCtr); /* Batch mode */ + tc_writel(TX_THRESHOLD, &tr->TxThrsh); + tc_writel(INT_EN_CMD, &tr->Int_En); + + /* set queues */ + tc_writel(virt_to_bus(lp->rfd_base), &tr->FDA_Bas); + tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base, + &tr->FDA_Lim); + /* + * Activation method: + * First, enable eht MAC Transmitter and the DMA Receive circuits. + * Then enable the DMA Transmitter and the MAC Receive circuits. + */ + tc_writel(virt_to_bus(lp->fbl_ptr), &tr->BLFrmPtr); /* start DMA receiver */ + tc_writel(RX_CTL_CMD, &tr->Rx_Ctl); /* start MAC receiver */ + /* start MAC transmitter */ + /* WORKAROUND: ignore LostCrS in full duplex operation */ + if (lp->fullduplex) + txctl = TX_CTL_CMD & ~Tx_EnLCarr; +#ifdef GATHER_TXINT + txctl &= ~Tx_EnComp; /* disable global tx completion int. */ +#endif + tc_writel(txctl, &tr->Tx_Ctl); +#if 0 /* No need to polling */ + tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr); /* start DMA transmitter */ +#endif + restore_flags(flags); +} + +static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +{ + int len = 0; + off_t pos = 0; + off_t begin = 0; + struct net_device *dev; + + len += sprintf(buffer, "TC35815 statistics:\n"); + for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) { + struct tc35815_local *lp = (struct tc35815_local *)dev->priv; + len += sprintf(buffer + len, + "%s: tx_ints %d, rx_ints %d, max_tx_qlen %d\n", + dev->name, + lp->lstats.tx_ints, + lp->lstats.rx_ints, + lp->lstats.max_tx_qlen); + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + + if (pos > offset+length) break; + } + + *start = buffer + (offset - begin); + len -= (offset - begin); + + if (len > length) len = length; + + return len; +} + +/* XXX */ +void +tc35815_killall(void) +{ + struct net_device *dev; + + for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) { + if (dev->flags&IFF_UP){ + dev->stop(dev); + } + } +} + +static struct pci_driver tc35815_driver = { + name: TC35815_MODULE_NAME, + probe: tc35815_probe, + remove: NULL, + id_table: tc35815_pci_tbl, +}; + +static int __init tc35815_init_module(void) +{ + int err; + + if ((err = pci_module_init(&tc35815_driver)) < 0 ) + return err; + else + return 0; +} + +static void __exit tc35815_cleanup_module(void) +{ + struct net_device *next_dev; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_tc35815_dev) { + struct net_device *dev = root_tc35815_dev; + next_dev = ((struct tc35815_local *)dev->priv)->next_module; + kfree(dev->priv); + iounmap((void *)(dev->base_addr)); + unregister_netdev(dev); + kfree(dev); + root_tc35815_dev = next_dev; + } +} +module_init(tc35815_init_module); +module_exit(tc35815_cleanup_module); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tlan.c linux-2.5/drivers/net/tlan.c --- linux-2.5.5/drivers/net/tlan.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/net/tlan.c Mon Feb 18 22:06:19 2002 @@ -160,7 +160,10 @@ * *******************************************************************************/ +#include // nuke me later +#ifdef CONFIG_DEBUG_OBSOLETE #error Please convert me to Documentation/DMA-mapping.txt +#endif #include @@ -431,7 +434,7 @@ name: "tlan", id_table: tlan_pci_tbl, probe: tlan_init_one, - remove: tlan_remove_one, + remove: __devexit_p(tlan_remove_one), }; static int __init tlan_probe(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tokenring/3c359.c linux-2.5/drivers/net/tokenring/3c359.c --- linux-2.5.5/drivers/net/tokenring/3c359.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/tokenring/3c359.c Tue Feb 26 21:24:49 2002 @@ -0,0 +1,1816 @@ +/* + * 3c359.c (c) 2000 Mike Phillips (mikep@linuxtr.net) All Rights Reserved + * + * Linux driver for 3Com 3c359 Tokenlink Velocity XL PCI NIC + * + * Base Driver Olympic: + * Written 1999 Peter De Schrijver & Mike Phillips + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * 7/17/00 - Clean up, version number 0.9.0. Ready to release to the world. + * + * 2/16/01 - Port up to kernel 2.4.2 ready for submission into the kernel. + * 3/05/01 - Last clean up stuff before submission. + * 2/15/01 - Finally, update to new pci api. + * + * To Do: + */ + +/* + * Technical Card Details + * + * All access to data is done with 16/8 bit transfers. The transfer + * method really sucks. You can only read or write one location at a time. + * + * Also, the microcode for the card must be uploaded if the card does not have + * the flashrom on board. This is a 28K bloat in the driver when compiled + * as a module. + * + * Rx is very simple, status into a ring of descriptors, dma data transfer, + * interrupts to tell us when a packet is received. + * + * Tx is a little more interesting. Similar scenario, descriptor and dma data + * transfers, but we don't have to interrupt the card to tell it another packet + * is ready for transmission, we are just doing simple memory writes, not io or mmio + * writes. The card can be set up to simply poll on the next + * descriptor pointer and when this value is non-zero will automatically download + * the next packet. The card then interrupts us when the packet is done. + * + */ + +#define XL_DEBUG 0 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "3c359.h" + +static char version[] __devinitdata = +"3c359.c v1.2.0 2/17/01 - Mike Phillips (mikep@linuxtr.net)" ; + +MODULE_AUTHOR("Mike Phillips ") ; +MODULE_DESCRIPTION("3Com 3C359 Velocity XL Token Ring Adapter Driver \n") ; + +/* Module paramters */ + +/* Ring Speed 0,4,16 + * 0 = Autosense + * 4,16 = Selected speed only, no autosense + * This allows the card to be the first on the ring + * and become the active monitor. + * + * WARNING: Some hubs will allow you to insert + * at the wrong speed. + * + * The adapter will _not_ fail to open if there are no + * active monitors on the ring, it will simply open up in + * its last known ringspeed if no ringspeed is specified. + */ + +static int ringspeed[XL_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(ringspeed, "1-" __MODULE_STRING(XL_MAX_ADAPTERS) "i"); +MODULE_PARM_DESC(ringspeed,"3c359: Ringspeed selection - 4,16 or 0") ; + +/* Packet buffer size */ + +static int pkt_buf_sz[XL_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(pkt_buf_sz, "1-" __MODULE_STRING(XL_MAX_ADAPTERS) "i") ; +MODULE_PARM_DESC(pkt_buf_sz,"3c359: Initial buffer size") ; +/* Message Level */ + +static int message_level[XL_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(message_level, "1-" __MODULE_STRING(XL_MAX_ADAPTERS) "i") ; +MODULE_PARM_DESC(message_level, "3c359: Level of reported messages \n") ; +/* + * This is a real nasty way of doing this, but otherwise you + * will be stuck with 1555 lines of hex #'s in the code. + */ + +#include "3c359_microcode.h" + +static struct pci_device_id xl_pci_tbl[] __devinitdata = +{ + {PCI_VENDOR_ID_3COM,PCI_DEVICE_ID_3COM_3C359, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci,xl_pci_tbl) ; + +static int xl_init(struct net_device *dev); +static int xl_open(struct net_device *dev); +static int xl_open_hw(struct net_device *dev) ; +static int xl_hw_reset(struct net_device *dev); +static int xl_xmit(struct sk_buff *skb, struct net_device *dev); +static void xl_dn_comp(struct net_device *dev); +static int xl_close(struct net_device *dev); +static void xl_set_rx_mode(struct net_device *dev); +static void xl_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct net_device_stats * xl_get_stats(struct net_device *dev); +static int xl_set_mac_address(struct net_device *dev, void *addr) ; +static void xl_arb_cmd(struct net_device *dev); +static void xl_asb_cmd(struct net_device *dev) ; +static void xl_srb_cmd(struct net_device *dev, int srb_cmd) ; +static void xl_wait_misr_flags(struct net_device *dev) ; +static int xl_change_mtu(struct net_device *dev, int mtu); +static void xl_srb_bh(struct net_device *dev) ; +static void xl_asb_bh(struct net_device *dev) ; +static void xl_reset(struct net_device *dev) ; +static void xl_freemem(struct net_device *dev) ; + + +/* EEProm Access Functions */ +static u16 xl_ee_read(struct net_device *dev, int ee_addr) ; +static void xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value) ; + +/* Debugging functions */ +#if XL_DEBUG +static void print_tx_state(struct net_device *dev) ; +static void print_rx_state(struct net_device *dev) ; + +static void print_tx_state(struct net_device *dev) +{ + + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_tx_desc *txd ; + u8 *xl_mmio = xl_priv->xl_mmio ; + int i ; + + printk("tx_ring_head: %d, tx_ring_tail: %d, free_ent: %d \n",xl_priv->tx_ring_head, + xl_priv->tx_ring_tail, xl_priv->free_ring_entries) ; + printk("Ring , Address , FSH , DnNextPtr, Buffer, Buffer_Len \n"); + for (i = 0; i < 16; i++) { + txd = &(xl_priv->xl_tx_ring[i]) ; + printk("%d, %08lx, %08x, %08x, %08x, %08x \n", i, virt_to_bus(txd), + txd->framestartheader, txd->dnnextptr, txd->buffer, txd->buffer_length ) ; + } + + printk("DNLISTPTR = %04x \n", readl(xl_mmio + MMIO_DNLISTPTR) ); + + printk("DmaCtl = %04x \n", readl(xl_mmio + MMIO_DMA_CTRL) ); + printk("Queue status = %0x \n",netif_running(dev) ) ; +} + +static void print_rx_state(struct net_device *dev) +{ + + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + struct xl_rx_desc *rxd ; + u8 *xl_mmio = xl_priv->xl_mmio ; + int i ; + + printk("rx_ring_tail: %d \n", xl_priv->rx_ring_tail) ; + printk("Ring , Address , FrameState , UPNextPtr, FragAddr, Frag_Len \n"); + for (i = 0; i < 16; i++) { + /* rxd = (struct xl_rx_desc *)xl_priv->rx_ring_dma_addr + (i * sizeof(struct xl_rx_desc)) ; */ + rxd = &(xl_priv->xl_rx_ring[i]) ; + printk("%d, %08lx, %08x, %08x, %08x, %08x \n", i, virt_to_bus(rxd), + rxd->framestatus, rxd->upnextptr, rxd->upfragaddr, rxd->upfraglen ) ; + } + + printk("UPLISTPTR = %04x \n", readl(xl_mmio + MMIO_UPLISTPTR) ); + + printk("DmaCtl = %04x \n", readl(xl_mmio + MMIO_DMA_CTRL) ); + printk("Queue status = %0x \n",netif_running(dev) ) ; +} +#endif + +/* + * Read values from the on-board EEProm. This looks very strange + * but you have to wait for the EEProm to get/set the value before + * passing/getting the next value from the nic. As with all requests + * on this nic it has to be done in two stages, a) tell the nic which + * memory address you want to access and b) pass/get the value from the nic. + * With the EEProm, you have to wait before and inbetween access a) and b). + * As this is only read at initialization time and the wait period is very + * small we shouldn't have to worry about scheduling issues. + */ + +static u16 xl_ee_read(struct net_device *dev, int ee_addr) +{ + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + u8 *xl_mmio = xl_priv->xl_mmio ; + + /* Wait for EEProm to not be busy */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + /* Tell EEProm what we want to do and where */ + writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(EEREAD + ee_addr, xl_mmio + MMIO_MACDATA) ; + + /* Wait for EEProm to not be busy */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + /* Tell EEProm what we want to do and where */ + writel(IO_WORD_WRITE | EECONTROL , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(EEREAD + ee_addr, xl_mmio + MMIO_MACDATA) ; + + /* Finally read the value from the EEProm */ + writel(IO_WORD_READ | EEDATA , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + return readw(xl_mmio + MMIO_MACDATA) ; +} + +/* + * Write values to the onboard eeprom. As with eeprom read you need to + * set which location to write, wait, value to write, wait, with the + * added twist of having to enable eeprom writes as well. + */ + +static void xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value) +{ + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + u8 *xl_mmio = xl_priv->xl_mmio ; + + /* Wait for EEProm to not be busy */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + /* Enable write/erase */ + writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(EE_ENABLE_WRITE, xl_mmio + MMIO_MACDATA) ; + + /* Wait for EEProm to not be busy */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + /* Put the value we want to write into EEDATA */ + writel(IO_WORD_WRITE | EEDATA, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(ee_value, xl_mmio + MMIO_MACDATA) ; + + /* Tell EEProm to write eevalue into ee_addr */ + writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(EEWRITE + ee_addr, xl_mmio + MMIO_MACDATA) ; + + /* Wait for EEProm to not be busy, to ensure write gets done */ + writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; + + return ; +} + +int __devinit xl_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *dev ; + struct xl_private *xl_priv ; + static int card_no = -1 ; + int i ; + + card_no++ ; + + if (pci_enable_device(pdev)) { + return -ENODEV ; + } + + pci_set_master(pdev); + + if ((i = pci_request_regions(pdev,"3c359"))) { + return i ; + } ; + + /* + * Allowing init_trdev to allocate the dev->priv structure will align xl_private + * on a 32 bytes boundary which we need for the rx/tx descriptors + */ + + dev = alloc_trdev(sizeof(struct xl_private)) ; + if (!dev) { + pci_release_regions(pdev) ; + return -ENOMEM ; + } + xl_priv = dev->priv ; + +#if XL_DEBUG + printk("pci_device: %p, dev:%p, dev->priv: %p, ba[0]: %10x, ba[1]:%10x\n", + pdev, dev, dev->priv, (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start) ; +#endif + + dev->irq=pdev->irq; + dev->base_addr=pci_resource_start(pdev,0) ; + dev->init=NULL ; /* Must be null with new api, otherwise get called twice */ + xl_priv->xl_card_name = (char *)pdev->name ; + xl_priv->xl_mmio=ioremap(pci_resource_start(pdev,1), XL_IO_SPACE); + xl_priv->pdev = pdev ; + + if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) ) + xl_priv->pkt_buf_sz = PKT_BUF_SZ ; + else + xl_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; + + dev->mtu = xl_priv->pkt_buf_sz - TR_HLEN ; + xl_priv->xl_ring_speed = ringspeed[card_no] ; + xl_priv->xl_message_level = message_level[card_no] ; + xl_priv->xl_functional_addr[0] = xl_priv->xl_functional_addr[1] = xl_priv->xl_functional_addr[2] = xl_priv->xl_functional_addr[3] = 0 ; + xl_priv->xl_copy_all_options = 0 ; + + if((i = xl_init(dev))) { + iounmap(xl_priv->xl_mmio) ; + kfree(dev) ; + pci_release_regions(pdev) ; + return i ; + } + + dev->open=&xl_open; + dev->hard_start_xmit=&xl_xmit; + dev->change_mtu=&xl_change_mtu; + dev->stop=&xl_close; + dev->do_ioctl=NULL; + dev->set_multicast_list=&xl_set_rx_mode; + dev->get_stats=&xl_get_stats ; + dev->set_mac_address=&xl_set_mac_address ; + SET_MODULE_OWNER(dev); + + pci_set_drvdata(pdev,dev) ; + if ((i = register_netdev(dev))) { + printk(KERN_ERR "3C359, register netdev failed\n") ; + pci_set_drvdata(pdev,NULL) ; + iounmap(xl_priv->xl_mmio) ; + kfree(dev) ; + pci_release_regions(pdev) ; + return i ; + } + + printk(KERN_INFO "3C359: %s registered as: %s\n",xl_priv->xl_card_name,dev->name) ; + + return 0; +} + + +static int __init xl_init(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + + printk(KERN_INFO "%s \n", version); + printk(KERN_INFO "%s: I/O at %hx, MMIO at %p, using irq %d\n", + xl_priv->xl_card_name, (unsigned int)dev->base_addr ,xl_priv->xl_mmio, dev->irq); + + spin_lock_init(&xl_priv->xl_lock) ; + + return xl_hw_reset(dev) ; + +} + + +/* + * Hardware reset. This needs to be a separate entity as we need to reset the card + * when we change the EEProm settings. + */ + +static int xl_hw_reset(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + u8 *xl_mmio = xl_priv->xl_mmio ; + unsigned long t ; + u16 i ; + u16 result_16 ; + u8 result_8 ; + u16 start ; + int j ; + + /* + * Reset the card. If the card has got the microcode on board, we have + * missed the initialization interrupt, so we must always do this. + */ + + writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; + + /* + * Must wait for cmdInProgress bit (12) to clear before continuing with + * card configuration. + */ + + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 40*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL card not responding to global reset.\n", dev->name); + return -ENODEV; + } + } + + /* + * Enable pmbar by setting bit in CPAttention + */ + + writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + result_8 = readb(xl_mmio + MMIO_MACDATA) ; + result_8 = result_8 | CPA_PMBARVIS ; + writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(result_8, xl_mmio + MMIO_MACDATA) ; + + /* + * Read cpHold bit in pmbar, if cleared we have got Flashrom on board. + * If not, we need to upload the microcode to the card + */ + + writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD); + +#if XL_DEBUG + printk(KERN_INFO "Read from PMBAR = %04x \n", readw(xl_mmio + MMIO_MACDATA)) ; +#endif + + if ( readw( (xl_mmio + MMIO_MACDATA)) & PMB_CPHOLD ) { + + /* Set PmBar, privateMemoryBase bits (8:2) to 0 */ + + writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD); + result_16 = readw(xl_mmio + MMIO_MACDATA) ; + result_16 = result_16 & ~((0x7F) << 2) ; + writel( (IO_WORD_WRITE | PMBAR), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(result_16,xl_mmio + MMIO_MACDATA) ; + + /* Set CPAttention, memWrEn bit */ + + writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + result_8 = readb(xl_mmio + MMIO_MACDATA) ; + result_8 = result_8 | CPA_MEMWREN ; + writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(result_8, xl_mmio + MMIO_MACDATA) ; + + /* + * Now to write the microcode into the shared ram + * The microcode must finish at position 0xFFFF, so we must subtract + * to get the start position for the code + */ + + start = (0xFFFF - (mc_size) + 1 ) ; /* Looks strange but ensures compiler only uses 16 bit unsigned int for this */ + + printk(KERN_INFO "3C359: Uploading Microcode: "); + + for (i = start,j=0; (j < mc_size && i <= 0xffff) ; i++,j++) { + writel(MEM_BYTE_WRITE | 0XD0000 | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(microcode[j],xl_mmio + MMIO_MACDATA) ; + if (j % 1024 == 0) + printk("."); + } + printk("\n") ; + + for (i=0;i < 16; i++) { + writel( (MEM_BYTE_WRITE | 0xDFFF0) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(microcode[mc_size - 16 + i], xl_mmio + MMIO_MACDATA) ; + } + + /* + * Have to write the start address of the upload to FFF4, but + * the address must be >> 4. You do not want to know how long + * it took me to discover this. + */ + + writel(MEM_WORD_WRITE | 0xDFFF4, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(start >> 4, xl_mmio + MMIO_MACDATA); + + /* Clear the CPAttention, memWrEn Bit */ + + writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + result_8 = readb(xl_mmio + MMIO_MACDATA) ; + result_8 = result_8 & ~CPA_MEMWREN ; + writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(result_8, xl_mmio + MMIO_MACDATA) ; + + /* Clear the cpHold bit in pmbar */ + + writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD); + result_16 = readw(xl_mmio + MMIO_MACDATA) ; + result_16 = result_16 & ~PMB_CPHOLD ; + writel( (IO_WORD_WRITE | PMBAR), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(result_16,xl_mmio + MMIO_MACDATA) ; + + + } /* If microcode upload required */ + + /* + * The card should now go though a self test procedure and get itself ready + * to be opened, we must wait for an srb response with the initialization + * information. + */ + +#if XL_DEBUG + printk(KERN_INFO "%s: Microcode uploaded, must wait for the self test to complete\n", dev->name); +#endif + + writew(SETINDENABLE | 0xFFF, xl_mmio + MMIO_COMMAND) ; + + t=jiffies; + while ( !(readw(xl_mmio + MMIO_INTSTATUS_AUTO) & INTSTAT_SRB) ) { + schedule(); + if(jiffies-t > 15*HZ) { + printk(KERN_ERR "3COM 3C359 Velocity XL card not responding.\n"); + return -ENODEV; + } + } + + /* + * Write the RxBufArea with D000, RxEarlyThresh, TxStartThresh, + * DnPriReqThresh, read the tech docs if you want to know what + * values they need to be. + */ + + writel(MMIO_WORD_WRITE | RXBUFAREA, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(0xD000, xl_mmio + MMIO_MACDATA) ; + + writel(MMIO_WORD_WRITE | RXEARLYTHRESH, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(0X0020, xl_mmio + MMIO_MACDATA) ; + + writew( SETTXSTARTTHRESH | 0x40 , xl_mmio + MMIO_COMMAND) ; + + writeb(0x04, xl_mmio + MMIO_DNBURSTTHRESH) ; + writeb(0x04, xl_mmio + DNPRIREQTHRESH) ; + + /* + * Read WRBR to provide the location of the srb block, have to use byte reads not word reads. + * Tech docs have this wrong !!!! + */ + + writel(MMIO_BYTE_READ | WRBR, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->srb = readb(xl_mmio + MMIO_MACDATA) << 8 ; + writel( (MMIO_BYTE_READ | WRBR) + 1, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->srb = xl_priv->srb | readb(xl_mmio + MMIO_MACDATA) ; + +#if XL_DEBUG + writel(IO_WORD_READ | SWITCHSETTINGS, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if ( readw(xl_mmio + MMIO_MACDATA) & 2) { + printk(KERN_INFO "Default ring speed 4 mbps \n") ; + } else { + printk(KERN_INFO "Default ring speed 16 mbps \n") ; + } + printk(KERN_INFO "%s: xl_priv->srb = %04x\n",xl_priv->xl_card_name, xl_priv->srb); +#endif + + return 0; +} + +static int xl_open(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + u8 i ; + u16 hwaddr[3] ; /* Should be u8[6] but we get word return values */ + int open_err ; + + u16 switchsettings, switchsettings_eeprom ; + + if(request_irq(dev->irq, &xl_interrupt, SA_SHIRQ , "3c359", dev)) { + return -EAGAIN; + } + + /* + * Read the information from the EEPROM that we need. I know we + * should use ntohs, but the word gets stored reversed in the 16 + * bit field anyway and it all works its self out when we memcpy + * it into dev->dev_addr. + */ + + hwaddr[0] = xl_ee_read(dev,0x10) ; + hwaddr[1] = xl_ee_read(dev,0x11) ; + hwaddr[2] = xl_ee_read(dev,0x12) ; + + /* Ring speed */ + + switchsettings_eeprom = xl_ee_read(dev,0x08) ; + switchsettings = switchsettings_eeprom ; + + if (xl_priv->xl_ring_speed != 0) { + if (xl_priv->xl_ring_speed == 4) + switchsettings = switchsettings | 0x02 ; + else + switchsettings = switchsettings & ~0x02 ; + } + + /* Only write EEProm if there has been a change */ + if (switchsettings != switchsettings_eeprom) { + xl_ee_write(dev,0x08,switchsettings) ; + /* Hardware reset after changing EEProm */ + xl_hw_reset(dev) ; + } + + memcpy(dev->dev_addr,hwaddr,dev->addr_len) ; + + open_err = xl_open_hw(dev) ; + + /* + * This really needs to be cleaned up with better error reporting. + */ + + if (open_err != 0) { /* Something went wrong with the open command */ + if (open_err & 0x07) { /* Wrong speed, retry at different speed */ + printk(KERN_WARNING "%s: Open Error, retrying at different ringspeed \n", dev->name) ; + switchsettings = switchsettings ^ 2 ; + xl_ee_write(dev,0x08,switchsettings) ; + xl_hw_reset(dev) ; + open_err = xl_open_hw(dev) ; + if (open_err != 0) { + printk(KERN_WARNING "%s: Open error returned a second time, we're bombing out now\n", dev->name); + free_irq(dev->irq,dev) ; + return -ENODEV ; + } + } else { + printk(KERN_WARNING "%s: Open Error = %04x\n", dev->name, open_err) ; + free_irq(dev->irq,dev) ; + return -ENODEV ; + } + } + + /* + * Now to set up the Rx and Tx buffer structures + */ + /* These MUST be on 8 byte boundaries */ + xl_priv->xl_tx_ring = kmalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL) ; + xl_priv->xl_rx_ring = kmalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL) ; + memset(xl_priv->xl_tx_ring,0,sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) ; + memset(xl_priv->xl_rx_ring,0,sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) ; + + /* Setup Rx Ring */ + for (i=0 ; i < XL_RX_RING_SIZE ; i++) { + struct sk_buff *skb ; + + skb = dev_alloc_skb(xl_priv->pkt_buf_sz) ; + if (skb==NULL) + break ; + + skb->dev = dev ; + xl_priv->xl_rx_ring[i].upfragaddr = pci_map_single(xl_priv->pdev, skb->data,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE) ; + xl_priv->xl_rx_ring[i].upfraglen = xl_priv->pkt_buf_sz | RXUPLASTFRAG; + xl_priv->rx_ring_skb[i] = skb ; + } + + if (i==0) { + printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled \n",dev->name) ; + free_irq(dev->irq,dev) ; + return -EIO ; + } + + xl_priv->rx_ring_no = i ; + xl_priv->rx_ring_tail = 0 ; + xl_priv->rx_ring_dma_addr = pci_map_single(xl_priv->pdev,xl_priv->xl_rx_ring, sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE, PCI_DMA_TODEVICE) ; + for (i=0;i<(xl_priv->rx_ring_no-1);i++) { + xl_priv->xl_rx_ring[i].upnextptr = xl_priv->rx_ring_dma_addr + (sizeof (struct xl_rx_desc) * (i+1)) ; + } + xl_priv->xl_rx_ring[i].upnextptr = 0 ; + + writel(xl_priv->rx_ring_dma_addr, xl_mmio + MMIO_UPLISTPTR) ; + + /* Setup Tx Ring */ + + xl_priv->tx_ring_dma_addr = pci_map_single(xl_priv->pdev,xl_priv->xl_tx_ring, sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE,PCI_DMA_TODEVICE) ; + + xl_priv->tx_ring_head = 1 ; + xl_priv->tx_ring_tail = 255 ; /* Special marker for first packet */ + xl_priv->free_ring_entries = XL_TX_RING_SIZE ; + + /* + * Setup the first dummy DPD entry for polling to start working. + */ + + xl_priv->xl_tx_ring[0].framestartheader = TXDPDEMPTY ; + xl_priv->xl_tx_ring[0].buffer = 0 ; + xl_priv->xl_tx_ring[0].buffer_length = 0 ; + xl_priv->xl_tx_ring[0].dnnextptr = 0 ; + + writel(xl_priv->tx_ring_dma_addr, xl_mmio + MMIO_DNLISTPTR) ; + writel(DNUNSTALL, xl_mmio + MMIO_COMMAND) ; + writel(UPUNSTALL, xl_mmio + MMIO_COMMAND) ; + writel(DNENABLE, xl_mmio + MMIO_COMMAND) ; + writeb(0x40, xl_mmio + MMIO_DNPOLL) ; + + /* + * Enable interrupts on the card + */ + + writel(SETINTENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; + writel(SETINDENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; + + netif_start_queue(dev) ; + return 0; + +} + +static int xl_open_hw(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + u16 vsoff ; + char ver_str[33]; + int open_err ; + int i ; + unsigned long t ; + + /* + * Okay, let's build up the Open.NIC srb command + * + */ + + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(OPEN_NIC, xl_mmio + MMIO_MACDATA) ; + + /* + * Use this as a test byte, if it comes back with the same value, the command didn't work + */ + + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb)+ 2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0xff,xl_mmio + MMIO_MACDATA) ; + + /* Open options */ + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + 8, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x00, xl_mmio + MMIO_MACDATA) ; + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + 9, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x00, xl_mmio + MMIO_MACDATA) ; + + /* + * Node address, be careful here, the docs say you can just put zeros here and it will use + * the hardware address, it doesn't, you must include the node address in the open command. + */ + + if (xl_priv->xl_laa[0]) { /* If using a LAA address */ + for (i=10;i<16;i++) { + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_laa[i],xl_mmio + MMIO_MACDATA) ; + } + memcpy(dev->dev_addr,xl_priv->xl_laa,dev->addr_len) ; + } else { /* Regular hardware address */ + for (i=10;i<16;i++) { + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(dev->dev_addr[i-10], xl_mmio + MMIO_MACDATA) ; + } + } + + /* Default everything else to 0 */ + for (i = 16; i < 34; i++) { + writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x00,xl_mmio + MMIO_MACDATA) ; + } + + /* + * Set the csrb bit in the MISR register + */ + + xl_wait_misr_flags(dev) ; + writel(MEM_BYTE_WRITE | MF_CSRB, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0xFF, xl_mmio + MMIO_MACDATA) ; + writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(MISR_CSRB , xl_mmio + MMIO_MACDATA) ; + + /* + * Now wait for the command to run + */ + + t=jiffies; + while (! (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_SRB)) { + schedule(); + if(jiffies-t > 40*HZ) { + printk(KERN_ERR "3COM 3C359 Velocity XL card not responding.\n"); + break ; + } + } + + /* + * Let's interpret the open response + */ + + writel( (MEM_BYTE_READ | 0xD0000 | xl_priv->srb)+2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if (readb(xl_mmio + MMIO_MACDATA)!=0) { + open_err = readb(xl_mmio + MMIO_MACDATA) << 8 ; + writel( (MEM_BYTE_READ | 0xD0000 | xl_priv->srb) + 7, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + open_err |= readb(xl_mmio + MMIO_MACDATA) ; + return open_err ; + } else { + writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 8, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->asb = ntohs(readw(xl_mmio + MMIO_MACDATA)) ; + printk(KERN_INFO "%s: Adapter Opened Details: ",dev->name) ; + printk("ASB: %04x",xl_priv->asb ) ; + writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 10, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + printk(", SRB: %04x",ntohs(readw(xl_mmio + MMIO_MACDATA)) ) ; + + writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 12, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->arb = ntohs(readw(xl_mmio + MMIO_MACDATA)) ; + printk(", ARB: %04x \n",xl_priv->arb ) ; + writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 14, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + vsoff = ntohs(readw(xl_mmio + MMIO_MACDATA)) ; + + /* + * Interesting, sending the individual characters directly to printk was causing klogd to use + * use 100% of processor time, so we build up the string and print that instead. + */ + + for (i=0;i<0x20;i++) { + writel( (MEM_BYTE_READ | 0xD0000 | vsoff) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + ver_str[i] = readb(xl_mmio + MMIO_MACDATA) ; + } + ver_str[i] = '\0' ; + printk(KERN_INFO "%s: Microcode version String: %s \n",dev->name,ver_str); + } + + /* + * Issue the AckInterrupt + */ + writew(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + + return 0 ; +} + +/* + * There are two ways of implementing rx on the 359 NIC, either + * interrupt driven or polling. We are going to uses interrupts, + * it is the easier way of doing things. + * + * The Rx works with a ring of Rx descriptors. At initialise time the ring + * entries point to the next entry except for the last entry in the ring + * which points to 0. The card is programmed with the location of the first + * available descriptor and keeps reading the next_ptr until next_ptr is set + * to 0. Hopefully with a ring size of 16 the card will never get to read a next_ptr + * of 0. As the Rx interrupt is received we copy the frame up to the protocol layers + * and then point the end of the ring to our current position and point our current + * position to 0, therefore making the current position the last position on the ring. + * The last position on the ring therefore loops continually loops around the rx ring. + * + * rx_ring_tail is the position on the ring to process next. (Think of a snake, the head + * expands as the card adds new packets and we go around eating the tail processing the + * packets.) + * + * Undoubtably it could be streamlined and improved upon, but at the moment it works + * and the fast path through the routine is fine. + * + * adv_rx_ring could be inlined to increase performance, but its called a *lot* of times + * in xl_rx so would increase the size of the function significantly. + */ + +static void adv_rx_ring(struct net_device *dev) /* Advance rx_ring, cut down on bloat in xl_rx */ +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + int prev_ring_loc ; + + prev_ring_loc = (xl_priv->rx_ring_tail + XL_RX_RING_SIZE - 1) & (XL_RX_RING_SIZE - 1); + xl_priv->xl_rx_ring[prev_ring_loc].upnextptr = xl_priv->rx_ring_dma_addr + (sizeof (struct xl_rx_desc) * xl_priv->rx_ring_tail) ; + xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus = 0 ; + xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upnextptr = 0 ; + xl_priv->rx_ring_tail++ ; + xl_priv->rx_ring_tail &= (XL_RX_RING_SIZE-1) ; + + return ; +} + +static void xl_rx(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + struct sk_buff *skb, *skb2 ; + int frame_length = 0, copy_len = 0 ; + int temp_ring_loc ; + + /* + * Receive the next frame, loop around the ring until all frames + * have been received. + */ + + while (xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus & (RXUPDCOMPLETE | RXUPDFULL) ) { /* Descriptor to process */ + + if (xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus & RXUPDFULL ) { /* UpdFull, Multiple Descriptors used for the frame */ + + /* + * This is a pain, you need to go through all the descriptors until the last one + * for this frame to find the framelength + */ + + temp_ring_loc = xl_priv->rx_ring_tail ; + + while (xl_priv->xl_rx_ring[temp_ring_loc].framestatus & RXUPDFULL ) { + temp_ring_loc++ ; + temp_ring_loc &= (XL_RX_RING_SIZE-1) ; + } + + frame_length = xl_priv->xl_rx_ring[temp_ring_loc].framestatus & 0x7FFF ; + + skb = dev_alloc_skb(frame_length) ; + + if (skb==NULL) { /* No memory for frame, still need to roll forward the rx ring */ + printk(KERN_WARNING "%s: dev_alloc_skb failed - multi buffer !\n", dev->name) ; + while (xl_priv->rx_ring_tail != temp_ring_loc) + adv_rx_ring(dev) ; + + adv_rx_ring(dev) ; /* One more time just for luck :) */ + xl_priv->xl_stats.rx_dropped++ ; + + writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; + return ; + } + + skb->dev = dev ; + + while (xl_priv->rx_ring_tail != temp_ring_loc) { + copy_len = xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen & 0x7FFF ; + frame_length -= copy_len ; + pci_dma_sync_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; + memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, copy_len) ; + adv_rx_ring(dev) ; + } + + /* Now we have found the last fragment */ + pci_dma_sync_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; + memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, frame_length) ; +/* memcpy(skb_put(skb,frame_length), bus_to_virt(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr), frame_length) ; */ + adv_rx_ring(dev) ; + skb->protocol = tr_type_trans(skb,dev) ; + netif_rx(skb) ; + + } else { /* Single Descriptor Used, simply swap buffers over, fast path */ + + frame_length = xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus & 0x7FFF ; + + skb = dev_alloc_skb(xl_priv->pkt_buf_sz) ; + + if (skb==NULL) { /* Still need to fix the rx ring */ + printk(KERN_WARNING "%s: dev_alloc_skb failed in rx, single buffer \n",dev->name) ; + adv_rx_ring(dev) ; + xl_priv->xl_stats.rx_dropped++ ; + writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; + return ; + } + + skb->dev = dev ; + + skb2 = xl_priv->rx_ring_skb[xl_priv->rx_ring_tail] ; + pci_unmap_single(xl_priv->pdev, xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr, xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; + skb_put(skb2, frame_length) ; + skb2->protocol = tr_type_trans(skb2,dev) ; + + xl_priv->rx_ring_skb[xl_priv->rx_ring_tail] = skb ; + xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr = pci_map_single(xl_priv->pdev,skb->data,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE) ; + xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen = xl_priv->pkt_buf_sz | RXUPLASTFRAG ; + adv_rx_ring(dev) ; + xl_priv->xl_stats.rx_packets++ ; + xl_priv->xl_stats.rx_bytes += frame_length ; + + netif_rx(skb2) ; + } /* if multiple buffers */ + dev->last_rx = jiffies ; + } /* while packet to do */ + + /* Clear the updComplete interrupt */ + writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; + return ; +} + +/* + * This is ruthless, it doesn't care what state the card is in it will + * completely reset the adapter. + */ + +static void xl_reset(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + unsigned long t; + + writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; + + /* + * Must wait for cmdInProgress bit (12) to clear before continuing with + * card configuration. + */ + + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + if(jiffies-t > 40*HZ) { + printk(KERN_ERR "3COM 3C359 Velocity XL card not responding.\n"); + break ; + } + } + +} + +static void xl_freemem(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv ; + int i ; + + for (i=0;irx_ring_skb[xl_priv->rx_ring_tail]) ; + pci_unmap_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE) ; + xl_priv->rx_ring_tail++ ; + xl_priv->rx_ring_tail &= XL_RX_RING_SIZE-1; + } + + /* unmap ring */ + pci_unmap_single(xl_priv->pdev,xl_priv->rx_ring_dma_addr, sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE, PCI_DMA_FROMDEVICE) ; + + pci_unmap_single(xl_priv->pdev,xl_priv->tx_ring_dma_addr, sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE, PCI_DMA_TODEVICE) ; + + kfree(xl_priv->xl_rx_ring) ; + kfree(xl_priv->xl_tx_ring) ; + + return ; +} + +static void xl_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct xl_private *xl_priv =(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + u16 intstatus, macstatus ; + + if (!dev) { + printk(KERN_WARNING "Device structure dead, aaahhhh !\n") ; + return ; + } + + intstatus = readw(xl_mmio + MMIO_INTSTATUS) ; + + if (!(intstatus & 1)) /* We didn't generate the interrupt */ + return ; + + spin_lock(&xl_priv->xl_lock) ; + + /* + * Process the interrupt + */ + /* + * Something fishy going on here, we shouldn't get 0001 ints, not fatal though. + */ + if (intstatus == 0x0001) { + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + printk(KERN_INFO "%s: 00001 int received \n",dev->name) ; + } else { + if (intstatus & (HOSTERRINT | SRBRINT | ARBCINT | UPCOMPINT | DNCOMPINT | HARDERRINT | (1<<8) | TXUNDERRUN | ASBFINT)) { + + /* + * Host Error. + * It may be possible to recover from this, but usually it means something + * is seriously fubar, so we just close the adapter. + */ + + if (intstatus & HOSTERRINT) { + printk(KERN_WARNING "%s: Host Error, performing global reset, intstatus = %04x \n",dev->name,intstatus) ; + writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; + printk(KERN_WARNING "%s: Resetting hardware: \n", dev->name); + netif_stop_queue(dev) ; + xl_freemem(dev) ; + free_irq(dev->irq,dev); + xl_reset(dev) ; + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + spin_unlock(&xl_priv->xl_lock) ; + return ; + } /* Host Error */ + + if (intstatus & SRBRINT ) { /* Srbc interrupt */ + writel(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + if (xl_priv->srb_queued) + xl_srb_bh(dev) ; + } /* SRBR Interrupt */ + + if (intstatus & TXUNDERRUN) { /* Issue DnReset command */ + writel(DNRESET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { /* Wait for command to run */ + /* !!! FIX-ME !!!! + Must put a timeout check here ! */ + /* Empty Loop */ + } + printk(KERN_WARNING "%s: TX Underrun received \n",dev->name) ; + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + } /* TxUnderRun */ + + if (intstatus & ARBCINT ) { /* Arbc interrupt */ + xl_arb_cmd(dev) ; + } /* Arbc */ + + if (intstatus & ASBFINT) { + if (xl_priv->asb_queued == 1) { + xl_asb_cmd(dev) ; + } else if (xl_priv->asb_queued == 2) { + xl_asb_bh(dev) ; + } else { + writel(ACK_INTERRUPT | LATCH_ACK | ASBFACK, xl_mmio + MMIO_COMMAND) ; + } + } /* Asbf */ + + if (intstatus & UPCOMPINT ) /* UpComplete */ + xl_rx(dev) ; + + if (intstatus & DNCOMPINT ) /* DnComplete */ + xl_dn_comp(dev) ; + + if (intstatus & HARDERRINT ) { /* Hardware error */ + writel(MMIO_WORD_READ | MACSTATUS, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + macstatus = readw(xl_mmio + MMIO_MACDATA) ; + printk(KERN_WARNING "%s: MacStatusError, details: ", dev->name); + if (macstatus & (1<<14)) + printk(KERN_WARNING "tchk error: Unrecoverable error \n") ; + if (macstatus & (1<<3)) + printk(KERN_WARNING "eint error: Internal watchdog timer expired \n") ; + if (macstatus & (1<<2)) + printk(KERN_WARNING "aint error: Host tried to perform illegal operation \n") ; + printk(KERN_WARNING "Instatus = %02x, macstatus = %02x\n",intstatus,macstatus) ; + printk(KERN_WARNING "%s: Resetting hardware: \n", dev->name); + netif_stop_queue(dev) ; + xl_freemem(dev) ; + free_irq(dev->irq,dev); + unregister_trdev(dev) ; + kfree(dev) ; + xl_reset(dev) ; + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + spin_unlock(&xl_priv->xl_lock) ; + return ; + } + } else { + printk(KERN_WARNING "%s: Received Unknown interrupt : %04x \n", dev->name, intstatus) ; + writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + } + } + + /* Turn interrupts back on */ + + writel( SETINDENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; + writel( SETINTENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; + + spin_unlock(&xl_priv->xl_lock) ; +} + +/* + * Tx - Polling configuration + */ + +static int xl_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + struct xl_tx_desc *txd ; + int tx_head, tx_tail, tx_prev ; + unsigned long flags ; + + spin_lock_irqsave(&xl_priv->xl_lock,flags) ; + + netif_stop_queue(dev) ; + + if (xl_priv->free_ring_entries > 1 ) { + /* + * Set up the descriptor for the packet + */ + tx_head = xl_priv->tx_ring_head ; + tx_tail = xl_priv->tx_ring_tail ; + + txd = &(xl_priv->xl_tx_ring[tx_head]) ; + txd->dnnextptr = 0 ; + txd->framestartheader = skb->len | TXDNINDICATE ; + txd->buffer = pci_map_single(xl_priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE) ; + txd->buffer_length = skb->len | TXDNFRAGLAST ; + xl_priv->tx_ring_skb[tx_head] = skb ; + xl_priv->xl_stats.tx_packets++ ; + xl_priv->xl_stats.tx_bytes += skb->len ; + + /* + * Set the nextptr of the previous descriptor equal to this descriptor, add XL_TX_RING_SIZE -1 + * to ensure no negative numbers in unsigned locations. + */ + + tx_prev = (xl_priv->tx_ring_head + XL_TX_RING_SIZE - 1) & (XL_TX_RING_SIZE - 1) ; + + xl_priv->tx_ring_head++ ; + xl_priv->tx_ring_head &= (XL_TX_RING_SIZE - 1) ; + xl_priv->free_ring_entries-- ; + + xl_priv->xl_tx_ring[tx_prev].dnnextptr = xl_priv->tx_ring_dma_addr + (sizeof (struct xl_tx_desc) * tx_head) ; + + /* Sneaky, by doing a read on DnListPtr we can force the card to poll on the DnNextPtr */ + /* readl(xl_mmio + MMIO_DNLISTPTR) ; */ + + netif_wake_queue(dev) ; + + spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; + + return 0; + } else { + spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; + return 1; + } + +} + +/* + * The NIC has told us that a packet has been downloaded onto the card, we must + * find out which packet it has done, clear the skb and information for the packet + * then advance around the ring for all tranmitted packets + */ + +static void xl_dn_comp(struct net_device *dev) +{ + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + struct xl_tx_desc *txd ; + + + if (xl_priv->tx_ring_tail == 255) {/* First time */ + xl_priv->xl_tx_ring[0].framestartheader = 0 ; + xl_priv->xl_tx_ring[0].dnnextptr = 0 ; + xl_priv->tx_ring_tail = 1 ; + } + + while (xl_priv->xl_tx_ring[xl_priv->tx_ring_tail].framestartheader & TXDNCOMPLETE ) { + txd = &(xl_priv->xl_tx_ring[xl_priv->tx_ring_tail]) ; + pci_unmap_single(xl_priv->pdev,txd->buffer, xl_priv->tx_ring_skb[xl_priv->tx_ring_tail]->len, PCI_DMA_TODEVICE) ; + txd->framestartheader = 0 ; + txd->buffer = 0xdeadbeef ; + txd->buffer_length = 0 ; + dev_kfree_skb_irq(xl_priv->tx_ring_skb[xl_priv->tx_ring_tail]) ; + xl_priv->tx_ring_tail++ ; + xl_priv->tx_ring_tail &= (XL_TX_RING_SIZE - 1) ; + xl_priv->free_ring_entries++ ; + } + + netif_wake_queue(dev) ; + + writel(ACK_INTERRUPT | DNCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; +} + +/* + * Close the adapter properly. + * This srb reply cannot be handled from interrupt context as we have + * to free the interrupt from the driver. + */ + +static int xl_close(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + unsigned long t ; + + netif_stop_queue(dev) ; + + /* + * Close the adapter, need to stall the rx and tx queues. + */ + + writew(DNSTALL, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNSTALL not responding.\n", dev->name); + break ; + } + } + writew(DNDISABLE, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNDISABLE not responding.\n", dev->name); + break ; + } + } + writew(UPSTALL, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-UPSTALL not responding.\n", dev->name); + break ; + } + } + + /* Turn off interrupts, we will still get the indication though + * so we can trap it + */ + + writel(SETINTENABLE, xl_mmio + MMIO_COMMAND) ; + + xl_srb_cmd(dev,CLOSE_NIC) ; + + t=jiffies; + while (!(readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_SRB)) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-CLOSENIC not responding.\n", dev->name); + break ; + } + } + /* Read the srb response from the adapter */ + + writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD); + if (readb(xl_mmio + MMIO_MACDATA) != CLOSE_NIC) { + printk(KERN_INFO "%s: CLOSE_NIC did not get a CLOSE_NIC response \n",dev->name) ; + } else { + writel((MEM_BYTE_READ | 0xd0000 | xl_priv->srb) +2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if (readb(xl_mmio + MMIO_MACDATA)==0) { + printk(KERN_INFO "%s: Adapter has been closed \n",dev->name) ; + writew(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + + xl_freemem(dev) ; + free_irq(dev->irq,dev) ; + } else { + printk(KERN_INFO "%s: Close nic command returned error code %02x\n",dev->name, readb(xl_mmio + MMIO_MACDATA)) ; + } + } + + /* Reset the upload and download logic */ + + writew(UPRESET, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-UPRESET not responding.\n", dev->name); + break ; + } + } + writew(DNRESET, xl_mmio + MMIO_COMMAND) ; + t=jiffies; + while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { + schedule(); + if(jiffies-t > 10*HZ) { + printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNRESET not responding.\n", dev->name); + break ; + } + } + xl_hw_reset(dev) ; + return 0 ; +} + +static void xl_set_rx_mode(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + struct dev_mc_list *dmi ; + unsigned char dev_mc_address[4] ; + u16 options ; + int i ; + + if (dev->flags & IFF_PROMISC) + options = 0x0004 ; + else + options = 0x0000 ; + + if (options ^ xl_priv->xl_copy_all_options) { /* Changed, must send command */ + xl_priv->xl_copy_all_options = options ; + xl_srb_cmd(dev, SET_RECEIVE_MODE) ; + return ; + } + + dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; + + for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) { + dev_mc_address[0] |= dmi->dmi_addr[2] ; + dev_mc_address[1] |= dmi->dmi_addr[3] ; + dev_mc_address[2] |= dmi->dmi_addr[4] ; + dev_mc_address[3] |= dmi->dmi_addr[5] ; + } + + if (memcmp(xl_priv->xl_functional_addr,dev_mc_address,4) != 0) { /* Options have changed, run the command */ + memcpy(xl_priv->xl_functional_addr, dev_mc_address,4) ; + xl_srb_cmd(dev, SET_FUNC_ADDRESS) ; + } + return ; +} + + +/* + * We issued an srb command and now we must read + * the response from the completed command. + */ + +static void xl_srb_bh(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + u8 srb_cmd, ret_code ; + int i ; + + writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + srb_cmd = readb(xl_mmio + MMIO_MACDATA) ; + writel((MEM_BYTE_READ | 0xd0000 | xl_priv->srb) +2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + ret_code = readb(xl_mmio + MMIO_MACDATA) ; + + /* Ret_code is standard across all commands */ + + switch (ret_code) { + case 1: + printk(KERN_INFO "%s: Command: %d - Invalid Command code\n",dev->name,srb_cmd) ; + break ; + case 4: + printk(KERN_INFO "%s: Command: %d - Adapter is closed, must be open for this command \n",dev->name,srb_cmd) ; + break ; + + case 6: + printk(KERN_INFO "%s: Command: %d - Options Invalid for command \n",dev->name,srb_cmd) ; + break ; + + case 0: /* Successful command execution */ + switch (srb_cmd) { + case READ_LOG: /* Returns 14 bytes of data from the NIC */ + if(xl_priv->xl_message_level) + printk(KERN_INFO "%s: READ.LOG 14 bytes of data ",dev->name) ; + /* + * We still have to read the log even if message_level = 0 and we don't want + * to see it + */ + for (i=0;i<14;i++) { + writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if(xl_priv->xl_message_level) + printk("%02x:",readb(xl_mmio + MMIO_MACDATA)) ; + } + printk("\n") ; + break ; + case SET_FUNC_ADDRESS: + if(xl_priv->xl_message_level) + printk(KERN_INFO "%s: Functional Address Set \n",dev->name) ; + break ; + case CLOSE_NIC: + if(xl_priv->xl_message_level) + printk(KERN_INFO "%s: Received CLOSE_NIC interrupt in interrupt handler \n",dev->name) ; + break ; + case SET_MULTICAST_MODE: + if(xl_priv->xl_message_level) + printk(KERN_INFO "%s: Multicast options successfully changed\n",dev->name) ; + break ; + case SET_RECEIVE_MODE: + if(xl_priv->xl_message_level) { + if (xl_priv->xl_copy_all_options == 0x0004) + printk(KERN_INFO "%s: Entering promiscuous mode \n", dev->name) ; + else + printk(KERN_INFO "%s: Entering normal receive mode \n",dev->name) ; + } + break ; + + } /* switch */ + break ; + } /* switch */ + return ; +} + +static struct net_device_stats * xl_get_stats(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + return (struct net_device_stats *) &xl_priv->xl_stats; +} + +static int xl_set_mac_address (struct net_device *dev, void *addr) +{ + struct sockaddr *saddr = addr ; + struct xl_private *xl_priv = (struct xl_private *)dev->priv ; + + if (netif_running(dev)) { + printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; + return -EIO ; + } + + memcpy(xl_priv->xl_laa, saddr->sa_data,dev->addr_len) ; + + if (xl_priv->xl_message_level) { + printk(KERN_INFO "%s: MAC/LAA Set to = %x.%x.%x.%x.%x.%x\n",dev->name, xl_priv->xl_laa[0], + xl_priv->xl_laa[1], xl_priv->xl_laa[2], + xl_priv->xl_laa[3], xl_priv->xl_laa[4], + xl_priv->xl_laa[5]); + } + + return 0 ; +} + +static void xl_arb_cmd(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv; + u8 * xl_mmio = xl_priv->xl_mmio ; + u8 arb_cmd ; + u16 lan_status, lan_status_diff ; + + writel( ( MEM_BYTE_READ | 0xD0000 | xl_priv->arb), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + arb_cmd = readb(xl_mmio + MMIO_MACDATA) ; + + if (arb_cmd == RING_STATUS_CHANGE) { /* Ring.Status.Change */ + writel( ( (MEM_WORD_READ | 0xD0000 | xl_priv->arb) + 6), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + + printk(KERN_INFO "%s: Ring Status Change: New Status = %04x\n", dev->name, ntohs(readw(xl_mmio + MMIO_MACDATA) )) ; + + lan_status = ntohs(readw(xl_mmio + MMIO_MACDATA)); + + /* Acknowledge interrupt, this tells nic we are done with the arb */ + writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + + lan_status_diff = xl_priv->xl_lan_status ^ lan_status ; + + if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR) ) { + if (lan_status_diff & LSC_LWF) + printk(KERN_WARNING "%s: Short circuit detected on the lobe\n",dev->name); + if (lan_status_diff & LSC_ARW) + printk(KERN_WARNING "%s: Auto removal error\n",dev->name); + if (lan_status_diff & LSC_FPE) + printk(KERN_WARNING "%s: FDX Protocol Error\n",dev->name); + if (lan_status_diff & LSC_RR) + printk(KERN_WARNING "%s: Force remove MAC frame received\n",dev->name); + + /* Adapter has been closed by the hardware */ + + netif_stop_queue(dev); + xl_freemem(dev) ; + free_irq(dev->irq,dev); + + printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; + } /* If serious error */ + + if (xl_priv->xl_message_level) { + if (lan_status_diff & LSC_SIG_LOSS) + printk(KERN_WARNING "%s: No receive signal detected \n", dev->name) ; + if (lan_status_diff & LSC_HARD_ERR) + printk(KERN_INFO "%s: Beaconing \n",dev->name); + if (lan_status_diff & LSC_SOFT_ERR) + printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame \n",dev->name); + if (lan_status_diff & LSC_TRAN_BCN) + printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name); + if (lan_status_diff & LSC_SS) + printk(KERN_INFO "%s: Single Station on the ring \n", dev->name); + if (lan_status_diff & LSC_RING_REC) + printk(KERN_INFO "%s: Ring recovery ongoing\n",dev->name); + if (lan_status_diff & LSC_FDX_MODE) + printk(KERN_INFO "%s: Operating in FDX mode\n",dev->name); + } + + if (lan_status_diff & LSC_CO) { + if (xl_priv->xl_message_level) + printk(KERN_INFO "%s: Counter Overflow \n", dev->name); + /* Issue READ.LOG command */ + xl_srb_cmd(dev, READ_LOG) ; + } + + /* There is no command in the tech docs to issue the read_sr_counters */ + if (lan_status_diff & LSC_SR_CO) { + if (xl_priv->xl_message_level) + printk(KERN_INFO "%s: Source routing counters overflow\n", dev->name); + } + + xl_priv->xl_lan_status = lan_status ; + + } /* Lan.change.status */ + else if ( arb_cmd == RECEIVE_DATA) { /* Received.Data */ +#if XL_DEBUG + printk(KERN_INFO "Received.Data \n") ; +#endif + writel( ((MEM_WORD_READ | 0xD0000 | xl_priv->arb) + 6), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + xl_priv->mac_buffer = ntohs(readw(xl_mmio + MMIO_MACDATA)) ; + + /* Now we are going to be really basic here and not do anything + * with the data at all. The tech docs do not give me enough + * information to calculate the buffers properly so we're + * just going to tell the nic that we've dealt with the frame + * anyway. + */ + + dev->last_rx = jiffies ; + /* Acknowledge interrupt, this tells nic we are done with the arb */ + writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; + + /* Is the ASB free ? */ + + xl_priv->asb_queued = 0 ; + writel( ((MEM_BYTE_READ | 0xD0000 | xl_priv->asb) + 2), xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if (readb(xl_mmio + MMIO_MACDATA) != 0xff) { + xl_priv->asb_queued = 1 ; + + xl_wait_misr_flags(dev) ; + + writel(MEM_BYTE_WRITE | MF_ASBFR, xl_mmio + MMIO_MAC_ACCESS_CMD); + writeb(0xff, xl_mmio + MMIO_MACDATA) ; + writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(MISR_ASBFR, xl_mmio + MMIO_MACDATA) ; + return ; + /* Drop out and wait for the bottom half to be run */ + } + + xl_asb_cmd(dev) ; + + } else { + printk(KERN_WARNING "%s: Received unknown arb (xl_priv) command: %02x \n",dev->name,arb_cmd) ; + } + + /* Acknowledge the arb interrupt */ + + writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; + + return ; +} + + +/* + * There is only one asb command, but we can get called from different + * places. + */ + +static void xl_asb_cmd(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + + if (xl_priv->asb_queued == 1) + writel(ACK_INTERRUPT | LATCH_ACK | ASBFACK, xl_mmio + MMIO_COMMAND) ; + + writel(MEM_BYTE_WRITE | 0xd0000 | xl_priv->asb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x81, xl_mmio + MMIO_MACDATA) ; + + writel(MEM_WORD_WRITE | 0xd0000 | xl_priv->asb | 6, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(ntohs(xl_priv->mac_buffer), xl_mmio + MMIO_MACDATA) ; + + xl_wait_misr_flags(dev) ; + + writel(MEM_BYTE_WRITE | MF_RASB, xl_mmio + MMIO_MAC_ACCESS_CMD); + writeb(0xff, xl_mmio + MMIO_MACDATA) ; + + writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(MISR_RASB, xl_mmio + MMIO_MACDATA) ; + + xl_priv->asb_queued = 2 ; + + return ; +} + +/* + * This will only get called if there was an error + * from the asb cmd. + */ +static void xl_asb_bh(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + u8 ret_code ; + + writel(MMIO_BYTE_READ | 0xd0000 | xl_priv->asb | 2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + ret_code = readb(xl_mmio + MMIO_MACDATA) ; + switch (ret_code) { + case 0x01: + printk(KERN_INFO "%s: ASB Command, unrecognized command code \n",dev->name) ; + break ; + case 0x26: + printk(KERN_INFO "%s: ASB Command, unexpected receive buffer \n", dev->name) ; + break ; + case 0x40: + printk(KERN_INFO "%s: ASB Command, Invalid Station ID \n", dev->name) ; + break ; + } + xl_priv->asb_queued = 0 ; + writel(ACK_INTERRUPT | LATCH_ACK | ASBFACK, xl_mmio + MMIO_COMMAND) ; + return ; +} + +/* + * Issue srb commands to the nic + */ + +static void xl_srb_cmd(struct net_device *dev, int srb_cmd) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + + switch (srb_cmd) { + case READ_LOG: + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(READ_LOG, xl_mmio + MMIO_MACDATA) ; + break; + + case CLOSE_NIC: + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(CLOSE_NIC, xl_mmio + MMIO_MACDATA) ; + break ; + + case SET_RECEIVE_MODE: + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(SET_RECEIVE_MODE, xl_mmio + MMIO_MACDATA) ; + writel(MEM_WORD_WRITE | 0xD0000 | xl_priv->srb | 4, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writew(xl_priv->xl_copy_all_options, xl_mmio + MMIO_MACDATA) ; + break ; + + case SET_FUNC_ADDRESS: + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(SET_FUNC_ADDRESS, xl_mmio + MMIO_MACDATA) ; + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 6 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_functional_addr[0], xl_mmio + MMIO_MACDATA) ; + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 7 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_functional_addr[1], xl_mmio + MMIO_MACDATA) ; + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 8 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_functional_addr[2], xl_mmio + MMIO_MACDATA) ; + writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 9 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(xl_priv->xl_functional_addr[3], xl_mmio + MMIO_MACDATA) ; + break ; + } /* switch */ + + + xl_wait_misr_flags(dev) ; + + /* Write 0xff to the CSRB flag */ + writel(MEM_BYTE_WRITE | MF_CSRB , xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0xFF, xl_mmio + MMIO_MACDATA) ; + /* Set csrb bit in MISR register to process command */ + writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(MISR_CSRB, xl_mmio + MMIO_MACDATA) ; + xl_priv->srb_queued = 1 ; + + return ; +} + +/* + * This is nasty, to use the MISR command you have to wait for 6 memory locations + * to be zero. This is the way the driver does on other OS'es so we should be ok with + * the empty loop. + */ + +static void xl_wait_misr_flags(struct net_device *dev) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv ; + u8 * xl_mmio = xl_priv->xl_mmio ; + + int i ; + + writel(MMIO_BYTE_READ | MISR_RW, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + if (readb(xl_mmio + MMIO_MACDATA) != 0) { /* Misr not clear */ + for (i=0; i<6; i++) { + writel(MEM_BYTE_READ | 0xDFFE0 | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + while (readb(xl_mmio + MMIO_MACDATA) != 0 ) {} ; /* Empty Loop */ + } + } + + writel(MMIO_BYTE_WRITE | MISR_AND, xl_mmio + MMIO_MAC_ACCESS_CMD) ; + writeb(0x80, xl_mmio + MMIO_MACDATA) ; + + return ; +} + +/* + * Change mtu size, this should work the same as olympic + */ + +static int xl_change_mtu(struct net_device *dev, int mtu) +{ + struct xl_private *xl_priv = (struct xl_private *) dev->priv; + u16 max_mtu ; + + if (xl_priv->xl_ring_speed == 4) + max_mtu = 4500 ; + else + max_mtu = 18000 ; + + if (mtu > max_mtu) + return -EINVAL ; + if (mtu < 100) + return -EINVAL ; + + dev->mtu = mtu ; + xl_priv->pkt_buf_sz = mtu + TR_HLEN ; + + return 0 ; +} + +static void __devexit xl_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct xl_private *xl_priv=(struct xl_private *)dev->priv; + + unregister_trdev(dev); + iounmap(xl_priv->xl_mmio) ; + pci_release_regions(pdev) ; + pci_set_drvdata(pdev,NULL) ; + kfree(dev); + return ; +} + +static struct pci_driver xl_3c359_driver = { + name: "3c359", + id_table: xl_pci_tbl, + probe: xl_probe, + remove: __devexit_p(xl_remove_one), +}; + +static int __init xl_pci_init (void) +{ + return pci_module_init (&xl_3c359_driver); +} + + +static void __exit xl_pci_cleanup (void) +{ + pci_unregister_driver (&xl_3c359_driver); +} + +module_init(xl_pci_init); +module_exit(xl_pci_cleanup); + +MODULE_LICENSE("GPL") ; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tokenring/3c359.h linux-2.5/drivers/net/tokenring/3c359.h --- linux-2.5.5/drivers/net/tokenring/3c359.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/tokenring/3c359.h Tue Feb 26 21:24:49 2002 @@ -0,0 +1,290 @@ +/* + * 3c359.h (c) 2000 Mike Phillips (mikep@linuxtr.net) All Rights Reserved + * + * Linux driver for 3Com 3C359 Token Link PCI XL cards. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License Version 2 or (at your option) + * any later verion, incorporated herein by reference. + */ + +/* Memory Access Commands */ +#define IO_BYTE_READ 0x28 << 24 +#define IO_BYTE_WRITE 0x18 << 24 +#define IO_WORD_READ 0x20 << 24 +#define IO_WORD_WRITE 0x10 << 24 +#define MMIO_BYTE_READ 0x88 << 24 +#define MMIO_BYTE_WRITE 0x48 << 24 +#define MMIO_WORD_READ 0x80 << 24 +#define MMIO_WORD_WRITE 0x40 << 24 +#define MEM_BYTE_READ 0x8C << 24 +#define MEM_BYTE_WRITE 0x4C << 24 +#define MEM_WORD_READ 0x84 << 24 +#define MEM_WORD_WRITE 0x44 << 24 + +#define PMBAR 0x1C80 +#define PMB_CPHOLD (1<<10) + +#define CPATTENTION 0x180D +#define CPA_PMBARVIS (1<<7) +#define CPA_MEMWREN (1<<6) + +#define SWITCHSETTINGS 0x1C88 +#define EECONTROL 0x1C8A +#define EEDATA 0x1C8C +#define EEREAD 0x0080 +#define EEWRITE 0x0040 +#define EEERASE 0x0060 +#define EE_ENABLE_WRITE 0x0030 +#define EEBUSY (1<<15) + +#define WRBR 0xCDE02 +#define WWOR 0xCDE04 +#define WWCR 0xCDE06 +#define MACSTATUS 0xCDE08 +#define MISR_RW 0xCDE0B +#define MISR_AND 0xCDE2B +#define MISR_SET 0xCDE4B +#define RXBUFAREA 0xCDE10 +#define RXEARLYTHRESH 0xCDE12 +#define TXSTARTTHRESH 0x58 +#define DNPRIREQTHRESH 0x2C + +#define MISR_CSRB (1<<5) +#define MISR_RASB (1<<4) +#define MISR_SRBFR (1<<3) +#define MISR_ASBFR (1<<2) +#define MISR_ARBF (1<<1) + +/* MISR Flags memory locations */ +#define MF_SSBF 0xDFFE0 +#define MF_ARBF 0xDFFE1 +#define MF_ASBFR 0xDFFE2 +#define MF_SRBFR 0xDFFE3 +#define MF_RASB 0xDFFE4 +#define MF_CSRB 0xDFFE5 + +#define MMIO_MACDATA 0x10 +#define MMIO_MAC_ACCESS_CMD 0x14 +#define MMIO_TIMER 0x1A +#define MMIO_DMA_CTRL 0x20 +#define MMIO_DNLISTPTR 0x24 +#define MMIO_HASHFILTER 0x28 +#define MMIO_CONFIG 0x29 +#define MMIO_DNPRIREQTHRESH 0x2C +#define MMIO_DNPOLL 0x2D +#define MMIO_UPPKTSTATUS 0x30 +#define MMIO_FREETIMER 0x34 +#define MMIO_COUNTDOWN 0x36 +#define MMIO_UPLISTPTR 0x38 +#define MMIO_UPPOLL 0x3C +#define MMIO_UPBURSTTHRESH 0x40 +#define MMIO_DNBURSTTHRESH 0x41 +#define MMIO_INTSTATUS_AUTO 0x56 +#define MMIO_TXSTARTTHRESH 0x58 +#define MMIO_INTERRUPTENABLE 0x5A +#define MMIO_INDICATIONENABLE 0x5C +#define MMIO_COMMAND 0x5E /* These two are meant to be the same */ +#define MMIO_INTSTATUS 0x5E /* Makes the code more readable this way */ +#define INTSTAT_CMD_IN_PROGRESS (1<<12) +#define INTSTAT_SRB (1<<14) +#define INTSTAT_INTLATCH (1<<0) + +/* Indication / Interrupt Mask + * Annoyingly the bits to be set in the indication and interrupt enable + * do not match with the actual bits received in the interrupt, although + * they are in the same order. + * The mapping for the indication / interrupt are: + * Bit Indication / Interrupt + * 0 HostError + * 1 txcomplete + * 2 updneeded + * 3 rxcomplete + * 4 intrequested + * 5 macerror + * 6 dncomplete + * 7 upcomplete + * 8 txunderrun + * 9 asbf + * 10 srbr + * 11 arbc + * + * The only ones we don't want to receive are txcomplete and rxcomplete + * we use dncomplete and upcomplete instead. + */ + +#define INT_MASK 0xFF5 + +/* Note the subtle difference here, IND and INT */ + +#define SETINDENABLE (8<<12) +#define SETINTENABLE (7<<12) +#define SRBBIT (1<<10) +#define ASBBIT (1<<9) +#define ARBBIT (1<<11) + +#define SRB 0xDFE90 +#define ASB 0xDFED0 +#define ARB 0xD0000 +#define SCRATCH 0xDFEF0 + +#define INT_REQUEST 0x6000 /* (6 << 12) */ +#define ACK_INTERRUPT 0x6800 /* (13 <<11) */ +#define GLOBAL_RESET 0x00 +#define DNDISABLE 0x5000 +#define DNENABLE 0x4800 +#define DNSTALL 0x3002 +#define DNRESET 0x5800 +#define DNUNSTALL 0x3003 +#define UPRESET 0x2800 +#define UPSTALL 0x3000 +#define UPUNSTALL 0x3001 +#define SETCONFIG 0x4000 +#define SETTXSTARTTHRESH 0x9800 + +/* Received Interrupts */ +#define ASBFINT (1<<13) +#define SRBRINT (1<<14) +#define ARBCINT (1<<15) +#define TXUNDERRUN (1<<11) + +#define UPCOMPINT (1<<10) +#define DNCOMPINT (1<<9) +#define HARDERRINT (1<<7) +#define RXCOMPLETE (1<<4) +#define TXCOMPINT (1<<2) +#define HOSTERRINT (1<<1) + +/* Receive descriptor bits */ +#define RXOVERRUN (1<<19) +#define RXFC (1<<21) +#define RXAR (1<<22) +#define RXUPDCOMPLETE (1<<23) +#define RXUPDFULL (1<<24) +#define RXUPLASTFRAG (1<<31) + +/* Transmit descriptor bits */ +#define TXDNCOMPLETE (1<<16) +#define TXTXINDICATE (1<<27) +#define TXDPDEMPTY (1<<29) +#define TXDNINDICATE (1<<31) +#define TXDNFRAGLAST (1<<31) + +/* Interrupts to Acknowledge */ +#define LATCH_ACK 1 +#define TXCOMPACK (1<<1) +#define INTREQACK (1<<2) +#define DNCOMPACK (1<<3) +#define UPCOMPACK (1<<4) +#define ASBFACK (1<<5) +#define SRBRACK (1<<6) +#define ARBCACK (1<<7) + +#define XL_IO_SPACE 128 +#define SRB_COMMAND_SIZE 50 + +/* Adapter Commands */ +#define REQUEST_INT 0x00 +#define MODIFY_OPEN_PARMS 0x01 +#define RESTORE_OPEN_PARMS 0x02 +#define OPEN_NIC 0x03 +#define CLOSE_NIC 0x04 +#define SET_SLEEP_MODE 0x05 +#define SET_GROUP_ADDRESS 0x06 +#define SET_FUNC_ADDRESS 0x07 +#define READ_LOG 0x08 +#define SET_MULTICAST_MODE 0x0C +#define CHANGE_WAKEUP_PATTERN 0x0D +#define GET_STATISTICS 0x13 +#define SET_RECEIVE_MODE 0x1F + +/* ARB Commands */ +#define RECEIVE_DATA 0x81 +#define RING_STATUS_CHANGE 0x84 + +/* ASB Commands */ +#define ASB_RECEIVE_DATE 0x81 + +/* Defines for LAN STATUS CHANGE reports */ +#define LSC_SIG_LOSS 0x8000 +#define LSC_HARD_ERR 0x4000 +#define LSC_SOFT_ERR 0x2000 +#define LSC_TRAN_BCN 0x1000 +#define LSC_LWF 0x0800 +#define LSC_ARW 0x0400 +#define LSC_FPE 0x0200 +#define LSC_RR 0x0100 +#define LSC_CO 0x0080 +#define LSC_SS 0x0040 +#define LSC_RING_REC 0x0020 +#define LSC_SR_CO 0x0010 +#define LSC_FDX_MODE 0x0004 + +#define XL_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */ + +/* 3c359 defaults for buffers */ + +#define XL_RX_RING_SIZE 16 /* must be a power of 2 */ +#define XL_TX_RING_SIZE 16 /* must be a power of 2 */ + +#define PKT_BUF_SZ 4096 /* Default packet size */ + +/* 3c359 data structures */ + +struct xl_tx_desc { + u32 dnnextptr ; + u32 framestartheader ; + u32 buffer ; + u32 buffer_length ; +}; + +struct xl_rx_desc { + u32 upnextptr ; + u32 framestatus ; + u32 upfragaddr ; + u32 upfraglen ; +}; + +struct xl_private { + + + /* These two structures must be aligned on 8 byte boundaries */ + + /* struct xl_rx_desc xl_rx_ring[XL_RX_RING_SIZE]; */ + /* struct xl_tx_desc xl_tx_ring[XL_TX_RING_SIZE]; */ + struct xl_rx_desc *xl_rx_ring ; + struct xl_tx_desc *xl_tx_ring ; + struct sk_buff *tx_ring_skb[XL_TX_RING_SIZE], *rx_ring_skb[XL_RX_RING_SIZE]; + int tx_ring_head, tx_ring_tail ; + int rx_ring_tail, rx_ring_no ; + int free_ring_entries ; + + u16 srb; + u16 arb; + u16 asb; + + u8 *xl_mmio; + char *xl_card_name; + struct pci_dev *pdev ; + + spinlock_t xl_lock ; + + volatile int srb_queued; + struct wait_queue *srb_wait; + volatile int asb_queued; + + struct net_device_stats xl_stats ; + + u16 mac_buffer ; + u16 xl_lan_status ; + u8 xl_ring_speed ; + u16 pkt_buf_sz ; + u8 xl_message_level; + u16 xl_copy_all_options ; + unsigned char xl_functional_addr[4] ; + u16 xl_addr_table_addr, xl_parms_addr ; + u8 xl_laa[6] ; + u32 rx_ring_dma_addr ; + u32 tx_ring_dma_addr ; +}; + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tokenring/3c359_microcode.h linux-2.5/drivers/net/tokenring/3c359_microcode.h --- linux-2.5.5/drivers/net/tokenring/3c359_microcode.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/tokenring/3c359_microcode.h Tue Feb 26 21:24:49 2002 @@ -0,0 +1,1585 @@ + +/* + * The firmware this driver downloads into the tokenring card is a + * separate program and is not GPL'd source code, even though the Linux + * side driver and the routine that loads this data into the card are. + * + * This firmware is licensed to you strictly for use in conjunction + * with the use of 3Com 3C359 TokenRing adapters. There is no + * waranty expressed or implied about its fitness for any purpose. + */ + +/* 3c359_microcode.mac: 3Com 3C359 Tokenring microcode. + * + * Notes: + * - Loaded from xl_init upon adapter initialization. + * + * Available from 3Com as part of their standard 3C359 driver. + * + * mc_size *must* must match the microcode being used, each version is a + * different length. + */ + + +#if defined(CONFIG_3C359) || defined(CONFIG_3C359_MODULE) + +static int mc_size = 24880 ; + +u8 microcode[] = { + 0xfe,0x3a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x33,0x2f,0x30,0x32,0x2f,0x39,0x39,0x20,0x31 +,0x37,0x3a,0x31,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46 +,0x00,0x00,0x07,0xff,0x02,0x00,0xfe,0x9f,0x06,0x00,0x00,0x7c,0x48,0x00,0x00,0x70 +,0x82,0x00,0xff,0xff,0x86,0x00,0xff,0xff,0x88,0x00,0xff,0xff,0x9a,0x00,0xff,0xff +,0xff,0xff,0x11,0x00,0xc0,0x00,0xff,0xff,0xff,0xff,0x11,0x22,0x33,0x44,0x55,0x66 +,0x33,0x43,0x4f,0x4d,0x20,0x42,0x41,0x42,0x45,0x11,0x40,0xc0,0x00,0xff,0xff,0xff +,0xff,0x11,0x22,0x33,0x44,0x55,0x66,0x53,0x74,0x61,0x72,0x74,0x20,0x6f,0x66,0x20 +,0x4c,0x4c,0x43,0x20,0x66,0x72,0x61,0x6d,0x65,0x2e,0x20,0x20,0x54,0x6f,0x74,0x61 +,0x6c,0x20,0x64,0x61,0x74,0x61,0x20,0x73,0x69,0x7a,0x65,0x20,0x69,0x73,0x20,0x78 +,0x78,0x78,0x20,0x20,0x20,0x42,0x41,0x42,0x45,0xe8,0xd2,0x01,0x83,0x3e,0xf7,0x34 +,0x00,0x75,0x21,0xe8,0x41,0x00,0x83,0x3e,0xf7,0x34,0x00,0x75,0x17,0xe8,0x82,0x00 +,0x83,0x3e,0xf7,0x34,0x00,0x75,0x0d,0xe8,0xbf,0x00,0x83,0x3e,0xf7,0x34,0x00,0x75 +,0x03,0xe8,0x41,0x02,0xc3,0x1e,0xb8,0x00,0xf0,0x8e,0xd8,0x33,0xf6,0xb9,0x00,0x80 +,0x33,0xdb,0xad,0x03,0xd8,0xe2,0xfb,0x1f,0xb8,0x00,0x00,0x83,0xfb,0x00,0x74,0x03 +,0xb8,0x22,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0xba,0x56,0x00,0xb0,0xff,0xee,0x33,0xc0 +,0x8e,0xc0,0x33,0xf6,0xb9,0xff,0x7f,0x83,0x3e,0xff,0x34,0x00,0x74,0x08,0x8d,0x3e +,0x30,0x61,0xd1,0xef,0x2b,0xcf,0x26,0x8b,0x1c,0x26,0xc7,0x04,0xff,0xff,0x26,0x83 +,0x3c,0xff,0x75,0x17,0x26,0xc7,0x04,0x00,0x00,0x26,0x83,0x3c,0x00,0x75,0x0c,0x26 +,0x89,0x1c,0x46,0x46,0xe2,0xe0,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x24,0x00,0xa3,0xf7 +,0x34,0xc3,0xfa,0xb4,0xd7,0x9e,0x73,0x3a,0x75,0x38,0x79,0x36,0x7b,0x34,0x9f,0xb1 +,0x05,0xd2,0xec,0x73,0x2d,0xb0,0x40,0xd0,0xe0,0x71,0x27,0x79,0x25,0xd0,0xe0,0x73 +,0x21,0x7b,0x1f,0x32,0xc0,0x75,0x1b,0x32,0xe4,0x9e,0x72,0x16,0x74,0x14,0x78,0x12 +,0x7a,0x10,0x9f,0xd2,0xec,0x72,0x0b,0xd0,0xe4,0x70,0x07,0x75,0x05,0xb8,0x00,0x00 +,0xeb,0x03,0xb8,0x26,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0xba,0x5a,0x00,0x33,0xc0,0xef +,0xef,0xef,0xef,0xb0,0x00,0xe6,0x56,0xb0,0x00,0xe6,0x54,0xba,0x52,0x00,0xb8,0x01 +,0x01,0xef,0xe8,0xca,0x00,0x3c,0x01,0x75,0x7f,0xe8,0x83,0x00,0xba,0x52,0x00,0xb8 +,0x02,0x02,0xef,0xe8,0xb9,0x00,0x3c,0x02,0x75,0x6e,0xe8,0x7a,0x00,0xba,0x52,0x00 +,0xb8,0x04,0x04,0xef,0xe8,0xa8,0x00,0x3c,0x04,0x75,0x5d,0xe8,0x71,0x00,0xba,0x52 +,0x00,0xb8,0x08,0x08,0xef,0xe8,0x97,0x00,0x3c,0x08,0x75,0x4c,0xe8,0x68,0x00,0xba +,0x52,0x00,0xb8,0x10,0x10,0xef,0xe8,0x86,0x00,0x3c,0x10,0x75,0x3b,0xe8,0x5f,0x00 +,0xba,0x52,0x00,0xb8,0x20,0x20,0xef,0xe8,0x75,0x00,0x3c,0x20,0x75,0x2a,0xe8,0x56 +,0x00,0xba,0x52,0x00,0xb8,0x40,0x40,0xef,0xe8,0x64,0x00,0x3c,0x40,0x75,0x19,0xe8 +,0x4d,0x00,0xba,0x52,0x00,0xb8,0x80,0x80,0xef,0xe8,0x53,0x00,0x3c,0x80,0x75,0x08 +,0xe8,0x44,0x00,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x28,0x00,0xa3,0xf7,0x34,0xc3,0xba +,0x5a,0x00,0xb8,0x00,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x01,0x80,0xef,0xc3,0xba +,0x5a,0x00,0xb8,0x02,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x03,0x80,0xef,0xc3,0xba +,0x5a,0x00,0xb8,0x04,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x05,0x80,0xef,0xc3,0xba +,0x5a,0x00,0xb8,0x06,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x07,0x80,0xef,0xc3,0xb9 +,0xff,0xff,0xe4,0x58,0xe4,0x54,0x3c,0x00,0x75,0x03,0x49,0x75,0xf7,0xc3,0xfa,0x32 +,0xc0,0xe6,0x56,0xe4,0x56,0x3c,0x00,0x74,0x03,0xe9,0x82,0x00,0xb0,0xff,0xe6,0x56 +,0xe4,0x56,0x3c,0xff,0x75,0x78,0xba,0x52,0x00,0xb8,0xff,0xff,0xef,0xed,0x3c,0xff +,0x75,0x6c,0xb8,0x00,0xff,0xef,0xed,0x3c,0x00,0x75,0x63,0xb0,0xff,0xe6,0x54,0xe4 +,0x54,0x3c,0xff,0x75,0x59,0x32,0xc0,0xe6,0x54,0xe4,0x54,0x3c,0x00,0x75,0x4f,0xb0 +,0x0f,0xe6,0x50,0xe4,0x50,0x24,0x0f,0x3c,0x0f,0x75,0x43,0xb0,0x00,0xe6,0x50,0xe4 +,0x50,0x24,0x0f,0x3c,0x00,0x75,0x37,0x8c,0xc8,0x8e,0xc0,0xbe,0x70,0x00,0x26,0x8b +,0x14,0x26,0x8b,0x5c,0x02,0xb8,0x00,0x00,0xef,0xed,0x23,0xc3,0x3d,0x00,0x00,0x75 +,0x1d,0xb8,0xff,0xff,0x23,0xc3,0xef,0x8b,0xc8,0xed,0x23,0xc3,0x3b,0xc1,0x75,0x0e +,0x83,0xc6,0x04,0x26,0x83,0x3c,0xff,0x75,0xd5,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x2a +,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0x33,0xc0,0xbf,0x00,0x20,0xb9,0x17,0x00,0xf3,0xab +,0xbf,0x00,0x30,0xb9,0x17,0x00,0xf3,0xab,0xbf,0x00,0x22,0xb9,0x40,0x00,0xf3,0xab +,0xbf,0x00,0x32,0xb9,0x40,0x00,0xf3,0xab,0xfc,0x1e,0x8c,0xc8,0x8e,0xd8,0x33,0xc0 +,0x8e,0xc0,0xbe,0x92,0x00,0xbf,0x00,0x20,0xb9,0x17,0x00,0xf3,0xa4,0xbe,0xa9,0x00 +,0xbf,0x00,0x22,0xb9,0x40,0x00,0xf3,0xa4,0x1f,0xc7,0x06,0xfb,0x34,0x64,0x00,0xba +,0x08,0x00,0xb8,0x0f,0x00,0xef,0xe8,0x82,0x01,0xe8,0x9b,0x01,0x72,0x0d,0xc7,0x06 +,0xf7,0x34,0x2c,0x00,0xc7,0x06,0xf9,0x34,0x04,0x00,0xc3,0xba,0x0a,0x00,0x33,0xc0 +,0xef,0xe8,0x98,0x01,0xe8,0xb5,0x01,0xb8,0x17,0x00,0xba,0x9c,0x00,0xef,0xb8,0x00 +,0x10,0xba,0x9a,0x00,0xef,0xb8,0x17,0x00,0xa9,0x01,0x00,0x74,0x01,0x40,0xba,0x8c +,0x00,0xef,0xb8,0x00,0x18,0xba,0x86,0x00,0xef,0xb8,0x0c,0x00,0xba,0x82,0x00,0xef +,0xba,0x02,0x00,0xed,0x25,0xf9,0xff,0x0d,0x02,0x00,0xef,0xba,0x06,0x00,0x33,0xc0 +,0xef,0xba,0x04,0x00,0xb8,0x60,0x00,0xef,0xba,0x00,0x00,0xb8,0x18,0x00,0xef,0xba +,0x80,0x00,0xb9,0xff,0xff,0xed,0xa9,0x01,0x00,0x75,0x04,0xe2,0xf8,0xeb,0x3e,0xba +,0x0a,0x00,0xed,0xa9,0x00,0x40,0x74,0x35,0xa9,0x00,0x20,0x74,0x30,0x33,0xc0,0xef +,0x51,0xb9,0xc8,0x00,0xe2,0xfe,0x59,0x1e,0x06,0x1f,0x26,0x8b,0x0e,0x02,0x30,0x83 +,0xf9,0x17,0x75,0x18,0x49,0x49,0xbe,0x02,0x20,0xbf,0x06,0x30,0xf3,0xa6,0x1f,0x23 +,0xc9,0x75,0x0a,0xff,0x0e,0xfb,0x34,0x74,0x12,0xe9,0x4d,0xff,0x1f,0xb8,0x2c,0x00 +,0xbb,0x00,0x00,0xa3,0xf7,0x34,0x89,0x1e,0xf9,0x34,0xc3,0xc7,0x06,0xfb,0x34,0x64 +,0x00,0xe8,0xd3,0x00,0x72,0x0d,0xc7,0x06,0xf7,0x34,0x2c,0x00,0xc7,0x06,0xf9,0x34 +,0x04,0x00,0xc3,0xe8,0xd6,0x00,0xe8,0xf3,0x00,0xb8,0x03,0x00,0xba,0x82,0x00,0xef +,0xb8,0x40,0x80,0xba,0x98,0x00,0xef,0xb8,0x00,0x11,0xba,0x96,0x00,0xef,0xb8,0x40 +,0x00,0xa9,0x01,0x00,0x74,0x01,0x40,0xba,0x92,0x00,0xef,0xb8,0x00,0x19,0xba,0x8e +,0x00,0xef,0xba,0x02,0x00,0xed,0x25,0xf9,0xff,0x0d,0x06,0x00,0xef,0xba,0x06,0x00 +,0x33,0xc0,0xef,0xba,0x00,0x00,0xb8,0x18,0x00,0xef,0xba,0x80,0x00,0xb9,0xff,0xff +,0xed,0xa9,0x20,0x00,0x75,0x04,0xe2,0xf8,0xeb,0x43,0xba,0x0a,0x00,0xed,0xa9,0x00 +,0x40,0x74,0x3a,0xa9,0x00,0x20,0x74,0x35,0x33,0xc0,0xef,0x51,0xb9,0xc8,0x00,0xe2 +,0xfe,0x59,0x1e,0x06,0x1f,0x26,0x8b,0x0e,0x02,0x32,0x83,0xf9,0x40,0x75,0x1d,0x49 +,0x49,0xbe,0x02,0x22,0xbf,0x06,0x32,0xf3,0xa6,0x1f,0x23,0xc9,0x75,0x0f,0xff,0x0e +,0xfb,0x34,0x74,0x03,0xe9,0x5a,0xff,0xb8,0x00,0x00,0xeb,0x0b,0x1f,0xb8,0x2c,0x00 +,0xbb,0x02,0x00,0x89,0x1e,0xf9,0x34,0xa3,0xf7,0x34,0xc3,0xba,0x02,0x00,0xb8,0x00 +,0x9c,0xef,0xba,0x00,0x00,0xb8,0x00,0x84,0xef,0x33,0xc0,0xef,0xba,0x0a,0x00,0xef +,0xba,0x0e,0x00,0x33,0xc0,0xef,0xc3,0xba,0x0a,0x00,0xb9,0xff,0xff,0xed,0x25,0x00 +,0x60,0x3d,0x00,0x60,0x74,0x04,0xe2,0xf5,0xf8,0xc3,0xf9,0xc3,0xb0,0x00,0xe6,0x56 +,0xb8,0x00,0xff,0xba,0x52,0x00,0xef,0xb9,0xff,0xff,0xba,0x58,0x00,0xed,0x25,0xef +,0x00,0x74,0x08,0xba,0x5a,0x00,0x33,0xc0,0xef,0xe2,0xef,0xc3,0xba,0x80,0x00,0xed +,0xba,0x84,0x00,0xef,0xba,0x80,0x00,0xed,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xc6,0x06,0xec,0x34,0x15,0x33,0xc0,0x8e,0xd8,0x8e,0xc0,0x1e,0x8c,0xc8,0xbe,0x40 +,0x54,0xbf,0x60,0xfe,0x8e,0xd8,0xb9,0x10,0x00,0xf3,0xa4,0x1f,0xc7,0x06,0x80,0x36 +,0x10,0x35,0xc7,0x06,0x8c,0x36,0x30,0x35,0x8d,0x06,0x38,0x35,0xa3,0x30,0x35,0xa3 +,0x32,0x35,0x05,0x33,0x01,0xa3,0x34,0x35,0xc7,0x06,0x36,0x35,0x50,0x01,0xc7,0x06 +,0x84,0x36,0x80,0xfe,0xc7,0x06,0x88,0x36,0xc0,0xfe,0xc6,0x06,0xc2,0xfe,0xff,0xc6 +,0x06,0x93,0x36,0x80,0xc6,0x06,0x92,0x36,0x00,0xc6,0x06,0x80,0xfe,0x80,0xc7,0x06 +,0x82,0xfe,0x54,0x50,0xc7,0x06,0x84,0xfe,0x2b,0x4d,0xe5,0xce,0xa9,0x02,0x00,0x75 +,0x08,0xc6,0x06,0x81,0xfe,0x23,0xe9,0x05,0x00,0xc6,0x06,0x81,0xfe,0x22,0xa1,0xf7 +,0x34,0xa3,0x86,0xfe,0xb8,0x48,0x34,0x86,0xe0,0xa3,0x88,0xfe,0x8d,0x06,0x4e,0x34 +,0x86,0xe0,0xa3,0x8a,0xfe,0xb8,0x58,0x34,0x86,0xe0,0xa3,0x8c,0xfe,0xb8,0x9c,0x34 +,0x86,0xe0,0xa3,0x8e,0xfe,0x8d,0x06,0x20,0x03,0x86,0xe0,0xa3,0x90,0xfe,0x33,0xc0 +,0xba,0x72,0x00,0xef,0x33,0xc0,0xba,0x74,0x00,0xef,0xba,0x76,0x00,0xef,0xb8,0x80 +,0xfe,0x86,0xe0,0xba,0x72,0x00,0xef,0xe8,0xbf,0x07,0xba,0x0c,0x01,0xb8,0x40,0x40 +,0xef,0xed,0xba,0x6a,0x00,0xb8,0x03,0x00,0xc1,0xe0,0x08,0x0d,0x03,0x00,0xef,0xb9 +,0x0a,0x00,0xe8,0x94,0x00,0xba,0x6a,0x00,0xb8,0x03,0x00,0xc1,0xe0,0x08,0xef,0xa1 +,0x32,0x34,0xa3,0xa2,0x33,0xc7,0x06,0xa6,0x33,0x04,0x00,0x8d,0x06,0xa0,0x33,0xc1 +,0xe8,0x04,0xcd,0x39,0xc7,0x06,0x90,0x36,0xff,0xff,0xe9,0xe3,0x00,0x63,0x0d,0x66 +,0x0d,0x66,0x0d,0x8a,0x0d,0xe6,0x0e,0x75,0x12,0x2e,0x0f,0x03,0x0f,0x50,0x0f,0x60 +,0x0d,0x60,0x0d,0x60,0x0d,0xed,0x0f,0xe9,0x12,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60 +,0x0d,0x60,0x0d,0x22,0x10,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0xfe,0x10,0x60 +,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0xaf,0x0f,0x32,0x10,0x37 +,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60 +,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60 +,0x0d,0x64,0x0e,0x00,0x0f,0x95,0x09,0x60,0x0a,0x49,0xbb,0xff,0xff,0xba,0x6a,0x00 +,0xed,0xa9,0x00,0x20,0x74,0x38,0x80,0x3e,0x80,0xfe,0x12,0x75,0x31,0xe8,0x4a,0x00 +,0xa1,0x32,0x34,0xa3,0xa2,0x33,0xc7,0x06,0xa6,0x33,0x04,0x00,0x8d,0x06,0xa0,0x33 +,0xc1,0xe8,0x04,0xcd,0x39,0xe8,0x22,0x00,0xc7,0x06,0xf3,0x34,0x46,0x00,0xc7,0x06 +,0xf5,0x34,0xff,0xff,0xc7,0x06,0x90,0x36,0xff,0xff,0x58,0xe9,0x32,0x00,0x4b,0x83 +,0xfb,0x00,0x75,0xb9,0x83,0xf9,0x00,0x75,0xb0,0xc3,0x52,0xba,0x6a,0x00,0xb8,0x03 +,0x00,0xc1,0xe0,0x08,0x0d,0x03,0x00,0xef,0x5a,0xc3,0x52,0xba,0x6a,0x00,0xb8,0x03 +,0x00,0xc1,0xe0,0x08,0xef,0x5a,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x68,0x80,0x07,0xa1,0x90,0x36,0xcd,0x35,0x8b,0x36,0x24,0x02,0x2e,0xff,0xa4,0x35 +,0x0a,0xfa,0x8a,0x26,0x94,0x36,0x88,0x26,0xe8,0x34,0xc6,0x06,0x94,0x36,0x00,0xfb +,0x22,0xe4,0x75,0x01,0xc3,0xf6,0xc4,0x20,0x74,0x7d,0xf6,0xc4,0x08,0x74,0x05,0x80 +,0x0e,0x92,0x36,0x04,0x80,0x26,0xe8,0x34,0xd7,0xc4,0x1e,0x84,0x36,0x26,0x8b,0x37 +,0x81,0xe6,0xff,0x00,0x83,0xfe,0x20,0x76,0x05,0xb0,0x01,0xe9,0x28,0x00,0x53,0x06 +,0xd1,0xe6,0x2e,0xff,0x94,0x9d,0x06,0x07,0x5b,0x26,0x88,0x47,0x02,0x3c,0xff,0x74 +,0x07,0x3c,0xfe,0x75,0x11,0xe9,0x3b,0x00,0xf6,0x06,0x92,0x36,0x08,0x75,0x34,0xf6 +,0x06,0x92,0x36,0x04,0x74,0x2d,0x80,0x26,0x92,0x36,0xf3,0x80,0x3e,0x95,0x36,0x00 +,0x75,0x21,0x26,0x80,0x3f,0x05,0x75,0x13,0xc6,0x06,0x95,0x36,0x00,0x26,0x80,0x7f +,0x06,0x00,0x74,0x07,0x26,0x8b,0x47,0x04,0xa2,0x95,0x36,0xba,0x0c,0x01,0xb8,0x40 +,0x40,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x10,0x75,0x03,0xe9,0x5b,0x00,0xf6 +,0xc4,0x04,0x74,0x05,0x80,0x0e,0x92,0x36,0x01,0x80,0x26,0xe8,0x34,0xeb,0xc4,0x3e +,0x88,0x36,0x26,0x8b,0x35,0x83,0xe6,0x7f,0x83,0xfe,0x12,0x72,0x08,0x26,0xc6,0x45 +,0x02,0x01,0xe9,0x24,0x00,0x83,0xc6,0x20,0xd1,0xe6,0x2e,0xff,0x94,0x9d,0x06,0xc4 +,0x3e,0x88,0x36,0x26,0x88,0x45,0x02,0x3c,0xff,0x75,0x0e,0xf6,0x06,0x92,0x36,0x01 +,0x74,0x14,0xf6,0x06,0x92,0x36,0x02,0x75,0x0d,0x80,0x26,0x92,0x36,0xfc,0xba,0x0c +,0x01,0xb8,0x20,0x20,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x08,0x74,0x22,0x80 +,0x26,0xe8,0x34,0xf7,0x80,0x0e,0x92,0x36,0x04,0xf6,0x06,0x92,0x36,0x08,0x74,0x11 +,0x80,0x26,0x92,0x36,0xf3,0xba,0x0c,0x01,0xb8,0x40,0x40,0xef,0xed,0x8a,0x26,0xe8 +,0x34,0xf6,0xc4,0x04,0x74,0x22,0x80,0x26,0xe8,0x34,0xfb,0x80,0x0e,0x92,0x36,0x01 +,0xf6,0x06,0x92,0x36,0x02,0x75,0x11,0x80,0x26,0x92,0x36,0xfe,0xba,0x0c,0x01,0xb8 +,0x20,0x20,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x01,0x74,0x67,0x80,0x26,0xe8 +,0x34,0xfe,0x80,0x3e,0xe8,0xff,0x00,0x74,0x39,0x80,0x3e,0xe8,0xff,0x04,0x74,0x32 +,0x80,0x3e,0xe8,0xff,0x01,0x75,0x21,0xe5,0x80,0xa9,0x00,0x07,0x74,0x0a,0xba,0x9e +,0x00,0xb8,0x00,0x02,0xef,0xe9,0xef,0xff,0xc6,0x06,0xe8,0xff,0x03,0xba,0x0c,0x01 +,0xb8,0x08,0x08,0xef,0xed,0xe9,0x28,0x00,0x80,0x3e,0xe8,0xff,0x03,0x74,0x06,0xe9 +,0x1e,0x00,0xe9,0x00,0x00,0xba,0x10,0x01,0xb8,0x02,0x02,0xef,0xed,0xe5,0x00,0x0d +,0x18,0x00,0xe7,0x00,0xe5,0x82,0x0d,0x02,0x00,0xe7,0x82,0xc6,0x06,0xe8,0xff,0x04 +,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x02,0x74,0x0d,0x80,0x26,0xe8,0x34,0xfd,0x80,0x26 +,0x92,0x36,0xbf,0xe8,0x4f,0x0b,0xfa,0xa0,0xe8,0x34,0x08,0x06,0x94,0x36,0xc6,0x06 +,0xe8,0x34,0x00,0xfb,0xc3,0xe8,0xe7,0x0f,0xc4,0x1e,0x84,0x36,0x2e,0xff,0x16,0x01 +,0x07,0x26,0x88,0x47,0x02,0xe9,0x7e,0xfe,0xe8,0x2d,0x10,0xc4,0x1e,0x84,0x36,0x2e +,0xff,0x16,0x03,0x07,0x26,0x88,0x47,0x02,0xe9,0x6b,0xfe,0x8e,0x06,0x26,0x02,0x2e +,0xff,0x16,0x07,0x07,0xc3,0xc3,0x83,0x3e,0xf5,0x34,0x00,0x74,0x0f,0xff,0x0e,0xf3 +,0x34,0x75,0x09,0xe8,0xc4,0xfd,0xc7,0x06,0xf5,0x34,0x00,0x00,0xf6,0x06,0x93,0x36 +,0x20,0x74,0x30,0xa1,0xc2,0x34,0x3b,0x06,0xe9,0x34,0xa3,0xe9,0x34,0x74,0x24,0x80 +,0x3e,0x95,0x36,0x00,0x75,0x1d,0xf7,0x06,0xe6,0x34,0x20,0x00,0x74,0x12,0xa9,0x20 +,0x00,0x74,0x0d,0x83,0x26,0xc2,0x34,0xdf,0x83,0x26,0xe9,0x34,0xdf,0xe9,0x03,0x00 +,0xe8,0xdd,0x09,0xba,0x06,0x01,0xed,0x8b,0xd0,0x81,0xe2,0x00,0xc0,0xc1,0xea,0x0e +,0x03,0x16,0x74,0x34,0xc1,0xe0,0x02,0x11,0x06,0x72,0x34,0x73,0x04,0xff,0x06,0x74 +,0x34,0xba,0x02,0x01,0xed,0x8b,0xd0,0x81,0xe2,0x00,0xc0,0xc1,0xea,0x0e,0x03,0x16 +,0x70,0x34,0xc1,0xe0,0x02,0x11,0x06,0x6e,0x34,0x73,0x04,0xff,0x06,0x70,0x34,0xc7 +,0x06,0xa6,0x33,0x04,0x00,0xc7,0x06,0xaa,0x33,0x00,0x00,0x8d,0x06,0xa0,0x33,0xc1 +,0xe8,0x04,0xcd,0x39,0xc3,0x95,0x09,0x95,0x09,0x65,0x09,0x78,0x09,0x95,0x09,0x95 +,0x09,0x91,0x07,0x95,0x09,0x96,0x09,0x8b,0x09,0x95,0x09,0x95,0x09,0x95,0x09,0x95 +,0x09,0x95,0x09,0x95,0x09,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x90 +,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xe9,0xcc,0x00,0x8c,0xc0,0x40,0x8e,0xc0,0x26 +,0x8b,0x0e,0x06,0x00,0x86,0xe9,0x26,0x89,0x0e,0x06,0x00,0x8c,0xc2,0xc1,0xe2,0x04 +,0xbe,0x0e,0x00,0x26,0xa1,0x04,0x00,0xd0,0xe0,0x24,0xc0,0x8a,0xe0,0xc0,0xec,0x04 +,0x0a,0xc4,0x26,0xa2,0x05,0x00,0x26,0xa1,0x08,0x00,0xa9,0x00,0xc0,0x74,0x03,0xe9 +,0x9e,0x00,0x26,0xf6,0x06,0x10,0x00,0x80,0x75,0x03,0xe9,0x0a,0x00,0x26,0xa0,0x16 +,0x00,0x24,0x1f,0x32,0xe4,0x03,0xf0,0x80,0x3e,0xec,0x34,0x06,0x72,0x5c,0x80,0x3e +,0x95,0x36,0x00,0x75,0x66,0x8b,0xfa,0x33,0xdb,0x8e,0xc3,0x26,0x89,0x1d,0x26,0x88 +,0x5d,0x04,0x51,0x50,0xc4,0x1e,0x8c,0x36,0xb9,0x0f,0x00,0x33,0xc0,0xe8,0x21,0x09 +,0x58,0x59,0x0b,0xdb,0x74,0x34,0xfe,0x0e,0xe6,0x3a,0x26,0xc6,0x07,0x81,0x26,0xc6 +,0x47,0x01,0x00,0x26,0xc6,0x47,0x02,0xff,0x26,0xc7,0x47,0x04,0x00,0x00,0x26,0x89 +,0x4f,0x0a,0x86,0xf2,0x26,0x89,0x57,0x06,0x26,0x89,0x77,0x08,0x26,0xc6,0x47,0x09 +,0x00,0x26,0xc6,0x47,0x0c,0x02,0xe8,0x8c,0x09,0xc3,0xff,0x06,0xec,0x33,0x8c,0xc0 +,0x48,0x8e,0xc0,0xfa,0xe8,0x97,0x10,0xfb,0xe9,0xeb,0xff,0x8c,0xc0,0x48,0x8e,0xc0 +,0xfa,0xe8,0x8a,0x10,0xfb,0xc3,0x8c,0xc0,0x8e,0xc0,0xfa,0xe8,0x80,0x10,0xfb,0xc3 +,0x80,0x3e,0x95,0x36,0x00,0x75,0x03,0xe9,0xc2,0x00,0xbf,0x08,0x00,0x26,0xf6,0x06 +,0x10,0x00,0x80,0x75,0x05,0x03,0xfe,0xe9,0x0c,0x00,0x26,0xa0,0x16,0x00,0x24,0x1f +,0x32,0xe4,0x03,0xf0,0x03,0xfe,0xa0,0x95,0x36,0x3c,0x00,0x75,0x03,0xe9,0x9c,0x00 +,0x3c,0x01,0x74,0x0b,0x3c,0x02,0x74,0x14,0x3c,0x03,0x74,0x1d,0xe9,0x8d,0x00,0xc6 +,0x06,0x96,0x36,0x01,0xe8,0x3c,0x01,0x72,0x27,0xe9,0x80,0x00,0xc6,0x06,0x96,0x36 +,0x02,0xe8,0x83,0x00,0x72,0x1a,0xe9,0x73,0x00,0xc6,0x06,0x96,0x36,0x01,0xe8,0x22 +,0x01,0x72,0x0d,0xc6,0x06,0x96,0x36,0x02,0xe8,0x6c,0x00,0x72,0x03,0xe9,0x5c,0x00 +,0x53,0x06,0x50,0xc4,0x1e,0x8c,0x36,0xb9,0x0b,0x00,0x33,0xc0,0xe8,0x42,0x08,0x58 +,0x26,0xc6,0x07,0x82,0x26,0xc6,0x47,0x02,0xff,0x8d,0x06,0xe0,0xfe,0x86,0xc4,0x26 +,0x89,0x47,0x06,0xa0,0x96,0x36,0x26,0x88,0x47,0x08,0xe8,0xc8,0x08,0x07,0x5b,0x83 +,0x26,0xad,0x36,0xfe,0xa1,0xad,0x36,0xe7,0x04,0xba,0x10,0x01,0xb8,0x80,0x80,0xef +,0xed,0xba,0x10,0x01,0xb8,0x02,0x02,0xef,0xed,0x52,0xba,0xe0,0x00,0xb8,0x41,0x10 +,0xef,0x5a,0xb8,0x9c,0x03,0xcd,0x39,0xc6,0x06,0x95,0x36,0x00,0x8c,0xc0,0x48,0x8e +,0xc0,0xfa,0xe8,0xa9,0x0f,0xfb,0xc3,0x1e,0x06,0x1f,0x06,0x33,0xc0,0x8e,0xc0,0x8b +,0xf0,0x8d,0x3e,0x20,0xf3,0x51,0xb1,0x0a,0x26,0x83,0x7d,0x0c,0x01,0x75,0x2a,0x57 +,0x26,0x83,0x7d,0x0e,0x00,0x74,0x06,0xe8,0x2f,0x00,0xe9,0x03,0x00,0xe8,0x66,0x07 +,0x5f,0x73,0x16,0x33,0xc0,0x8e,0xd8,0x26,0x8b,0x4d,0x12,0x8d,0x75,0x20,0x8d,0x3e +,0xe0,0xfe,0xf3,0xa4,0x59,0x07,0x1f,0xf9,0xc3,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20 +,0x01,0xe9,0xc4,0xff,0x59,0x07,0x1f,0xf8,0xc3,0x51,0x50,0x53,0x56,0x52,0x57,0x33 +,0xdb,0x26,0x8a,0x5d,0x0e,0x26,0x8b,0x4d,0x12,0x8d,0x7d,0x20,0x5a,0x87,0xd7,0x26 +,0x8a,0x45,0x14,0x87,0xd7,0x42,0x32,0xff,0x80,0xff,0x08,0x75,0x08,0xfe,0xcb,0x22 +,0xdb,0x75,0xea,0x33,0xdb,0x23,0xdb,0x74,0x06,0xfe,0xc7,0xd0,0xc8,0x73,0x0c,0x50 +,0x26,0x8a,0x05,0x38,0x04,0x58,0x74,0x03,0xe9,0x0a,0x00,0x49,0x46,0x47,0x23,0xc9 +,0x74,0x0a,0xe9,0xd3,0xff,0x5a,0x5e,0x5b,0x58,0x59,0xf8,0xc3,0x5a,0x5e,0x5b,0x58 +,0x59,0xf9,0xc3,0x1e,0x06,0x1f,0x06,0x33,0xc0,0x8e,0xc0,0x86,0xcd,0x2b,0xce,0x8b +,0xf7,0x8b,0xc1,0x33,0xc9,0x80,0x3c,0xff,0x74,0x16,0x80,0xf9,0x06,0x73,0x09,0x32 +,0xc9,0x46,0x48,0x74,0x2e,0xe9,0xed,0xff,0x3d,0x60,0x00,0x73,0x0c,0xe9,0x23,0x00 +,0xfe,0xc1,0x46,0x48,0x74,0x1d,0xe9,0xdc,0xff,0xb8,0x10,0x00,0x8d,0x3e,0x18,0x34 +,0x32,0xed,0xb1,0x06,0xf3,0xa6,0x74,0x03,0xe9,0x08,0x00,0x48,0x23,0xc0,0x74,0x07 +,0xe9,0xe9,0xff,0x07,0x1f,0xf8,0xc3,0x8d,0x36,0x18,0x34,0x33,0xc0,0x8e,0xd8,0x8d +,0x3e,0xe0,0xfe,0xb8,0x10,0x00,0xb9,0x06,0x00,0x56,0xf3,0xa4,0x5e,0x48,0x3d,0x00 +,0x00,0x75,0xf3,0x07,0x1f,0xf9,0xc3,0xff,0x06,0xe4,0x33,0xc6,0x06,0xeb,0x34,0x00 +,0x26,0x8b,0x45,0x06,0x86,0xe0,0xc1,0xe8,0x04,0x48,0x06,0x8e,0xc0,0xfe,0x06,0xe6 +,0x3a,0xfa,0xe8,0x69,0x0e,0xfb,0x07,0xb0,0xff,0xc3,0x00,0x00,0x00,0x00,0x00,0x00 +,0xb0,0x01,0xc3,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3 +,0x8b,0x0e,0x97,0x36,0x81,0xe1,0x80,0x30,0x26,0x8b,0x47,0x04,0x25,0x7f,0xcf,0x0b +,0xc1,0xa3,0x97,0x36,0xa3,0xe6,0x34,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x74 +,0x03,0xb0,0x03,0xc3,0x26,0x8b,0x47,0x08,0xa3,0x97,0x36,0xa3,0xe6,0x34,0x26,0x8a +,0x47,0x20,0xa2,0xfd,0x34,0x3c,0x01,0x75,0x06,0xc7,0x06,0xa1,0x36,0x00,0x00,0x26 +,0x8a,0x47,0x21,0xa2,0xfe,0x34,0x26,0x8b,0x47,0x0a,0xa3,0x18,0x34,0xa3,0x58,0x34 +,0x26,0x8b,0x47,0x0c,0xa3,0x1a,0x34,0xa3,0x5a,0x34,0x26,0x8b,0x47,0x0e,0xa3,0x1c +,0x34,0xa3,0x5c,0x34,0xc6,0x06,0x2a,0x34,0xc0,0x26,0x8b,0x47,0x14,0x25,0x7f,0xff +,0x09,0x06,0x2c,0x34,0x26,0x8b,0x47,0x16,0x25,0xff,0xfe,0x25,0xff,0xfc,0x09,0x06 +,0x2e,0x34,0xc6,0x06,0x00,0x34,0xc0,0x26,0x8b,0x47,0x10,0xa3,0x02,0x34,0x26,0x8b +,0x47,0x12,0xa3,0x04,0x34,0x06,0x53,0xe8,0x84,0x0a,0x5b,0x07,0x3d,0x00,0x00,0x75 +,0x07,0x80,0x0e,0x92,0x36,0x08,0xb0,0xfe,0xc3,0xb9,0x00,0x01,0xa1,0xac,0x33,0x33 +,0xd2,0xf7,0xf9,0xa3,0xae,0x33,0x91,0x49,0x33,0xd2,0xf7,0xe9,0x05,0x00,0x3b,0xa3 +,0x46,0x34,0xbf,0x00,0x3b,0x89,0x3e,0x44,0x34,0xba,0x68,0x00,0xb8,0xe0,0xe0,0xef +,0xa1,0xae,0x33,0xe7,0x62,0xa1,0xae,0x33,0xba,0x08,0x01,0xef,0xa1,0x44,0x34,0xe7 +,0x64,0xa1,0x44,0x34,0xba,0x0a,0x01,0xef,0xb8,0x00,0x01,0x2d,0x04,0x00,0x0d,0x00 +,0x10,0xe7,0x92,0xc3,0x3d,0x00,0x00,0x74,0x0a,0x26,0x89,0x47,0x07,0xe8,0x83,0x3a +,0xb0,0x07,0xc3,0xa1,0xae,0x33,0x26,0x89,0x47,0x2b,0xa1,0x44,0x34,0x26,0x89,0x47 +,0x2d,0xa1,0x46,0x34,0x26,0x89,0x47,0x2f,0x80,0x0e,0x93,0x36,0x20,0xa1,0x88,0x36 +,0x86,0xe0,0x26,0x89,0x47,0x08,0xa1,0x84,0x36,0x86,0xe0,0x26,0x89,0x47,0x0a,0xa1 +,0x80,0x36,0x86,0xe0,0x26,0x89,0x47,0x0c,0xb8,0x60,0xfe,0x86,0xe0,0x26,0x89,0x47 +,0x0e,0xa0,0xa1,0x36,0x26,0x88,0x47,0x10,0x8b,0x36,0x88,0x36,0x26,0xc6,0x44,0x02 +,0xff,0xe5,0x9e,0xa9,0x00,0x08,0x74,0x0c,0xba,0x84,0x00,0xed,0x0d,0x08,0x00,0xef +,0xba,0x8e,0x00,0xef,0xe5,0x02,0x25,0xf9,0xff,0xe7,0x02,0xba,0x10,0x01,0xb8,0x02 +,0x02,0xef,0xed,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x01,0xc3 +,0x80,0x26,0x93,0x36,0x9f,0xe8,0x8d,0x0a,0x80,0x0e,0x92,0x36,0x08,0xb0,0xfe,0xc3 +,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xc6,0x06,0x2a +,0x34,0xc0,0x26,0x8b,0x47,0x06,0x25,0x7f,0xff,0xa3,0x2c,0x34,0x26,0x8b,0x47,0x08 +,0x25,0xff,0xfe,0x25,0xff,0xfc,0xa3,0x2e,0x34,0xcd,0x52,0xb0,0x00,0xc3,0xf6,0x06 +,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xc6,0x06,0x00,0x34,0xc0,0x26,0x8b,0x47 +,0x06,0xa3,0x02,0x34,0x26,0x8b,0x47,0x08,0xa3,0x04,0x34,0xcd,0x52,0xb0,0x00,0xc3 +,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x57,0x8d,0x7f,0x06,0x51,0xb9 +,0x07,0x00,0x33,0xc0,0xf3,0xab,0x59,0x8d,0x7f,0x06,0xa1,0x7a,0x34,0x03,0x06,0x39 +,0x37,0x26,0x88,0x05,0xa1,0x95,0x37,0x26,0x88,0x45,0x02,0xa1,0x80,0x34,0x03,0x06 +,0x76,0x34,0x26,0x88,0x45,0x07,0xa1,0xc6,0x34,0x26,0x88,0x45,0x09,0xa1,0xd8,0x33 +,0x26,0x88,0x45,0x0a,0x33,0xc0,0xa3,0x7a,0x34,0xa3,0x39,0x37,0xa3,0x95,0x37,0xa3 +,0x80,0x34,0xa3,0x76,0x34,0xa3,0xc6,0x34,0xa3,0xd8,0x33,0x5f,0xb0,0x00,0xc3,0xf6 +,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x26,0x8b,0x4f,0x04,0x83,0xf9,0x06 +,0x74,0x12,0x83,0xf9,0x04,0x74,0x0d,0x83,0xf9,0x00,0x74,0x08,0x83,0xf9,0x02,0x74 +,0x03,0xb0,0x01,0xc3,0x89,0x0e,0xe8,0x3a,0x83,0x26,0xab,0x36,0xf9,0x09,0x0e,0xab +,0x36,0xe5,0x02,0x25,0xf9,0xff,0x0b,0xc1,0xe7,0x02,0xb0,0x00,0xc3,0xf6,0x06,0x93 +,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x26,0x8b,0x4f,0x04,0x80,0xf9,0xff,0x74,0x08 +,0x80,0xf9,0x00,0x74,0x10,0xb0,0x01,0xc3,0x83,0x0e,0xad,0x36,0x02,0xa1,0xad,0x36 +,0xe7,0x04,0xe9,0x0a,0x00,0x83,0x26,0xad,0x36,0xfd,0xa1,0xad,0x36,0xe7,0x04,0xb0 +,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xe8,0xd5,0x04,0xb0 +,0x00,0xc3,0xf6,0x06,0x93,0x36,0x80,0x75,0x03,0xb0,0x01,0xc3,0x26,0x83,0x7f,0x06 +,0x05,0x75,0x03,0xe9,0x9d,0x00,0x26,0x8b,0x57,0x04,0x26,0x8b,0x47,0x08,0x26,0x81 +,0x7f,0x06,0x00,0x80,0x75,0x08,0xed,0x26,0x89,0x47,0x0a,0xe9,0x9d,0x00,0x26,0x83 +,0x7f,0x06,0x01,0x75,0x04,0xef,0xe9,0x92,0x00,0x26,0x81,0x7f,0x06,0x01,0x80,0x75 +,0x09,0xef,0xed,0x26,0x89,0x47,0x0a,0xe9,0x81,0x00,0x26,0x83,0x7f,0x06,0x02,0x75 +,0x07,0x26,0x21,0x47,0x04,0xe9,0x73,0x00,0x26,0x81,0x7f,0x06,0x02,0x80,0x75,0x0c +,0x26,0x21,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x5f,0x00,0x26,0x83,0x7f,0x06 +,0x03,0x75,0x07,0x26,0x09,0x47,0x04,0xe9,0x51,0x00,0x26,0x81,0x7f,0x06,0x03,0x80 +,0x75,0x0c,0x26,0x09,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x3d,0x00,0x26,0x83 +,0x7f,0x06,0x04,0x75,0x07,0x26,0x31,0x47,0x04,0xe9,0x2f,0x00,0x26,0x81,0x7f,0x06 +,0x04,0x80,0x75,0x0c,0x26,0x31,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x1b,0x00 +,0xb0,0x01,0xc3,0xfa,0x53,0x26,0x8b,0x4f,0x08,0x0b,0xc9,0x74,0x0c,0x8d,0x1e,0xe0 +,0xfe,0xe8,0x52,0xff,0x83,0xc3,0x08,0xe2,0xf8,0x5b,0xfb,0xb0,0x00,0xc3,0xf6,0x06 +,0x93,0x36,0x80,0x75,0x0a,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x01,0xc3,0x8d +,0x3e,0xe0,0xfe,0xe5,0x00,0x26,0x89,0x05,0xe5,0x02,0x26,0x89,0x45,0x02,0xa1,0xad +,0x36,0x26,0x89,0x45,0x04,0xe5,0x06,0x26,0x89,0x45,0x06,0xe5,0x08,0x26,0x89,0x45 +,0x08,0xe5,0x0a,0x26,0x89,0x45,0x0a,0xe5,0x0e,0x26,0x89,0x45,0x0c,0xe5,0x48,0x26 +,0x89,0x45,0x0e,0xe5,0x4a,0x26,0x89,0x45,0x10,0xe5,0x4c,0x26,0x89,0x45,0x12,0xa1 +,0xb7,0x36,0x26,0x89,0x45,0x14,0xe5,0x50,0x26,0x89,0x45,0x16,0xe5,0x52,0x26,0x89 +,0x45,0x18,0xe5,0x54,0x26,0x89,0x45,0x1a,0xe5,0x56,0x26,0x89,0x45,0x1c,0xe5,0x58 +,0x26,0x89,0x45,0x1e,0xe5,0x62,0x26,0x89,0x45,0x20,0xe5,0x64,0x26,0x89,0x45,0x22 +,0xe5,0x66,0x26,0x89,0x45,0x24,0xe5,0x68,0x26,0x89,0x45,0x26,0xe5,0x6a,0x26,0x89 +,0x45,0x28,0xe5,0x6c,0x26,0x89,0x45,0x2a,0xe5,0x70,0x26,0x89,0x45,0x2c,0xe5,0x72 +,0x26,0x89,0x45,0x2e,0xe5,0x74,0x26,0x89,0x45,0x30,0xe5,0x76,0x26,0x89,0x45,0x32 +,0xe5,0x7c,0x26,0x89,0x45,0x34,0xe5,0x7e,0x26,0x89,0x45,0x36,0xe5,0x80,0x26,0x89 +,0x45,0x38,0xe5,0x82,0x26,0x89,0x45,0x3a,0xe5,0x86,0x26,0x89,0x45,0x3c,0xe5,0x88 +,0x26,0x89,0x45,0x3e,0xe5,0x9a,0x26,0x89,0x45,0x40,0xe5,0x9e,0x26,0x89,0x45,0x42 +,0xe5,0xcc,0x26,0x89,0x45,0x44,0xe5,0xce,0x26,0x89,0x45,0x46,0xe5,0xd0,0x26,0x89 +,0x45,0x48,0xe5,0xd2,0x26,0x89,0x45,0x4a,0xba,0x00,0x01,0xed,0x11,0x06,0x66,0x34 +,0x73,0x04,0xff,0x06,0x68,0x34,0x26,0x89,0x45,0x4c,0xba,0x02,0x01,0xed,0xc1,0xe0 +,0x02,0x11,0x06,0x6e,0x34,0x73,0x04,0xff,0x06,0x70,0x34,0x26,0x89,0x45,0x4e,0xba +,0x04,0x01,0xed,0x11,0x06,0x6a,0x34,0x73,0x04,0xff,0x06,0x6c,0x34,0x26,0x89,0x45 +,0x50,0xba,0x06,0x01,0xed,0xc1,0xe0,0x02,0x11,0x06,0x72,0x34,0x73,0x04,0xff,0x06 +,0x74,0x34,0x26,0x89,0x45,0x52,0xba,0x08,0x01,0xed,0x26,0x89,0x45,0x54,0xba,0x0a +,0x01,0xed,0x26,0x89,0x45,0x56,0xba,0x0c,0x01,0xed,0x26,0x89,0x45,0x58,0xba,0x0e +,0x01,0xed,0x01,0x06,0x7a,0x34,0x26,0x89,0x45,0x5e,0xba,0x10,0x01,0xed,0x26,0x89 +,0x45,0x5c,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x80,0x74,0x07,0xf6,0x06,0x93,0x36 +,0x20,0x75,0x03,0xb0,0x01,0xc3,0x26,0x80,0x7f,0x06,0x00,0x75,0x30,0x80,0x3e,0x95 +,0x36,0x00,0x74,0x52,0xc6,0x06,0x95,0x36,0x00,0x83,0x26,0xad,0x36,0xfe,0xa1,0xad +,0x36,0xe7,0x04,0xba,0x10,0x01,0xb8,0x80,0x80,0xef,0xed,0xba,0x10,0x01,0xb8,0x02 +,0x02,0xef,0xed,0xba,0xe0,0x00,0xb8,0x00,0x10,0xef,0xb0,0x00,0xc3,0x26,0x8b,0x47 +,0x04,0x3d,0x00,0x00,0x74,0x20,0x3d,0x03,0x00,0x77,0x1b,0xba,0x10,0x01,0xb8,0x02 +,0x00,0xef,0xba,0xe0,0x00,0xb8,0x01,0x10,0xef,0x83,0x0e,0xad,0x36,0x01,0xa1,0xad +,0x36,0xe7,0x04,0xb0,0x00,0xc3,0xb0,0x06,0xc3,0xf6,0x06,0x93,0x36,0x80,0x75,0x03 +,0xb0,0x01,0xc3,0x26,0x83,0x7f,0x04,0x01,0x74,0x0a,0x26,0x83,0x7f,0x04,0x02,0x74 +,0x19,0xb0,0x06,0xc3,0x26,0x83,0x7f,0x06,0x0c,0x77,0xf6,0x26,0x83,0x7f,0x0a,0x60 +,0x77,0xef,0xe8,0x10,0x00,0x72,0x0b,0xb0,0x46,0xc3,0xe8,0x4e,0x00,0x72,0x03,0xb0 +,0x46,0xc3,0xb0,0x00,0xc3,0x51,0xb1,0x0a,0x8b,0x3e,0x20,0xf3,0x26,0x83,0x7d,0x0c +,0x02,0x75,0x03,0xe9,0x0e,0x00,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20,0x01,0xe9,0xeb +,0xff,0x59,0xf8,0xc3,0x57,0x8d,0x7d,0x0e,0x8d,0x77,0x06,0xb9,0x12,0x00,0xf3,0xa4 +,0x8d,0x7d,0x20,0x8d,0x36,0xe0,0xfe,0x26,0x8b,0x4d,0x12,0xf3,0xa4,0xff,0x06,0x01 +,0x35,0x5f,0x26,0xc7,0x45,0x0c,0x01,0x00,0x59,0xf9,0xc3,0x51,0xb1,0x0a,0x8d,0x3e +,0x20,0xf3,0x8d,0x36,0xe0,0xfe,0x26,0x83,0x7d,0x0c,0x01,0x75,0x1b,0x57,0xe8,0x25 +,0x00,0x5f,0x73,0x14,0x33,0xc0,0xb9,0x20,0x01,0xf3,0xaa,0x26,0xc7,0x45,0x0c,0x02 +,0x00,0xff,0x0e,0x01,0x35,0x59,0xf9,0xc3,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20,0x01 +,0xe9,0xd3,0xff,0x59,0xf8,0xc3,0x51,0x26,0x8b,0x4d,0x12,0x8d,0x7d,0x20,0xf3,0xa6 +,0x74,0x03,0x59,0xf8,0xc3,0x59,0xf9,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x80,0x3e,0xec,0x34,0x06,0x72,0x33,0xff,0x06,0xf0,0x33,0x50,0xc4,0x1e,0x8c,0x36 +,0xb9,0x0f,0x00,0x33,0xc0,0xe8,0x29,0x00,0x58,0x81,0x26,0xc2,0x34,0xdf,0x7f,0x81 +,0x26,0xe9,0x34,0xdf,0x7f,0x0b,0xdb,0x74,0x11,0x26,0xc6,0x07,0x84,0x26,0xc6,0x47 +,0x02,0xff,0x26,0x89,0x47,0x06,0xe8,0xac,0x00,0xc3,0xff,0x06,0xea,0x33,0xe9,0xf5 +,0xff,0x57,0x26,0x8b,0x3f,0x03,0xf9,0x26,0x3b,0x7f,0x02,0x74,0x16,0x26,0x3b,0x7f +,0x04,0x7c,0x2a,0x3d,0x00,0x00,0x75,0x13,0x8d,0x7f,0x08,0x03,0xf9,0x26,0x3b,0x7f +,0x02,0x7c,0x14,0xff,0x06,0xde,0x33,0x33,0xdb,0x5f,0xc3,0x26,0x8b,0x7f,0x02,0x26 +,0x89,0x3f,0x03,0xf9,0xe9,0x06,0x00,0x26,0x89,0x3f,0x26,0x29,0x0f,0x26,0xc7,0x05 +,0xff,0xff,0x26,0x87,0x3f,0x26,0x89,0x0d,0x8d,0x5d,0x02,0x50,0x8b,0xfb,0x83,0xe9 +,0x02,0x33,0xc0,0xf3,0xaa,0x58,0xfe,0x0e,0xec,0x34,0x5f,0xc3,0x8b,0x7c,0x02,0x3b +,0x3c,0x74,0x2f,0x83,0x3d,0xff,0x75,0x0b,0x8d,0x7c,0x08,0x89,0x7c,0x02,0x83,0x3d +,0xff,0x74,0x1e,0x8a,0x45,0x02,0x3c,0x81,0x75,0x0c,0x80,0x3e,0xeb,0x34,0x00,0x74 +,0x05,0x33,0xc0,0xe9,0x0b,0x00,0x8b,0x0d,0x01,0x4c,0x02,0x8d,0x75,0x02,0x83,0xe9 +,0x02,0xc3,0x80,0x3e,0xec,0x34,0x06,0x72,0x05,0x33,0xc0,0xe9,0xf3,0xff,0xff,0x06 +,0xee,0x33,0xe9,0xbe,0xff,0xf6,0x06,0x92,0x36,0x40,0x74,0x01,0xc3,0x57,0x56,0x51 +,0x52,0x8b,0x36,0x8c,0x36,0xe8,0xa4,0xff,0x75,0x03,0xe9,0x1a,0x00,0xe9,0x1c,0x00 +,0xfe,0x06,0xec,0x34,0xc4,0x3e,0x80,0x36,0xf3,0xa4,0x80,0x0e,0x92,0x36,0x40,0xba +,0x0c,0x01,0xb8,0x80,0x80,0xef,0xed,0x5a,0x59,0x5e,0x5f,0xc3,0xff,0x06,0xe0,0x33 +,0x80,0x3c,0x81,0x75,0x0c,0xff,0x06,0xe2,0x33,0xc6,0x06,0xeb,0x34,0x01,0xe9,0xcf +,0xff,0x80,0x3c,0x84,0x75,0x07,0xff,0x06,0xe6,0x33,0xe9,0xc3,0xff,0xff,0x06,0xe8 +,0x33,0xe9,0xbc,0xff,0x8d,0x3e,0xe0,0xfe,0xa1,0x72,0x34,0xc7,0x06,0x72,0x34,0x00 +,0x00,0x89,0x05,0xa1,0x74,0x34,0xc7,0x06,0x74,0x34,0x00,0x00,0x89,0x45,0x02,0xba +,0x04,0x01,0xed,0x89,0x45,0x04,0xc7,0x45,0x06,0x00,0x00,0xa1,0x6e,0x34,0xc7,0x06 +,0x6e,0x34,0x00,0x00,0x89,0x45,0x08,0xa1,0x70,0x34,0xc7,0x06,0x70,0x34,0x00,0x00 +,0x89,0x45,0x0a,0xba,0x00,0x01,0xed,0x89,0x45,0x0c,0xc7,0x45,0x0e,0x00,0x00,0x32 +,0xe4,0xba,0x0e,0x01,0xec,0x89,0x45,0x10,0xa1,0x7e,0x34,0xc7,0x06,0x7e,0x34,0x00 +,0x00,0x89,0x45,0x12,0xa1,0x8c,0x34,0xc7,0x06,0x8c,0x34,0x00,0x00,0x89,0x45,0x14 +,0xa1,0x8a,0x34,0xc7,0x06,0x8a,0x34,0x00,0x00,0x89,0x45,0x16,0xa1,0x7c,0x34,0xc7 +,0x06,0x7c,0x34,0x00,0x00,0x89,0x45,0x18,0xa1,0x88,0x34,0xc7,0x06,0x88,0x34,0x00 +,0x00,0x89,0x45,0x1a,0xa1,0xca,0x33,0xc7,0x06,0xca,0x33,0x00,0x00,0x89,0x45,0x1c +,0xa1,0x78,0x34,0xc7,0x06,0x78,0x34,0x00,0x00,0x89,0x45,0x1e,0xa1,0xc6,0x34,0xc7 +,0x06,0xc6,0x34,0x00,0x00,0x89,0x45,0x20,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xfa,0x33,0xc0,0x8e,0xd8,0x8e,0xc0,0xb8,0xa0,0x01,0xc1,0xe8,0x04,0x8e,0xd0,0x8d +,0x26,0x80,0x00,0xe8,0x00,0x01,0xe8,0x10,0xeb,0x8b,0x1e,0xf7,0x34,0x8b,0x16,0xf9 +,0x34,0x8b,0x36,0xff,0x34,0x33,0xc0,0xb9,0xef,0xff,0x8d,0x3e,0x14,0x00,0x2b,0xcf +,0x2b,0xce,0xd1,0xe9,0xf3,0xab,0x89,0x1e,0xf7,0x34,0x89,0x16,0xf9,0x34,0x83,0xfe +,0x00,0x74,0x0c,0xb9,0xef,0xff,0xbf,0x80,0xfe,0x2b,0xcf,0xd1,0xe9,0xf3,0xab,0xb9 +,0xff,0xff,0x81,0xe9,0x00,0x3b,0x83,0xfe,0x00,0x74,0x03,0xe9,0x1b,0x00,0x51,0x1e +,0xb8,0x00,0xe0,0x8e,0xd8,0x33,0xf6,0x8d,0x3e,0x00,0xd8,0xb9,0x00,0x0c,0xf3,0xa5 +,0x1f,0x59,0xbe,0xff,0xff,0x81,0xee,0x00,0xd8,0x2b,0xce,0x81,0xe1,0x00,0xff,0x89 +,0x0e,0xac,0x33,0x8d,0x06,0x20,0x02,0xc1,0xe8,0x04,0xa3,0x32,0x34,0x8e,0xd0,0x36 +,0xc7,0x06,0x1e,0x00,0x80,0x18,0x36,0xc7,0x06,0x22,0x00,0xff,0x7f,0x36,0xc7,0x06 +,0x0a,0x00,0xff,0xff,0x36,0xc7,0x06,0x1c,0x00,0x80,0x00,0x8d,0x06,0xa0,0x02,0xc1 +,0xe8,0x04,0xa3,0x30,0x34,0x8e,0xd0,0x36,0xc7,0x06,0x1e,0x00,0x50,0x28,0x36,0xc7 +,0x06,0x0a,0x00,0xff,0xff,0x36,0xc7,0x06,0x1c,0x00,0x80,0x00,0xb8,0xa0,0x01,0xc1 +,0xe8,0x04,0xa3,0x34,0x34,0xa3,0xf2,0x33,0x8e,0xd0,0x8d,0x26,0x80,0x00,0xb8,0x00 +,0x90,0xe7,0x02,0x8d,0x3e,0x70,0x01,0x8b,0xc7,0xc1,0xe8,0x04,0xb9,0x03,0x00,0x89 +,0x45,0x0e,0x89,0x45,0x02,0xc7,0x05,0xff,0xff,0x83,0xc7,0x10,0x05,0x01,0x00,0xe2 +,0xee,0xe8,0x5b,0x01,0xe5,0xce,0xa3,0xb5,0x36,0xe8,0x21,0x00,0xe8,0x45,0x01,0xa1 +,0x32,0x34,0x8c,0xcb,0xcd,0x37,0x0e,0x58,0xa9,0x00,0xf0,0x74,0x07,0x33,0xf6,0x89 +,0x36,0xff,0x34,0xc3,0x8d,0x36,0x30,0x61,0x89,0x36,0xff,0x34,0xc3,0x33,0xc0,0x8b +,0xd0,0x8b,0xf2,0xb9,0x68,0x00,0x2e,0x80,0xbc,0xac,0x17,0x80,0x75,0x01,0xef,0x83 +,0xc2,0x02,0x46,0xe2,0xf1,0xb8,0x02,0x00,0xe7,0x50,0xb9,0x5a,0x00,0x33,0xff,0xc7 +,0x05,0x65,0x18,0x8c,0x4d,0x02,0x83,0xc7,0x04,0xe2,0xf4,0x33,0xc0,0x8e,0xc0,0x8c +,0xc8,0x8e,0xd8,0x8d,0x3e,0x80,0x00,0x8d,0x36,0x9c,0x17,0xb9,0x08,0x00,0xe8,0x37 +,0x00,0x8d,0x36,0x20,0x21,0x8d,0x3e,0xc0,0x00,0xb9,0x0d,0x00,0xe8,0x29,0x00,0x8d +,0x3e,0x40,0x01,0xb9,0x0a,0x00,0xe8,0x1f,0x00,0xe8,0x4b,0x0e,0x33,0xc0,0x8e,0xd8 +,0xc7,0x06,0x4e,0x37,0x6f,0x17,0xe7,0x48,0xe7,0x4c,0xb8,0x40,0x9c,0xe7,0x4a,0xe5 +,0x48,0x90,0xb8,0x00,0x70,0xe7,0x48,0xc3,0xa5,0x83,0xc7,0x02,0xe2,0xfa,0xc3,0xe5 +,0x4c,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe5,0x58,0xd1 +,0xe0,0x73,0x11,0x8b,0xf0,0xd1,0xe6,0x33,0xc0,0x8e,0xd8,0x8b,0xb4,0x80,0x00,0x83 +,0xc6,0x0b,0xff,0xe6,0x1f,0x07,0x5a,0x5f,0x5e,0x59,0x58,0xcf,0x58,0x1c,0xe4,0x1c +,0x6c,0x1c,0x8e,0x1a,0xc0,0x1f,0x40,0x1a,0x44,0x1c,0x65,0x18,0x80,0x80,0x80,0xff +,0x80,0x03,0x02,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +,0x80,0x03,0x03,0x43,0x80,0x80,0x02,0x80,0x42,0x03,0x02,0xff,0x03,0x01,0x03,0x01 +,0x01,0x03,0x02,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x02,0x03,0x01,0x03 +,0x03,0xff,0x01,0x01,0xff,0x01,0xff,0x01,0x01,0x03,0x03,0x03,0xff,0xff,0xff,0xff +,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +,0xff,0xff,0xff,0x02,0xb8,0x0f,0x00,0xe7,0x84,0xb8,0x0f,0xf8,0xe7,0x82,0xc3,0xb9 +,0x08,0x00,0x89,0x0e,0xe6,0x3a,0x8d,0x06,0x20,0x03,0x8b,0xd0,0xc1,0xe8,0x04,0xa3 +,0x90,0x01,0x8b,0xc2,0x8b,0xd8,0xc1,0xe8,0x04,0x8e,0xc0,0x05,0x61,0x00,0x26,0xa3 +,0x00,0x00,0xa1,0x30,0x34,0x26,0xa3,0x02,0x00,0x83,0xc3,0x14,0xd1,0xeb,0x26,0x89 +,0x1e,0x08,0x00,0x81,0xc2,0x10,0x06,0xe2,0xd9,0x26,0xc7,0x06,0x00,0x00,0xff,0xff +,0x8c,0x06,0x92,0x01,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8 +,0xe7,0x5a,0xff,0x06,0xbe,0x33,0xba,0xd2,0x00,0xed,0xcf,0x00,0x00,0x00,0x00,0x00 +,0x8c,0xcb,0xa1,0x30,0x34,0xcd,0x37,0xe9,0x06,0xed,0xb8,0x32,0x00,0xc3,0xe8,0x8c +,0x01,0xfe,0x06,0xe2,0x34,0xe8,0x21,0x01,0x75,0xf0,0xe8,0x53,0x0e,0x81,0x0e,0xaf +,0x36,0x00,0xc0,0xc7,0x06,0xad,0x36,0x60,0x00,0xf7,0x06,0xe6,0x34,0x80,0x00,0x75 +,0x1a,0xf7,0x06,0xe6,0x34,0x00,0x08,0x74,0x09,0xc7,0x06,0xab,0x36,0x0b,0x00,0xe9 +,0x0f,0x00,0xc7,0x06,0xab,0x36,0x03,0x00,0xe9,0x06,0x00,0xc7,0x06,0xab,0x36,0x11 +,0x9c,0xc7,0x06,0xa9,0x36,0x18,0x00,0xf7,0x06,0xe6,0x34,0x80,0x00,0x75,0x0d,0xf7 +,0x06,0xb5,0x36,0x02,0x00,0x74,0x05,0x83,0x0e,0xa9,0x36,0x20,0xa1,0xa9,0x36,0xe7 +,0x00,0xa1,0xab,0x36,0xe7,0x02,0xf7,0x06,0xe6,0x34,0x80,0x00,0x74,0x2e,0xe8,0xf2 +,0x2f,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56,0xa1,0xb1,0x36,0x0d,0x00,0x10,0xe7,0x08 +,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xb8,0x40,0x00,0xe7,0x4e,0x33 +,0xc0,0xe7,0x0e,0xc7,0x06,0x26,0x02,0x00,0x00,0xe9,0x23,0x00,0xc7,0x06,0x4e,0x37 +,0x3f,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x80,0x74,0x07,0x26 +,0x81,0x0e,0x08,0x00,0x00,0x80,0xc6,0x06,0xe0,0x34,0x01,0xb8,0x00,0x00,0xc3,0xfe +,0x06,0xe1,0x34,0xc6,0x06,0xe0,0x34,0x00,0xa1,0x26,0x02,0x0b,0xc0,0x74,0x01,0xc3 +,0xe8,0x04,0x00,0xb8,0x00,0x00,0xc3,0xa1,0xa9,0x36,0xe7,0x00,0x8b,0x1e,0xab,0x36 +,0x83,0xe3,0x06,0xe5,0x02,0x25,0xf9,0xff,0x0b,0xc3,0x0d,0x10,0x00,0xe7,0x02,0xa1 +,0xad,0x36,0xe7,0x04,0xc3,0xb8,0x0a,0x00,0xe7,0x84,0xfe,0x06,0xe5,0x34,0xc6,0x06 +,0xe3,0x34,0x01,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x40,0x74,0x07 +,0x26,0x81,0x0e,0x08,0x00,0x00,0x40,0xc3,0xc7,0x06,0x4e,0x37,0x6f,0x17,0xfe,0x06 +,0xe4,0x34,0xc6,0x06,0xe3,0x34,0x00,0xc3,0xc3,0xf6,0x06,0x18,0x34,0x80,0x75,0x0d +,0xa1,0x18,0x34,0x0b,0x06,0x1a,0x34,0x0b,0x06,0x1c,0x34,0x75,0x01,0xc3,0xa1,0x2e +,0x34,0x25,0xff,0xfe,0x8b,0x16,0xe7,0x36,0x81,0xe2,0x00,0x01,0x0b,0xc2,0xa3,0x2e +,0x34,0x8d,0x16,0x10,0x00,0xbf,0x00,0x00,0xb9,0x08,0x00,0x8b,0x85,0x00,0x34,0xef +,0x83,0xc2,0x10,0x8b,0x85,0x02,0x34,0xef,0x83,0xc2,0x10,0x8b,0x85,0x04,0x34,0xef +,0x83,0xc2,0xe2,0x83,0xc7,0x06,0x49,0x75,0xe2,0xb8,0x00,0x00,0x8e,0xc0,0xbe,0x00 +,0x34,0xbf,0xb9,0x36,0xb9,0x18,0x00,0xf3,0xa5,0xb8,0x00,0x00,0xc3,0x33,0xc0,0x8e +,0xc0,0x8d,0x3e,0xb0,0x33,0xb9,0x08,0x00,0xf3,0xab,0x8d,0x3e,0x3e,0x34,0xb9,0x03 +,0x00,0xf3,0xab,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xba +,0x33,0xe5,0x56,0x0d,0x20,0x00,0xe7,0x56,0xba,0x7a,0x00,0xed,0x08,0x26,0x94,0x36 +,0x33,0xc0,0xb1,0x08,0x32,0xed,0x06,0x8e,0xc0,0x8d,0x3e,0xe0,0xff,0xf3,0xaa,0x8e +,0x06,0x32,0x34,0x26,0x81,0x0e,0x08,0x00,0x00,0x02,0x07,0xe5,0x56,0x25,0xdf,0xff +,0xe7,0x56,0xe9,0xf8,0xfc,0x00,0xbd,0x1b,0x10,0x1b,0xd9,0x1a,0xf3,0x1a,0x50,0x51 +,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb6,0x33,0x53 +,0x06,0x51,0xe5,0x80,0xa3,0xb4,0x33,0x8b,0xd8,0x8b,0xc8,0x25,0x10,0x00,0xa3,0xed +,0x34,0x0b,0xc0,0x74,0x14,0xff,0x06,0x80,0x34,0x80,0x3e,0xfe,0x34,0x00,0x74,0x03 +,0xe9,0x06,0x00,0xb8,0x80,0x00,0xe8,0x9d,0x04,0x83,0xe3,0x03,0xd1,0xe3,0x2e,0xff +,0x97,0x86,0x1a,0x59,0x07,0x5b,0xe9,0xa4,0xfc,0xba,0x20,0x00,0x8e,0x06,0x3c,0x34 +,0x83,0x3e,0x3c,0x34,0x00,0x75,0x03,0xe9,0xf0,0x00,0xc7,0x06,0x3c,0x34,0x00,0x00 +,0xe9,0x2a,0x00,0xba,0x10,0x00,0x8e,0x06,0x3a,0x34,0x83,0x3e,0x3a,0x34,0x00,0x75 +,0x03,0xe9,0xd5,0xff,0xc7,0x06,0x3a,0x34,0x00,0x00,0xe8,0x10,0x00,0xe9,0xc9,0xff +,0xba,0x10,0x00,0x8e,0x06,0x3a,0x34,0xc7,0x06,0x3a,0x34,0x00,0x00,0x26,0xa1,0x14 +,0x00,0x26,0xa3,0x0c,0x00,0x26,0xa1,0x16,0x00,0x26,0xa3,0x0e,0x00,0x26,0xc6,0x06 +,0x0a,0x00,0x00,0xc1,0xea,0x02,0x23,0xd1,0x74,0x1c,0xba,0x20,0x00,0x26,0xc7,0x06 +,0x0e,0x00,0xea,0x05,0x26,0x0b,0x16,0x0c,0x00,0x26,0x89,0x16,0x0c,0x00,0xff,0x06 +,0x86,0x34,0xff,0x06,0xdc,0x33,0x26,0xa1,0x0c,0x00,0xa9,0x00,0x37,0x74,0x16,0x26 +,0xc6,0x06,0x0a,0x00,0x02,0xa9,0x00,0x30,0x74,0x04,0xff,0x06,0x7a,0x34,0xff,0x06 +,0xda,0x33,0xe9,0x49,0x00,0xc0,0xec,0x07,0x83,0x16,0x8a,0x34,0x00,0x24,0x07,0x3c +,0x07,0x75,0x04,0xff,0x06,0x8c,0x34,0xff,0x06,0x7e,0x34,0xa1,0x30,0x34,0x8c,0xc3 +,0x8e,0xc0,0x8e,0xdb,0x26,0x83,0x0e,0x08,0x00,0x40,0x8c,0xd8,0x26,0x87,0x06,0x16 +,0x00,0x26,0x83,0x3e,0x14,0x00,0xff,0x74,0x0a,0x8e,0xc0,0x26,0x8c,0x1e,0x00,0x00 +,0xe9,0x05,0x00,0x26,0x8c,0x1e,0x14,0x00,0x33,0xc0,0x8e,0xd8,0xc3,0xc3,0x8c,0xc0 +,0x87,0x06,0x92,0x01,0x3d,0xff,0xff,0x74,0x0d,0x8e,0xd8,0x8c,0x06,0x00,0x00,0x33 +,0xc0,0x8e,0xd8,0xe9,0x04,0x00,0x8c,0x06,0x90,0x01,0xe8,0x01,0x00,0xc3,0x06,0x83 +,0x3e,0x90,0x01,0xff,0x74,0x29,0x83,0x3e,0x3a,0x34,0x00,0x75,0x11,0xba,0x86,0x00 +,0xe8,0x1e,0x00,0x8c,0x06,0x3a,0x34,0x83,0x3e,0x90,0x01,0xff,0x74,0x11,0x83,0x3e +,0x3c,0x34,0x00,0x75,0x0a,0xba,0x88,0x00,0xe8,0x06,0x00,0x8c,0x06,0x3c,0x34,0x07 +,0xc3,0xa1,0x90,0x01,0x8e,0xc0,0x26,0xa1,0x08,0x00,0xef,0x26,0xa1,0x00,0x00,0x26 +,0xc7,0x06,0x00,0x00,0xff,0xff,0xa3,0x90,0x01,0x3d,0xff,0xff,0x75,0x03,0xa3,0x92 +,0x01,0x83,0x3e,0xed,0x34,0x00,0x74,0x0b,0xb8,0x10,0x00,0xe7,0x84,0xc7,0x06,0xed +,0x34,0x00,0x00,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7 +,0x5a,0xff,0x06,0xbc,0x33,0xe9,0x25,0xfb,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33 +,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb0,0x33,0xe9,0x11,0xfb,0x50,0x51,0x56,0x57 +,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb4,0x33,0x06,0xff,0x06 +,0x76,0x34,0x80,0x3e,0xfe,0x34,0x00,0x74,0x04,0x07,0xe9,0xf0,0xfa,0xb8,0x80,0x00 +,0xe8,0xd3,0x02,0x07,0xe9,0xe6,0xfa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xc6,0x1d,0x08,0x1d,0x91,0x1e,0x5d,0x1e,0x73,0x1e,0x89,0x1e,0x91,0x1e,0xa8,0x1d +,0x91,0x1e,0x91,0x1e,0xaf,0x1e,0xaf,0x1e,0x15,0x1d,0x15,0x1d,0x91,0x1e,0x99,0x1f +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x02,0x00,0x00 +,0x00,0x01,0x00,0x10,0x00,0x01,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00 +,0x07,0xe9,0x99,0xfa,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7 +,0x5a,0xff,0x06,0xb2,0x33,0x06,0x68,0xf6,0x1c,0xe5,0x06,0xa3,0xb2,0x33,0x8b,0xf0 +,0x83,0xe6,0x1e,0x2e,0xff,0xa4,0xa0,0x1c,0xe5,0x0c,0xa9,0x80,0x00,0x74,0x06,0xe8 +,0xa4,0x01,0xe5,0x06,0xc3,0x53,0xe5,0x0c,0x8b,0xd8,0xa9,0x01,0x00,0x74,0x14,0x83 +,0x3e,0xe0,0x3a,0x00,0x74,0x0d,0x8e,0x06,0x38,0x34,0xe8,0xbf,0x06,0xc7,0x06,0xe0 +,0x3a,0x00,0x00,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7 +,0x02,0x8b,0xc3,0x5b,0xa9,0x01,0x00,0x74,0x01,0xc3,0x8b,0xd0,0xb8,0x00,0x08,0xe7 +,0x84,0x8b,0xc2,0x8e,0x06,0x38,0x34,0x26,0xa3,0x0c,0x00,0x8b,0xd0,0xc1,0xe0,0x03 +,0x83,0x16,0x88,0x34,0x00,0xff,0x06,0x7c,0x34,0x26,0x83,0x3e,0x06,0x00,0x0a,0x75 +,0x21,0x8b,0xc2,0x25,0x40,0x18,0x3d,0x40,0x00,0x74,0x0c,0x3d,0x00,0x10,0x75,0x12 +,0x26,0xfe,0x0e,0x0a,0x00,0x74,0x0b,0xf7,0x06,0xef,0x34,0x20,0x00,0x75,0x03,0xe9 +,0x5a,0x06,0x8c,0xc0,0x26,0x8e,0x06,0x02,0x00,0x26,0x83,0x0e,0x08,0x00,0x20,0x26 +,0xa3,0x12,0x00,0x26,0xa3,0x10,0x00,0xc3,0xff,0x06,0xc4,0x33,0xe5,0x0c,0xa9,0x01 +,0x00,0x75,0x01,0xc3,0xa9,0xf0,0x07,0x74,0x01,0xc3,0xff,0x06,0xd4,0x33,0xe5,0x00 +,0x0d,0x18,0x00,0xe7,0x00,0xc3,0xff,0x06,0xca,0x33,0x80,0x3e,0xa0,0x36,0x08,0x75 +,0x14,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x08,0x74,0x07,0x26,0x81 +,0x0e,0x08,0x00,0x00,0x08,0xe5,0x82,0x25,0xfd,0xff,0xe7,0x82,0xe5,0x0c,0x50,0xe5 +,0x80,0x25,0x00,0x07,0xa3,0xe4,0x3a,0xe5,0x8c,0x25,0x00,0x80,0xa3,0xe2,0x3a,0x58 +,0xa9,0x02,0x00,0x75,0x25,0x83,0x3e,0xe2,0x3a,0x00,0x75,0x1e,0x83,0x3e,0xe4,0x3a +,0x00,0x75,0x17,0xe5,0x08,0x0d,0x00,0x04,0x25,0xff,0x04,0xe7,0x08,0xe8,0x6a,0x01 +,0xe5,0x82,0x0d,0x02,0x00,0xe7,0x82,0xe9,0x21,0x00,0xe8,0x1a,0x06,0x80,0x3e,0xe8 +,0xff,0x00,0x74,0x0a,0x80,0x3e,0xe8,0xff,0x04,0x74,0x03,0xe9,0x0d,0x00,0xc6,0x06 +,0xe8,0xff,0x01,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0x80,0x3e,0x9f,0x36,0x06 +,0x75,0x05,0x83,0x0e,0x99,0x36,0x40,0xb8,0x00,0x01,0xe9,0x09,0x01,0xff,0x06,0xcc +,0x33,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36,0xe7,0x06,0xff,0x06,0xc6,0x34 +,0xe9,0x1e,0x00,0xff,0x06,0xce,0x33,0xff,0x06,0x95,0x37,0x81,0x26,0xaf,0x36,0xff +,0xef,0xa1,0xaf,0x36,0xe7,0x06,0xe9,0x08,0x00,0xff,0x06,0xd0,0x33,0xff,0x06,0x7a +,0x34,0xff,0x06,0xd2,0x33,0xd1,0xe6,0x8e,0x06,0x30,0x34,0x2e,0x8b,0x84,0xc0,0x1c +,0x26,0x09,0x06,0x08,0x00,0x2e,0x8b,0x84,0xc2,0x1c,0x09,0x06,0x66,0x37,0xc3,0xe5 +,0x0c,0xa9,0x80,0x00,0x74,0x56,0x50,0xe8,0xf0,0x00,0x58,0xa9,0x00,0x01,0x75,0x07 +,0xff,0x06,0xc6,0x33,0xe9,0x08,0x00,0xff,0x06,0x78,0x34,0xff,0x06,0xc8,0x33,0xe5 +,0x82,0x25,0xfd,0xff,0xe7,0x82,0xe8,0x6e,0x05,0xba,0x10,0x01,0xed,0x80,0x3e,0xe8 +,0xff,0x00,0x74,0x0a,0x80,0x3e,0xe8,0xff,0x04,0x74,0x03,0xe9,0x1d,0x00,0xc6,0x06 +,0xe8,0xff,0x01,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0xe9,0x0d,0x00,0xc6,0x06 +,0xe8,0xff,0x03,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0xc3,0xa9,0x01,0x00,0x74 +,0x1c,0xe8,0x2c,0x00,0x83,0x3e,0xe0,0x3a,0x00,0x74,0x0f,0x06,0x8e,0x06,0x38,0x34 +,0xe8,0xc9,0x04,0xc7,0x06,0xe0,0x3a,0x00,0x00,0x07,0xe9,0x5d,0x00,0x8b,0xd0,0x8e +,0x06,0x38,0x34,0x26,0xa3,0x0c,0x00,0xe8,0x06,0x00,0x68,0x69,0x1d,0xe9,0x4a,0x00 +,0xa9,0x00,0x04,0x74,0x0a,0xb8,0x00,0x04,0xff,0x06,0xd8,0x33,0xe9,0x17,0x00,0xa9 +,0x00,0x01,0x74,0x0a,0xff,0x06,0x39,0x37,0xb8,0x00,0x01,0xe9,0x08,0x00,0xa9,0x10 +,0x00,0xb8,0x10,0x00,0x74,0x1d,0x09,0x06,0x66,0x37,0x8c,0xc0,0x8e,0x06,0x30,0x34 +,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x01 +,0x8e,0xc0,0xc3,0xff,0x06,0xc2,0x33,0xe9,0xf8,0xff,0xe5,0x00,0x0d,0x18,0x00,0xe7 +,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7,0x02,0xc3,0x58,0xe9,0x43,0xfd,0xe5,0x08,0x0d +,0x00,0x04,0x25,0xff,0x04,0xe7,0x08,0xe9,0xe0,0xff,0xe5,0x0e,0xa9,0x00,0x08,0x75 +,0x01,0xc3,0xe9,0xf5,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb8 +,0x33,0xe5,0x48,0x06,0x53,0x57,0xff,0x16,0x4e,0x37,0x5f,0x5b,0x83,0x3e,0x80,0x01 +,0xff,0x74,0x58,0x8e,0x06,0x80,0x01,0x26,0xff,0x0e,0x08,0x00,0x75,0x4d,0x26,0xa1 +,0x00,0x00,0xa3,0x80,0x01,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x8c,0xc0,0x26,0x8e +,0x06,0x02,0x00,0x26,0x81,0x0e,0x08,0x00,0x80,0x00,0x8b,0xd0,0x26,0x87,0x06,0x1a +,0x00,0x26,0x83,0x3e,0x18,0x00,0xff,0x74,0x0a,0x8e,0xc0,0x26,0x89,0x16,0x00,0x00 +,0xe9,0x05,0x00,0x26,0x89,0x16,0x18,0x00,0x83,0x3e,0x80,0x01,0xff,0x74,0x0c,0x8e +,0x06,0x80,0x01,0x26,0x83,0x3e,0x08,0x00,0x00,0x74,0xb3,0x07,0xe9,0x3e,0xf7,0xe5 +,0x4c,0x90,0xe5,0x02,0xa9,0x00,0x20,0x74,0x0d,0x25,0xff,0xdf,0x0d,0x01,0x00,0xe7 +,0x02,0x0d,0x00,0x20,0xe7,0x02,0xe5,0x0a,0x8b,0xd8,0xa3,0xf4,0x33,0x25,0xc3,0x57 +,0x0d,0x00,0x10,0xe7,0x0a,0xf7,0x06,0x9b,0x36,0x00,0x80,0x74,0x37,0xf7,0xc3,0x00 +,0x80,0x74,0x06,0xf7,0xc3,0x00,0x08,0x74,0x5d,0x81,0x26,0xc2,0x34,0x7f,0xff,0xc7 +,0x06,0x35,0x37,0x05,0x00,0xb8,0x80,0x03,0xcd,0x39,0x81,0x26,0x9b,0x36,0xff,0x7f +,0xc7,0x06,0x0f,0x37,0x04,0x00,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06 +,0x0f,0x37,0x03,0x00,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x2a,0xf7,0xc3,0x00,0x08 +,0x74,0x24,0x80,0x3e,0x9d,0x36,0x06,0x7c,0x1d,0xff,0x06,0x94,0x34,0x83,0x0e,0x66 +,0x37,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26 +,0x81,0x0e,0x08,0x00,0x00,0x01,0xf7,0xc3,0x00,0x20,0x75,0x3b,0xf7,0x06,0x9a,0x37 +,0x80,0x00,0x74,0x0b,0xff,0x06,0x89,0x37,0x33,0xc0,0xe7,0x0e,0xe9,0x04,0x00,0xff +,0x06,0x3b,0x37,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x1c,0x80,0x26,0x9e,0x36,0xff +,0x75,0x15,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x08,0x74,0x07,0x26 +,0x81,0x0e,0x08,0x00,0x00,0x08,0xc3,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x02,0x23,0x02,0x23,0x02,0x23,0x02,0x23,0x03,0x23,0xdd,0x22,0x02,0x23,0xfd,0x21 +,0x02,0x23,0xa4,0x24,0xf3,0x24,0x02,0x23,0x8d,0x22,0x7a,0x23,0x02,0x23,0x97,0x24 +,0x1b,0x24,0x75,0x24,0x02,0x23,0x02,0x23,0x8e,0x25,0xfb,0x8e,0x06,0x7e,0x01,0xfb +,0x26,0x83,0x3e,0x00,0x00,0xff,0x74,0xf2,0x26,0x8e,0x06,0x00,0x00,0xfa,0x26,0x8b +,0x1e,0x08,0x00,0x26,0x23,0x1e,0x0a,0x00,0x74,0xe5,0x8c,0xc0,0x8e,0xd0,0x26,0x8b +,0x26,0x02,0x00,0x8c,0x16,0xf2,0x33,0x22,0xff,0x75,0x6a,0x26,0xa1,0x1c,0x00,0x8a +,0xe3,0x8a,0xdc,0x22,0xd8,0x75,0x0d,0xd0,0xe8,0x24,0xf8,0x0a,0xc0,0x75,0xf2,0xb0 +,0x80,0xe9,0xed,0xff,0xd0,0xe8,0x24,0xf8,0x0a,0xc0,0x75,0x02,0xb0,0x80,0x32,0xe4 +,0x26,0xa3,0x1c,0x00,0xf7,0xc3,0x08,0x00,0x75,0x47,0x2e,0x8a,0x9f,0xc5,0x25,0x2e +,0x8b,0xbf,0xc5,0x26,0x80,0xc3,0x10,0x26,0x8e,0x1d,0x26,0x8c,0x1e,0x06,0x00,0x8b +,0x16,0x00,0x00,0xc7,0x06,0x00,0x00,0xff,0xff,0x26,0x89,0x15,0x83,0xfa,0xff,0x75 +,0x0a,0x2e,0x8b,0x97,0xcd,0x26,0x26,0x21,0x16,0x08,0x00,0x33,0xc0,0x8e,0xd8,0x26 +,0x89,0x1e,0x04,0x00,0xc3,0x8a,0xdf,0xb7,0x00,0x2e,0x8a,0x9f,0xc5,0x25,0xe9,0xe0 +,0xff,0x26,0x83,0x26,0x08,0x00,0xf7,0x83,0xc3,0x10,0xe9,0xde,0xff,0x60,0x06,0x1e +,0x68,0x87,0x25,0x6a,0x00,0x1f,0x8e,0x06,0xf2,0x33,0x8b,0x0e,0x34,0x34,0x39,0x0e +,0xf2,0x33,0x74,0x0e,0x26,0x81,0x0e,0x0a,0x00,0x00,0x02,0x26,0x81,0x0e,0x08,0x00 +,0x00,0x02,0x26,0x89,0x26,0x02,0x00,0xa3,0xf2,0x33,0x8e,0xd0,0x8d,0x26,0x80,0x00 +,0x36,0x89,0x26,0x02,0x00,0x36,0x89,0x1e,0x20,0x00,0x36,0xc7,0x06,0x08,0x00,0x00 +,0x00,0xb9,0x04,0x00,0xbe,0x00,0x00,0x2e,0x8b,0xbc,0xc5,0x26,0x36,0xc7,0x05,0xff +,0xff,0x36,0xc7,0x45,0x02,0xff,0xff,0x83,0xc6,0x02,0xe2,0xeb,0x8e,0x06,0x7e,0x01 +,0x36,0x8b,0x0e,0x22,0x00,0x8c,0xc0,0x26,0x83,0x3e,0x00,0x00,0xff,0x26,0x8e,0x06 +,0x00,0x00,0x74,0x07,0x26,0x3b,0x0e,0x22,0x00,0x7d,0xea,0x36,0x8c,0x06,0x00,0x00 +,0x8e,0xc0,0x26,0x8c,0x16,0x00,0x00,0xfb,0x36,0xff,0x2e,0x1e,0x00,0x06,0x1e,0x68 +,0x8b,0x25,0x6a,0x00,0x1f,0x26,0x09,0x36,0x08,0x00,0xf7,0xc6,0x00,0xff,0x74,0x01 +,0xc3,0x56,0x52,0x2e,0x8b,0xb4,0xc5,0x25,0x81,0xe6,0xff,0x00,0x2e,0x8b,0xb4,0xc5 +,0x26,0x8c,0xc2,0x8e,0xc0,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x8e,0xc2,0x26,0x83 +,0x3c,0xff,0x74,0x0f,0x8b,0xd0,0x26,0x87,0x54,0x02,0x8e,0xc2,0x26,0xa3,0x00,0x00 +,0xe9,0x07,0x00,0x26,0x89,0x44,0x02,0x26,0x89,0x04,0x5a,0x5e,0xc3,0x06,0x1e,0x68 +,0x8b,0x25,0x6a,0x00,0x1f,0x8e,0x06,0xf2,0x33,0x26,0xa3,0x0a,0x00,0x26,0x89,0x26 +,0x02,0x00,0xa1,0x34,0x34,0x8e,0xd0,0x8d,0x26,0x80,0x00,0x8c,0x16,0xf2,0x33,0xe9 +,0x4d,0xfe,0xcf,0x50,0x1e,0x52,0x53,0x33,0xc0,0x8e,0xd8,0x26,0x83,0x3e,0x04,0x00 +,0xff,0x26,0xc7,0x06,0x04,0x00,0x00,0x00,0x74,0x03,0xe9,0x1a,0x00,0x83,0x3e,0xe6 +,0x3a,0x02,0x76,0x13,0xff,0x06,0xd6,0x33,0x8c,0xc0,0x8e,0x06,0x32,0x34,0xbe,0x40 +,0x00,0x68,0x3a,0x23,0xe9,0x5e,0xff,0xe8,0x84,0xf8,0x5b,0x5a,0x1f,0x58,0xcf,0xe8 +,0xe1,0x00,0x26,0xc6,0x06,0x18,0x00,0x10,0x26,0x8a,0x1e,0x29,0x00,0x88,0x1e,0x1b +,0x37,0x26,0xc7,0x06,0x0c,0x00,0xff,0x7f,0x26,0xa1,0x0e,0x00,0xe7,0x9c,0x26,0xa1 +,0x08,0x00,0xe7,0x9a,0xe5,0x00,0x80,0xfb,0x08,0x74,0x09,0x0d,0x18,0xac,0xe7,0x00 +,0x07,0x1f,0x58,0xcf,0x0d,0x18,0x00,0xe9,0xf4,0xff,0x50,0x1e,0x06,0x33,0xc0,0x8e +,0xd8,0x83,0x3e,0xa1,0x36,0x00,0x75,0xb7,0x26,0x8b,0x36,0x06,0x00,0x2e,0xff,0x94 +,0xdc,0x23,0x07,0x1f,0x58,0xcf,0xe8,0x8a,0x00,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00 +,0xe8,0x49,0x00,0xc3,0x53,0xf7,0x06,0xef,0x34,0x20,0x00,0x75,0x2d,0xe5,0x8c,0x25 +,0x00,0x70,0x8b,0xd8,0xe5,0x8c,0x25,0x00,0x70,0x3b,0xc3,0x74,0x05,0x8b,0xd8,0xe9 +,0xf2,0xff,0x3d,0x00,0x30,0x75,0x10,0xe5,0x02,0x25,0xef,0xff,0xe7,0x02,0xc7,0x06 +,0xe0,0x3a,0xff,0xff,0xe9,0x03,0x00,0xe8,0x12,0x00,0x5b,0xc3,0xa3,0x23,0x96,0x23 +,0xa4,0x23,0xa4,0x23,0x96,0x23,0xa4,0x23,0x96,0x23,0x96,0x23,0x26,0xa0,0x29,0x00 +,0xa2,0x1b,0x37,0x26,0xc7,0x06,0x0c,0x00,0xff,0x7f,0x26,0xa1,0x0e,0x00,0xe7,0x9c +,0x26,0xa1,0x08,0x00,0xe7,0x9a,0xe5,0x00,0x25,0xff,0x53,0x26,0x8b,0x36,0x06,0x00 +,0x83,0xe6,0x0e,0x2e,0x0b,0x84,0xad,0x25,0xe7,0x00,0xc3,0x06,0x1e,0x68,0x8b,0x25 +,0x6a,0x00,0x1f,0x83,0x0e,0xef,0x34,0x20,0x83,0x0e,0x9b,0x36,0x08,0xe5,0x00,0x25 +,0xef,0xff,0x0d,0x08,0x00,0xe7,0x00,0xe5,0x00,0xa9,0x10,0x00,0x75,0x01,0xc3,0xe5 +,0x00,0xa9,0x10,0x00,0x75,0xf9,0xc3,0x50,0x53,0x51,0x56,0x06,0x1e,0x33,0xc0,0x8e +,0xd8,0xb8,0x05,0x00,0xe7,0x84,0xe5,0x08,0x0d,0x00,0x04,0x25,0xff,0x04,0xe7,0x08 +,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7,0x02,0x1f,0x07 +,0x5e,0x59,0x5b,0x58,0xc3,0x50,0x1e,0x33,0xc0,0x8e,0xd8,0xc7,0x06,0xef,0x34,0x00 +,0x00,0x83,0x26,0x9b,0x36,0xf7,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d +,0x11,0x00,0xe7,0x02,0x1f,0x58,0xcf,0x60,0x06,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f +,0xe8,0x16,0xf5,0xc3,0x06,0x1e,0x68,0x8b,0x25,0x6a,0x00,0x1f,0x8e,0xc0,0x26,0x83 +,0x3e,0x0a,0x00,0x00,0x74,0x03,0xe8,0x43,0x00,0x26,0xc7,0x06,0x0a,0x00,0xff,0xff +,0x26,0x8b,0x16,0x06,0x00,0x8e,0x1e,0x8e,0x01,0x8c,0xd8,0x8b,0xca,0x83,0x3e,0x00 +,0x00,0xff,0x8e,0x1e,0x00,0x00,0x74,0x0a,0x2b,0x16,0x08,0x00,0x73,0xeb,0x29,0x0e +,0x08,0x00,0x26,0x89,0x0e,0x08,0x00,0x26,0x8c,0x1e,0x00,0x00,0x8e,0xd8,0x8c,0x06 +,0x00,0x00,0xc3,0x60,0x06,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f,0x8e,0xc0,0x8b,0xc8 +,0x8e,0x1e,0x8e,0x01,0x26,0xc7,0x06,0x0a,0x00,0x00,0x00,0x8c,0xd8,0x83,0x3e,0x00 +,0x00,0xff,0x74,0x25,0x3b,0x0e,0x00,0x00,0x8e,0x1e,0x00,0x00,0x75,0xed,0x8e,0xd8 +,0x26,0xa1,0x00,0x00,0xa3,0x00,0x00,0x3d,0xff,0xff,0x74,0x56,0x8e,0xd8,0x26,0xa1 +,0x08,0x00,0x01,0x06,0x08,0x00,0xe9,0x49,0x00,0x26,0x8e,0x1e,0x02,0x00,0xbe,0x18 +,0x00,0x83,0x3c,0xff,0x74,0x3c,0x39,0x0c,0x74,0x19,0x8e,0x1c,0xbe,0x00,0x00,0x83 +,0x3e,0x00,0x00,0xff,0x74,0x2c,0x39,0x0e,0x00,0x00,0x74,0x07,0x8e,0x1e,0x00,0x00 +,0xe9,0xec,0xff,0x26,0xa1,0x00,0x00,0x89,0x04,0x33,0xc9,0x8e,0xd9,0x3d,0xff,0xff +,0x75,0x10,0x83,0xfe,0x18,0x75,0x0b,0x26,0x8e,0x1e,0x02,0x00,0x81,0x26,0x08,0x00 +,0x7f,0xff,0x33,0xc0,0x8e,0xd8,0xc3,0x1f,0x07,0x61,0xcf,0x1f,0x07,0xcf,0x60,0x06 +,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f,0xe5,0x06,0x25,0x1e,0x00,0x3d,0x1e,0x00,0x75 +,0xf6,0xb9,0x08,0x00,0xe5,0x58,0xe7,0x5a,0x23,0xc0,0xe0,0xf8,0xc3,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x00,0x00,0x00,0xa8,0x00,0x8c,0x02,0x04,0x00 +,0x00,0x08,0x10,0x20,0x00,0xff,0x0e,0x0c,0x0c,0x0a,0x0a,0x0a,0x0a,0x08,0x08,0x08 +,0x08,0x08,0x08,0x08,0x08,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06 +,0x06,0x06,0x06,0x06,0x06,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 +,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 +,0x04,0x04,0x04,0x04,0x04,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 +,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 +,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 +,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 +,0x02,0x02,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x14,0x00,0x10,0x00,0x0c,0x00,0xff,0x7f,0xff +,0xbf,0xff,0xdf,0xff,0xef,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe,0x7f,0xff,0xbf +,0xff,0xdf,0xff,0xef,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe,0xff,0x00,0x00,0x00 +,0x80,0x3e,0xe2,0x34,0x01,0x76,0x03,0xe9,0xa5,0x00,0xb8,0x00,0x00,0xe7,0x4e,0xb9 +,0x28,0x00,0xe2,0xfe,0xc6,0x06,0x45,0x37,0x02,0xbf,0x3f,0x28,0x2e,0x8b,0x45,0x08 +,0xe7,0x4e,0xb9,0x28,0x00,0xe2,0xfe,0x2e,0x8b,0x1d,0xc7,0x06,0xb3,0x36,0x40,0x11 +,0xc7,0x06,0xb1,0x36,0x27,0x00,0xc7,0x06,0x46,0x37,0x02,0x00,0xc7,0x06,0x48,0x37 +,0x64,0x00,0xf7,0x06,0xb5,0x36,0x02,0x00,0x75,0x1c,0x2e,0x0b,0x5d,0x02,0x81,0x26 +,0xb3,0x36,0xff,0xfe,0xc7,0x06,0xb1,0x36,0x9c,0x00,0xc7,0x06,0x46,0x37,0x08,0x00 +,0xc7,0x06,0x48,0x37,0x90,0x01,0x89,0x1e,0xb7,0x36,0x89,0x1e,0xfe,0x33,0xbe,0x20 +,0x00,0x8b,0xc3,0xe7,0x4e,0xb9,0x28,0x00,0xe2,0xfe,0x2e,0x8b,0x45,0x04,0xe7,0x4e +,0xb9,0x28,0x00,0xe2,0xfe,0xe5,0x4e,0x8b,0xcb,0x2e,0x23,0x45,0x06,0x2e,0x23,0x4d +,0x06,0x3a,0xc1,0x74,0x36,0x4e,0x75,0xd9,0x80,0x3e,0x45,0x37,0x00,0x74,0x0b,0xc6 +,0x06,0x45,0x37,0x00,0xbf,0x2f,0x28,0xe9,0x72,0xff,0xc6,0x06,0x45,0x37,0x01,0xf7 +,0x06,0xb5,0x36,0x02,0x00,0x74,0x14,0xe5,0xce,0x25,0xfd,0xff,0xe7,0xce,0xe8,0x43 +,0x00,0xe5,0xce,0x0d,0x02,0x00,0xe7,0xce,0xe8,0x39,0x00,0x80,0x3e,0xe2,0x34,0x01 +,0x76,0x01,0xc3,0xb8,0xea,0x05,0xe7,0x8c,0xfa,0xe8,0x12,0xf4,0xfb,0x8d,0x06,0xd0 +,0x39,0x8b,0xd8,0xc1,0xe8,0x04,0xa3,0x38,0x34,0x8e,0xc0,0xa1,0x30,0x34,0x26,0xa3 +,0x02,0x00,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x83,0xc3,0x18,0xd1,0xeb,0x26,0x89 +,0x1e,0x08,0x00,0xc3,0xe5,0x02,0x0d,0x00,0x40,0xe7,0x02,0xe5,0x00,0x0d,0x04,0x00 +,0xe7,0x00,0xb8,0x00,0x00,0xe7,0x0a,0xe5,0x0a,0xa9,0x00,0x80,0x75,0x14,0xe5,0x08 +,0x0d,0x00,0x10,0xe7,0x08,0xe5,0x0a,0x0d,0x00,0x08,0xb9,0x05,0x00,0xe7,0x0a,0xe2 +,0xfc,0xc3,0xe5,0x08,0x0d,0x00,0x10,0xb9,0x05,0x00,0xe7,0x08,0xe2,0xfc,0xc3,0x04 +,0x0c,0x20,0x00,0x01,0x0c,0x7e,0xff,0x00,0x0c,0x02,0x00,0x10,0x00,0x40,0x00,0x0c +,0xc6,0x01,0x00,0x00,0xc0,0xf7,0xff,0x00,0xc0,0x02,0x00,0x10,0x00,0x40,0x00,0x00 +,0x33,0xc0,0x8e,0xd8,0x8d,0x3e,0x72,0x49,0x8d,0x36,0xb0,0x37,0xb9,0x14,0x00,0x8b +,0x1e,0x30,0x34,0x89,0x5c,0x02,0x2e,0x8b,0x45,0x02,0x89,0x44,0x06,0x2e,0x8b,0x05 +,0x89,0x44,0x04,0x83,0xc7,0x04,0x83,0xc6,0x10,0xe2,0xe8,0xc6,0x06,0x9e,0x36,0x0e +,0xe8,0xfd,0x26,0x68,0x83,0x28,0xa1,0xaa,0x02,0xcd,0x35,0x83,0x3e,0xa1,0x36,0x00 +,0x74,0x03,0xe9,0x3b,0x27,0x33,0xff,0x8e,0x06,0xa6,0x02,0x8b,0x36,0xa4,0x02,0x2e +,0xff,0xa4,0x2e,0x30,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37,0x37,0x01,0x00,0xc6 +,0x06,0xca,0x34,0x01,0xe9,0x7d,0x19,0x80,0x3e,0xa0,0x36,0x08,0x74,0xe6,0x80,0x26 +,0x9e,0x36,0xff,0x75,0x1a,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x12,0xf7,0x06,0x9b +,0x36,0x03,0x00,0x75,0x0a,0x83,0x0e,0x66,0x37,0x10,0xc6,0x06,0xa0,0x36,0x08,0xe9 +,0xfb,0x01,0x80,0x3e,0x9e,0x36,0x02,0x75,0xce,0xc6,0x06,0xa0,0x36,0x06,0xe9,0xec +,0x01,0xc3,0xe9,0xe8,0x01,0x26,0xc7,0x06,0x0a,0x00,0x00,0x00,0x26,0xff,0x26,0x04 +,0x00,0xa1,0xd1,0x36,0x26,0x39,0x06,0x1a,0x00,0x75,0x22,0xa1,0xd3,0x36,0x26,0x39 +,0x06,0x1c,0x00,0x75,0x18,0xa1,0xd5,0x36,0x26,0x39,0x06,0x1e,0x00,0x75,0x0e,0x26 +,0xf7,0x06,0x0c,0x00,0x40,0x00,0x74,0x05,0x83,0x0e,0x66,0x37,0x40,0x81,0x0e,0xaf +,0x36,0x00,0x10,0xa1,0xaf,0x36,0xe7,0x06,0x80,0x3e,0x9d,0x36,0x02,0x75,0x06,0xcd +,0x34,0xe9,0xa2,0x1a,0xc3,0xf7,0x06,0x9b,0x36,0x10,0x00,0x75,0x54,0x26,0xf6,0x06 +,0x0a,0x00,0xff,0x75,0x4c,0x26,0xa0,0x19,0x00,0x24,0xc0,0x3c,0x40,0x75,0x11,0x80 +,0x3e,0x95,0x36,0x00,0x74,0x3b,0x26,0xc7,0x06,0x04,0x00,0xff,0xff,0xe9,0x31,0x00 +,0xe8,0xf1,0x04,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74,0x2f,0x8b,0xd8,0xb8,0x7d,0x03 +,0xcd,0x3a,0x8b,0xc3,0xc6,0x06,0xa0,0x36,0x06,0xf7,0x06,0x9b,0x36,0x02,0x00,0x75 +,0x05,0xc6,0x06,0xa0,0x36,0x04,0x81,0x0e,0x9b,0x36,0x80,0x00,0x83,0x26,0x9b,0x36 +,0xfc,0xe9,0x23,0x01,0xe8,0x87,0x1d,0xe9,0x33,0x01,0x50,0x26,0xa1,0x0c,0x00,0x25 +,0x07,0x00,0x3d,0x07,0x00,0x75,0x03,0xe9,0x84,0x00,0x3d,0x05,0x00,0x75,0x03,0xe9 +,0x7c,0x00,0x83,0x3e,0xe8,0x3a,0x04,0x74,0x75,0x83,0x3e,0xe8,0x3a,0x02,0x74,0x6e +,0xf7,0x06,0xe6,0x34,0x18,0x80,0x75,0x03,0xe9,0x6a,0x00,0xf7,0x06,0xe6,0x34,0x00 +,0x80,0x74,0x35,0x26,0x80,0x3e,0x29,0x00,0x02,0x75,0x2d,0x51,0x56,0x57,0x8d,0x36 +,0x3e,0x34,0x8d,0x3e,0x20,0x00,0xb9,0x06,0x00,0xf3,0xa6,0x5f,0x5e,0x59,0x74,0x45 +,0x26,0xa1,0x20,0x00,0xa3,0x3e,0x34,0x26,0xa1,0x22,0x00,0xa3,0x40,0x34,0x26,0xa1 +,0x24,0x00,0xa3,0x42,0x34,0xe9,0x26,0x00,0xf7,0x06,0xe6,0x34,0x08,0x00,0x74,0x0b +,0x26,0x80,0x3e,0x19,0x00,0x00,0x74,0x03,0xe9,0x13,0x00,0xf7,0x06,0xe6,0x34,0x10 +,0x00,0x74,0x12,0x26,0xa0,0x28,0x00,0xc0,0xe8,0x04,0x22,0xc0,0x74,0x07,0x26,0xc7 +,0x06,0x04,0x00,0xff,0xff,0x58,0x23,0xc0,0x74,0x03,0xe9,0x57,0xff,0x81,0x26,0x9b +,0x36,0xff,0xfe,0x83,0xfe,0x06,0x7f,0x24,0x26,0xa1,0x20,0x00,0x3b,0x06,0xd1,0x36 +,0x75,0x1a,0x26,0xa1,0x22,0x00,0x3b,0x06,0xd3,0x36,0x75,0x10,0x26,0xa1,0x24,0x00 +,0x3b,0x06,0xd5,0x36,0x75,0x06,0x81,0x0e,0x9b,0x36,0x00,0x01,0x26,0xa1,0x20,0x00 +,0x25,0x7f,0xff,0xa3,0xb8,0x34,0x26,0xa1,0x22,0x00,0xa3,0xba,0x34,0x26,0xa1,0x24 +,0x00,0xa3,0xbc,0x34,0x8b,0xc6,0x86,0xc4,0xa3,0xc0,0x34,0xd1,0xe6,0x80,0xfc,0x09 +,0x74,0x03,0xe8,0xaa,0x1c,0x8b,0xc6,0x2e,0xff,0xa4,0x30,0x49,0x26,0xa1,0x0c,0x00 +,0x3d,0xff,0x7f,0x74,0x0f,0x26,0xff,0x26,0x04,0x00,0x8e,0x06,0x38,0x34,0xe8,0x36 +,0x06,0xcd,0x50,0xc3,0xe9,0x16,0x00,0xcd,0x34,0xe9,0x11,0x00,0xcd,0x34,0x89,0x36 +,0x3d,0x37,0xa1,0x9d,0x36,0xa3,0x3f,0x37,0xc6,0x06,0xa0,0x36,0x0c,0xe8,0x8e,0x00 +,0xa1,0x9f,0x36,0x22,0xe4,0x75,0x32,0xf7,0x06,0x4c,0x37,0x01,0x00,0x75,0x2a,0xf6 +,0x06,0x9d,0x36,0x80,0x74,0x07,0x88,0x26,0x9e,0x36,0xe9,0x31,0x00,0x3a,0x06,0x9d +,0x36,0xa3,0x9d,0x36,0x74,0x28,0x8b,0xf0,0x2e,0xff,0xa4,0x0d,0x2b,0x44,0x29,0xee +,0x42,0x19,0x44,0xcd,0x44,0x2f,0x45,0x5a,0x45,0x3a,0x26,0x9e,0x36,0x75,0x01,0xc3 +,0x32,0xc0,0x86,0xc4,0x8b,0xf0,0xa2,0x9e,0x36,0x2e,0xff,0xa4,0x20,0x49,0x8b,0x2e +,0x99,0x36,0x23,0xed,0x75,0x01,0xc3,0xbf,0x01,0x00,0xbe,0x00,0x00,0x85,0xfd,0x75 +,0x1a,0x46,0xd1,0xe7,0xe9,0xf6,0xff,0x2a,0x00,0x29,0x00,0x28,0x00,0x27,0x00,0x25 +,0x00,0x05,0x00,0x07,0x00,0x26,0x00,0x06,0x00,0x20,0x00,0xf7,0xd7,0x21,0x3e,0x99 +,0x36,0xd1,0xe6,0x2e,0x8b,0xb4,0x47,0x2b,0xe9,0x4f,0xff,0xe9,0x56,0xff,0x80,0x26 +,0x9e,0x36,0xff,0x75,0x17,0xf7,0x06,0x4c,0x37,0x01,0x00,0x75,0x0f,0xf6,0x06,0x9d +,0x36,0x80,0x74,0x08,0xf7,0x06,0x66,0x37,0xff,0xff,0x75,0x07,0xc7,0x06,0x66,0x37 +,0x00,0x00,0xc3,0xf7,0x06,0x41,0x37,0x01,0x00,0x75,0x0b,0xb8,0x7f,0x03,0xcd,0x39 +,0xc7,0x06,0x41,0x37,0x01,0x00,0x33,0xf6,0xb8,0x00,0x40,0x85,0x06,0x66,0x37,0x74 +,0x21,0x80,0xbc,0x54,0x37,0xff,0x74,0x04,0xfe,0x84,0x54,0x37,0x80,0xbc,0x96,0x34 +,0xff,0x74,0x04,0xfe,0x84,0x96,0x34,0x31,0x06,0x66,0x37,0x83,0x3e,0x66,0x37,0x00 +,0x74,0x05,0x46,0xd1,0xe8,0x73,0xd4,0xc3,0xa1,0xf4,0x33,0xa9,0x00,0x88,0x74,0x0b +,0xa9,0x00,0x10,0x75,0x09,0x8b,0x1e,0x43,0x37,0xff,0xe3,0xe9,0xd7,0x00,0xc7,0x06 +,0x35,0x37,0x05,0x00,0xc7,0x06,0x43,0x37,0x1e,0x2c,0xf7,0x06,0xf4,0x33,0x00,0x08 +,0x74,0x06,0xc7,0x06,0x43,0x37,0x10,0x2c,0xb8,0x80,0x03,0xcd,0x39,0xe9,0xcd,0xfe +,0xa9,0x00,0x08,0x74,0xd9,0xff,0x0e,0x35,0x37,0x75,0xed,0xe9,0x66,0x00,0xa9,0x00 +,0x08,0x75,0xcb,0xff,0x0e,0x35,0x37,0x75,0xdf,0x81,0x0e,0xc2,0x34,0xc0,0x00,0xf6 +,0x06,0x9d,0x36,0x80,0x74,0x48,0x81,0x0e,0x9b,0x36,0x00,0x80,0xf7,0x06,0x9b,0x36 +,0x01,0x00,0x74,0x1e,0xb8,0x7d,0x03,0xcd,0x3a,0x81,0x0e,0x9b,0x36,0x80,0x00,0x83 +,0x26,0x9b,0x36,0xfe,0xc7,0x06,0x0f,0x37,0x02,0x00,0xc6,0x06,0xa0,0x36,0x04,0xe9 +,0x7b,0xfe,0x80,0x3e,0xa0,0x36,0x04,0x75,0x07,0x83,0x3e,0x0f,0x37,0x01,0x75,0x05 +,0xc6,0x06,0xa0,0x36,0x06,0xc7,0x06,0x0f,0x37,0x02,0x00,0xe9,0x5f,0xfe,0xbe,0x02 +,0x00,0xe9,0x4a,0xfe,0x80,0x26,0x9e,0x36,0xff,0x75,0x3a,0xf6,0x06,0x9d,0x36,0x80 +,0x74,0x2d,0xf7,0x06,0x9b,0x36,0x00,0x20,0x75,0x2b,0xc6,0x06,0xa0,0x36,0x06,0xff +,0x06,0x94,0x34,0x83,0x0e,0x66,0x37,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a +,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x01,0xe9,0x06,0x00,0xbe +,0x04,0x00,0xe9,0x09,0xfe,0x81,0x0e,0xaf,0x36,0x00,0x08,0xa1,0xaf,0x36,0xe7,0x06 +,0xe5,0x0a,0xa9,0x00,0x80,0x74,0x0e,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36 +,0xe7,0x06,0xe9,0x09,0xff,0xe9,0xf5,0xfd,0xc7,0x06,0x41,0x37,0x00,0x00,0x83,0x0e +,0x99,0x36,0x02,0xe9,0xe7,0xfd,0x80,0x26,0x9e,0x36,0xff,0x75,0x1d,0xf7,0x06,0x9b +,0x36,0x00,0x40,0x75,0x05,0x83,0x0e,0x99,0x36,0x08,0x83,0x0e,0x99,0x36,0x20,0x81 +,0x26,0x9b,0x36,0xff,0xbf,0xb8,0x85,0x03,0xcd,0x39,0xe9,0xc0,0xfd,0x80,0x3e,0x9e +,0x36,0x06,0x74,0x07,0x80,0x3e,0x9e,0x36,0x0a,0x75,0x34,0xf6,0x06,0x9d,0x36,0x80 +,0x75,0x06,0xbe,0x07,0x00,0xe9,0x96,0xfd,0xc6,0x06,0xa0,0x36,0x04,0x83,0x3e,0x0f +,0x37,0x02,0x74,0x1b,0xc7,0x06,0x0f,0x37,0x04,0x00,0x80,0x3e,0x9e,0x36,0x06,0x75 +,0x0e,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06,0x0f,0x37,0x03,0x00,0xe9 +,0x7b,0xfd,0x80,0x3e,0x9d,0x36,0x04,0x75,0x12,0x81,0x0e,0xc2,0x34,0x00,0x40,0xff +,0x06,0x92,0x34,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x62,0xfd,0xbe,0x05,0x00,0xe9,0x4d +,0xfd,0xf6,0x06,0x9d,0x36,0x80,0x75,0x19,0x83,0x0e,0xc2,0x34,0x04,0xbe,0x06,0x00 +,0xe9,0x3b,0xfd,0x80,0x26,0x9e,0x36,0xff,0x75,0xc5,0xff,0x06,0x31,0x37,0xe9,0x00 +,0x00,0x83,0x26,0xc2,0x34,0xbf,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x2f,0xfd,0xe5,0x0a +,0x50,0x25,0xc3,0xbf,0xe7,0x0a,0x58,0x80,0x26,0x9e,0x36,0xff,0x75,0x0d,0xa9,0x00 +,0x40,0x75,0x08,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x12,0xfd,0xb8,0x83,0x03,0xcd,0x39 +,0xc3,0xb8,0x7c,0x03,0xcd,0x39,0xf7,0x06,0xf4,0x33,0x00,0x10,0x75,0x09,0xc7,0x06 +,0x33,0x37,0x02,0x00,0xe9,0xf6,0xfc,0xff,0x0e,0x33,0x37,0x74,0x03,0xe9,0xed,0xfc +,0xff,0x06,0x8e,0x34,0xe8,0xf7,0x19,0x83,0x0e,0xc2,0x34,0x08,0xbe,0x03,0x00,0xe9 +,0xcc,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x04,0x05 +,0x04,0x04,0x04,0x00,0x03,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x04,0x00,0x08,0x08,0x05,0x08,0x08,0x08,0x00,0x03,0x00,0x03,0x03,0x00,0x00 +,0x02,0x04,0x04,0x04,0x04,0x00,0x00,0x08,0x00,0x00,0x0a,0x14,0x00,0x00,0x1a,0x00 +,0x1c,0x00,0x1e,0x20,0x00,0x00,0x04,0x41,0x06,0x0b,0x08,0xc2,0xff,0xe7,0x04,0x03 +,0x06,0x04,0x04,0x05,0x04,0x06,0x04,0x87,0x04,0x03,0x06,0x04,0x04,0x85,0x4e,0xa2 +,0x04,0xcf,0x04,0xcd,0xc7,0x06,0xa2,0x37,0x00,0x00,0xc7,0x06,0xa6,0x37,0x00,0x00 +,0x26,0xa1,0x20,0x00,0x25,0x7f,0xff,0xa3,0xf5,0x36,0x26,0xa1,0x22,0x00,0xa3,0xf7 +,0x36,0x26,0xa1,0x24,0x00,0xa3,0xf9,0x36,0xe8,0x3b,0x19,0x8b,0xf0,0x26,0x8b,0x0e +,0x0e,0x00,0x2b,0xc8,0x83,0xe9,0x0e,0xb8,0x01,0x80,0x83,0xf9,0x04,0x7c,0x51,0x26 +,0x8a,0x54,0x28,0x88,0x16,0x1c,0x37,0x40,0x26,0x8b,0x6c,0x26,0x86,0xcd,0x3b,0xcd +,0x86,0xcd,0x89,0x0e,0xa4,0x37,0x75,0x38,0x40,0x32,0xff,0x26,0x8a,0x5c,0x29,0x80 +,0xfb,0x15,0x77,0x25,0x80,0xfb,0x0a,0x74,0x20,0x80,0xfb,0x01,0x74,0x1b,0xb8,0x04 +,0x80,0x2e,0x3a,0x97,0x02,0x2e,0x74,0x07,0x2e,0x3a,0x97,0x18,0x2e,0x75,0x11,0x33 +,0xc0,0x80,0xfb,0x09,0x75,0x4f,0x8b,0xf3,0xc3,0x26,0xc7,0x06,0x04,0x00,0xff,0xff +,0x50,0x52,0xa1,0xa4,0x37,0x86,0xc4,0x26,0x3b,0x06,0x26,0x00,0x7c,0x32,0x26,0x81 +,0x3e,0x26,0x00,0x00,0x04,0x7e,0x29,0x8d,0x74,0x2a,0x26,0x8b,0x14,0x22,0xd2,0x74 +,0x1f,0x80,0xe6,0xbf,0x80,0xfe,0x09,0x75,0x17,0xc7,0x06,0xa2,0x37,0x01,0x00,0x80 +,0xfa,0x04,0x75,0x0c,0x26,0x8b,0x44,0x02,0xa3,0x03,0x37,0x86,0xc4,0xa3,0xd0,0x34 +,0x5a,0x58,0xe9,0xb1,0xff,0xbd,0x72,0x37,0x2e,0x8a,0x87,0x2e,0x2e,0x22,0xc0,0x74 +,0x16,0x05,0x44,0x2e,0x8b,0xf8,0x2e,0x8b,0x05,0x3e,0x89,0x46,0x00,0x83,0xc5,0x02 +,0x83,0xc7,0x02,0x22,0xe4,0x7d,0xef,0x8d,0x74,0x2a,0x83,0xe9,0x04,0x75,0x03,0xe9 +,0xa1,0x00,0x26,0x8b,0x14,0x22,0xd2,0x75,0x03,0xe9,0x7c,0x00,0xc7,0x06,0xa6,0x37 +,0x01,0x00,0xbf,0x72,0x37,0x8b,0x05,0x83,0xc7,0x02,0x80,0xe6,0xbf,0x80,0xe4,0x3f +,0x80,0xfe,0x09,0x75,0x22,0x80,0xfa,0x04,0x75,0x5e,0xc7,0x06,0xa2,0x37,0x01,0x00 +,0x26,0x8b,0x44,0x02,0xa3,0x03,0x37,0x86,0xc4,0xa3,0xd0,0x34,0x86,0xc4,0xc7,0x06 +,0xa6,0x37,0x00,0x00,0xe9,0x47,0x00,0x3b,0xfd,0x7e,0x15,0x26,0x8b,0x04,0xa8,0x40 +,0x74,0x06,0xb8,0x07,0x80,0xe9,0x38,0xff,0x32,0xc0,0x26,0x8b,0x04,0xe9,0x2e,0x00 +,0x3a,0xf4,0x75,0xb1,0xc7,0x45,0xfe,0x00,0x00,0x80,0xfe,0x22,0x75,0x0d,0x3a,0xd0 +,0x77,0x16,0xc7,0x06,0xa6,0x37,0x00,0x00,0xe9,0x13,0x00,0x3a,0xd0,0x75,0x09,0xc7 +,0x06,0xa6,0x37,0x00,0x00,0xe9,0x06,0x00,0xb8,0x05,0x80,0xe9,0x02,0xff,0x32,0xf6 +,0x03,0xf2,0x2b,0xca,0xb8,0x05,0x80,0x23,0xc9,0x76,0x03,0xe9,0x64,0xff,0x74,0x03 +,0xe9,0xed,0xfe,0x33,0xc0,0xbf,0x72,0x37,0x8b,0x15,0x47,0x47,0x3b,0xfd,0x7f,0x1b +,0xf6,0xc6,0x80,0x74,0x16,0xf7,0x06,0xa6,0x37,0x01,0x00,0x74,0x06,0xb8,0x08,0x80 +,0xe9,0xc3,0xfe,0xf6,0xc6,0x40,0x74,0xe0,0xb8,0x07,0x80,0xe9,0xb8,0xfe,0x7d,0x42 +,0xa3,0x45,0x44,0x29,0x44,0x29,0xb7,0x28,0xe2,0x28,0xee,0x2b,0xf2,0x28,0xf5,0x28 +,0x01,0x29,0xac,0x2a,0x44,0x29,0x44,0x29,0x44,0x29,0x44,0x29,0x44,0x29,0x00,0x00 +,0x73,0x36,0x00,0x00,0x03,0x36,0xc5,0x35,0x83,0x35,0x45,0x35,0x07,0x35,0xd2,0x34 +,0x45,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0xa6,0x38,0x00,0x00,0xe0,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xf2,0x33,0x00,0x00,0xa6,0x33,0x60,0x33,0xfd,0x32,0xbc,0x32,0x77,0x32,0x3c,0x32 +,0xfb,0x31,0x6a,0x31,0x0a,0x31,0xe0,0xe0,0x10,0x10,0x10,0xe0,0xe0,0xe0,0xe0,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0 +,0xe0,0x33,0xff,0x26,0xf6,0x06,0x1a,0x00,0x80,0x74,0x1b,0x26,0x80,0x26,0x1a,0x00 +,0x7f,0x26,0x8b,0x3e,0x26,0x00,0x83,0xe7,0x1f,0x74,0x0b,0x26,0x80,0x0e,0x20,0x00 +,0x80,0x26,0x01,0x3e,0x0e,0x00,0xc3,0x60,0x2e,0x8b,0x84,0xa6,0x30,0x26,0xa3,0x18 +,0x00,0xd1,0xe6,0x2e,0xff,0x94,0x50,0x30,0x61,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4 +,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x16,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26 +,0xc6,0x06,0x19,0x00,0x00,0xe8,0xbf,0x05,0xe8,0x98,0x05,0x26,0xc7,0x06,0x26,0x00 +,0x00,0x08,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29,0x00,0x2a,0xbf,0x2a +,0x00,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x2a,0xa1,0x93,0x37,0x33,0xdb,0xa9 +,0x40,0x00,0x75,0x02,0xb3,0x01,0xa9,0x00,0x10,0x74,0x02,0xb7,0x88,0xa9,0x00,0x08 +,0x74,0x03,0x80,0xcf,0x44,0x26,0x89,0x5d,0x02,0xc3,0x83,0x0e,0xc2,0x34,0x20,0x26 +,0xc7,0x06,0x04,0x00,0x6b,0x2b,0x26,0xc7,0x06,0x0e,0x00,0x30,0x00,0x26,0xc7,0x06 +,0x06,0x00,0x0a,0x00,0x26,0xc7,0x06,0x0a,0x00,0x04,0x00,0x26,0xc6,0x06,0x19,0x00 +,0x00,0xe8,0x69,0x05,0xe8,0x2c,0x05,0x26,0xc7,0x06,0x26,0x00,0x00,0x22,0x26,0xc6 +,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x29,0xbf,0x2a,0x00,0x26,0xc6,0x05 +,0x08,0x26,0xc6,0x45,0x01,0x2d,0x8d,0x7d,0x02,0xbe,0x54,0x37,0xb9,0x03,0x00,0xf3 +,0xa5,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x2e,0x8d,0x7d,0x02,0xbe,0x5a,0x37 +,0xb9,0x03,0x00,0xf3,0xa5,0xe8,0xd4,0x05,0xe8,0x64,0x05,0xb9,0x06,0x00,0xbe,0x54 +,0x37,0x8d,0x2e,0x2c,0x00,0x26,0x8b,0x46,0x00,0x29,0x04,0x83,0xc6,0x02,0x83,0xc5 +,0x02,0x83,0xf9,0x04,0x75,0x02,0x45,0x45,0xe2,0xeb,0xc3,0x26,0xc7,0x06,0x04,0x00 +,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x24,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00 +,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0xe4,0x04,0xe8,0xa7,0x04,0x26,0xc7,0x06,0x26 +,0x00,0x00,0x16,0x26,0xc6,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x28,0xbf +,0x2a,0x00,0xe8,0x5b,0x06,0xe8,0x74,0x05,0xe8,0x04,0x05,0xc3,0x26,0xc7,0x06,0x04 +,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x1a,0x00,0x26,0xc7,0x06,0x06,0x00,0x06 +,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0xa3,0x04,0xe8,0x66,0x04,0x26,0xc7,0x06 +,0x26,0x00,0x00,0x0c,0x26,0xc6,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x27 +,0xbf,0x2a,0x00,0xe8,0x21,0x05,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7 +,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x0a,0x00,0x26,0xc7,0x06,0x0a +,0x00,0x04,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x4b,0x04,0xe8,0x24,0x04,0x26 +,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29 +,0x00,0x26,0xbf,0x2a,0x00,0xe8,0xf4,0x04,0xe8,0x84,0x04,0xc3,0x26,0xc7,0x06,0x04 +,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06 +,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x0d,0x04,0xe8,0xe6,0x03,0x26,0xc7,0x06 +,0x26,0x00,0x00,0x26,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29,0x00,0x25 +,0xbf,0x2a,0x00,0xe8,0xb6,0x04,0xe8,0x46,0x04,0xe8,0xfa,0x04,0xc3,0x26,0xc7,0x06 +,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x38,0x00,0xa1,0xa2,0x37,0x50,0x0b +,0xc0,0x75,0x07,0x26,0xc7,0x06,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06 +,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x99,0x03,0xe8,0xa4,0xfd,0x26,0xc7,0x45 +,0x26,0x00,0x2a,0x58,0x0b,0xc0,0x75,0x06,0x26,0xc7,0x45,0x26,0x00,0x26,0xa1,0x1c +,0x37,0xc1,0xe0,0x04,0x26,0x88,0x45,0x28,0x26,0xc6,0x45,0x29,0x24,0x83,0xc7,0x2a +,0xe8,0x29,0x04,0xe8,0xa0,0x04,0xe8,0x22,0x05,0xe8,0xf8,0x03,0xe8,0x09,0x04,0xc3 +,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x32,0x00,0x26,0xc7 +,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x45,0x03,0xe8,0x50 +,0xfd,0x26,0xc7,0x45,0x26,0x00,0x24,0xa1,0x1c,0x37,0xc1,0xe0,0x04,0x26,0x88,0x45 +,0x28,0x26,0xc6,0x45,0x29,0x23,0x83,0xc7,0x2a,0xe8,0xe0,0x03,0xe8,0x6c,0x04,0xe8 +,0x8a,0x04,0xe8,0x9c,0x04,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06 +,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00 +,0x00,0xe8,0xff,0x02,0xe8,0x0a,0xfd,0x26,0xc7,0x45,0x26,0x00,0x26,0xa1,0x1c,0x37 +,0xc1,0xe0,0x04,0x26,0x88,0x45,0x28,0x26,0xc6,0x45,0x29,0x22,0x83,0xc7,0x2a,0xe8 +,0x9a,0x03,0xe8,0xc7,0x03,0xe8,0x57,0x03,0xe8,0xf8,0x03,0xe8,0x78,0x04,0xe8,0x8a +,0x04,0xc3,0x26,0xc7,0x06,0x04,0x00,0x74,0x45,0x26,0xc7,0x06,0x0e,0x00,0x3e,0x00 +,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc7,0x06,0x0a,0x00,0x04,0x00,0x26,0xc6 +,0x06,0x19,0x00,0x00,0xe8,0xfc,0x02,0xe8,0xa9,0x02,0x83,0x3e,0x8d,0x37,0x03,0x75 +,0x01,0x90,0x26,0xc7,0x06,0x26,0x00,0x00,0x30,0x26,0xc6,0x06,0x28,0x00,0x50,0x26 +,0xc6,0x06,0x29,0x00,0x20,0xbf,0x2a,0x00,0xe8,0xd0,0x03,0xe8,0x01,0x03,0xe8,0xb5 +,0x03,0xe8,0x9f,0x03,0xc3,0x26,0xc7,0x06,0x04,0x00,0x61,0x43,0xb9,0xf0,0x00,0x83 +,0xe9,0x02,0x26,0x89,0x0e,0x0e,0x00,0x26,0xc7,0x06,0x06,0x00,0x02,0x00,0x26,0xc6 +,0x06,0x19,0x00,0x00,0x26,0xc7,0x06,0x1a,0x00,0x00,0x00,0x26,0xc7,0x06,0x1c,0x00 +,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x00,0xe8,0x47,0x02,0x83,0xe9,0x0e,0x86 +,0xcd,0x26,0x89,0x0e,0x26,0x00,0x86,0xcd,0x26,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6 +,0x06,0x29,0x00,0x08,0xbf,0x2a,0x00,0x83,0xe9,0x04,0x26,0x89,0x0d,0x26,0xc6,0x45 +,0x01,0x26,0x8d,0x7d,0x02,0x83,0xe9,0x02,0xbb,0x01,0x00,0xb8,0x30,0x30,0x4b,0x75 +,0x17,0xbb,0x0a,0x00,0x8a,0xc4,0x26,0x88,0x05,0xb0,0x31,0x80,0xc4,0x01,0x80,0xfc +,0x3a,0x75,0x0a,0xb4,0x61,0xe9,0x05,0x00,0x26,0x88,0x05,0x04,0x01,0x47,0x49,0x75 +,0xdd,0xc3,0x26,0xc7,0x06,0x04,0x00,0x04,0x45,0x26,0xc7,0x06,0x0e,0x00,0x12,0x00 +,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x01,0xe8,0xe5,0x01 +,0xe8,0xd0,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x04,0x26,0xc6,0x06,0x28,0x00,0x00 +,0x26,0xc6,0x06,0x29,0x00,0x07,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7 +,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19 +,0x00,0x06,0xe8,0x04,0x02,0xe8,0x9b,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26 +,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x06,0xbf,0x2a,0x00,0xe8,0x6b +,0x02,0xe8,0xfb,0x01,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e +,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x05 +,0xe8,0xc6,0x01,0xe8,0x5d,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06 +,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x05,0xbf,0x2a,0x00,0xe8,0x2d,0x02,0xe8 +,0xbd,0x01,0xc3,0xff,0x06,0x82,0x34,0x26,0xc7,0x06,0x04,0x00,0x3d,0x41,0x26,0xc7 +,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x0e,0x00,0x26,0xc6,0x06,0x19 +,0x00,0x04,0xe8,0x84,0x01,0xe8,0x1b,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26 +,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x04,0xbf,0x2a,0x00,0xe8,0xeb +,0x01,0xe8,0x7b,0x01,0xc3,0x26,0xc7,0x06,0x04,0x00,0x67,0x42,0x26,0xc7,0x06,0x0e +,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x08,0x00,0x26,0xc6,0x06,0x19,0x00,0x03 +,0xe8,0x46,0x01,0xe8,0xdd,0x00,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06 +,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x03,0xbf,0x2a,0x00,0xe8,0xad,0x01,0xe8 +,0x3d,0x01,0xc3,0xff,0x06,0x84,0x34,0x26,0xc7,0x06,0x04,0x00,0x67,0x42,0x26,0xc7 +,0x06,0x0e,0x00,0x24,0x00,0x26,0xc7,0x06,0x06,0x00,0x08,0x00,0x26,0xc6,0x06,0x19 +,0x00,0x02,0xe8,0x04,0x01,0xe8,0x9b,0x00,0x26,0xc7,0x06,0x26,0x00,0x00,0x16,0x26 +,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x02,0xbf,0x2a,0x00,0x26,0xc6 +,0x05,0x04,0x26,0xc6,0x45,0x01,0x01,0xa1,0x0f,0x37,0x86,0xe0,0xf6,0x06,0x6f,0x37 +,0x01,0x75,0x0f,0x39,0x06,0xcc,0x34,0x74,0x09,0x8b,0xd8,0xb8,0x89,0x03,0xcd,0x39 +,0x8b,0xc3,0xa3,0xcc,0x34,0x26,0x89,0x45,0x02,0x8d,0x7d,0x04,0xe8,0x3d,0x01,0xe8 +,0xcd,0x00,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x1c +,0x00,0xa1,0xa2,0x37,0x50,0x0b,0xc0,0x75,0x07,0x26,0xc7,0x06,0x0e,0x00,0x18,0x00 +,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x23,0x00 +,0xe8,0x2e,0xfa,0x26,0xc7,0x45,0x26,0x00,0x0e,0x58,0x0b,0xc0,0x75,0x06,0x26,0xc7 +,0x45,0x26,0x00,0x0a,0x26,0xc6,0x45,0x29,0x00,0x83,0xc7,0x2a,0xe8,0xbd,0x00,0xe8 +,0xff,0x00,0xc3,0x56,0x57,0x51,0xb9,0x03,0x00,0xbe,0xd1,0x36,0xbf,0x20,0x00,0xf3 +,0xa5,0x59,0x5f,0x5e,0xc3,0x56,0x57,0x51,0xb9,0x03,0x00,0xbe,0xd1,0x36,0xbf,0x1a +,0x00,0xf3,0xa5,0x59,0x5f,0x5e,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00,0x26,0xc7 +,0x06,0x1c,0x00,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x10,0xc3,0x26,0xc7,0x06 +,0x1a,0x00,0xc0,0x00,0x26,0xc7,0x06,0x1c,0x00,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00 +,0x00,0x08,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00,0x26,0xc7,0x06,0x1c,0x00,0x00 +,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x02,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00 +,0x26,0xc7,0x06,0x1c,0x00,0xff,0xff,0x26,0xc7,0x06,0x1e,0x00,0xff,0xff,0xc3,0x26 +,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x02,0x8d,0x7d,0x02,0xbe,0x05,0x37,0xb9,0x03 +,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x06,0xa1,0x0d,0x37 +,0x26,0x89,0x45,0x02,0x8d,0x7d,0x04,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01 +,0x07,0xa1,0x0b,0x37,0x26,0x89,0x45,0x02,0x83,0xc7,0x04,0xc3,0xa1,0xa2,0x37,0x0b +,0xc0,0x74,0x13,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x09,0xa1,0x03,0x37,0x26 +,0x89,0x45,0x02,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x02 +,0x8d,0x7d,0x02,0xbe,0x05,0x37,0xb9,0x03,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x06 +,0x26,0xc6,0x45,0x01,0x0b,0x8d,0x7d,0x02,0xbe,0xef,0x36,0xb9,0x02,0x00,0xf3,0xa5 +,0xc3,0x26,0xc6,0x05,0x06,0x26,0xc6,0x45,0x01,0x20,0xa1,0x68,0x37,0x26,0x89,0x45 +,0x02,0xa1,0x6a,0x37,0x26,0x88,0x65,0x05,0xc1,0xe0,0x04,0x26,0x88,0x45,0x04,0x83 +,0xc7,0x06,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x21,0x26,0xc7,0x45,0x02 +,0x00,0x00,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x14,0x26,0xc6,0x45,0x01,0x22,0x8d +,0x7d,0x02,0xbe,0x1f,0x37,0xb9,0x09,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x0c,0x26 +,0xc6,0x45,0x01,0x23,0x8d,0x7d,0x02,0x1e,0x0e,0x1f,0x8d,0x36,0x40,0x54,0xb9,0x03 +,0x00,0xf3,0xa5,0x33,0xc0,0xb9,0x02,0x00,0xf3,0xab,0x1f,0xc3,0x26,0xc6,0x05,0x08 +,0x26,0xc6,0x45,0x01,0x28,0x8d,0x7d,0x02,0xbe,0xd1,0x36,0xb9,0x03,0x00,0xf3,0xa5 +,0xc3,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x29,0xa1,0xc2,0x34,0x86,0xe0,0x26 +,0x89,0x45,0x02,0xa1,0x9b,0x36,0x26,0x89,0x45,0x04,0x26,0x88,0x45,0x06,0x26,0x88 +,0x45,0x07,0x8d,0x7d,0x08,0xc3,0x26,0xc6,0x05,0x06,0x26,0xc6,0x45,0x01,0x2b,0x8d +,0x7d,0x02,0xbe,0xbb,0x36,0xb9,0x02,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x06,0x26 +,0xc6,0x45,0x01,0x2c,0x8d,0x7d,0x02,0xbe,0xe5,0x36,0xb9,0x02,0x00,0xf3,0xa5,0xc3 +,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x30,0xa1,0x37,0x37,0x86,0xe0,0x26,0x89 +,0x45,0x02,0x8d,0x7d,0x04,0xc3,0x26,0xc7,0x06,0x0e,0x00,0x1e,0x00,0x26,0xc7,0x06 +,0x06,0x00,0x02,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x6c,0xfe,0xe8,0x03,0xfe +,0x26,0xc7,0x06,0x26,0x00,0x00,0x10,0x26,0xc6,0x06,0x28,0x00,0x30,0x26,0xc6,0x06 +,0x29,0x00,0x11,0xbf,0x2a,0x00,0xe8,0x35,0x00,0xe8,0x45,0x00,0xe8,0x55,0x00,0xc3 +,0x26,0xc7,0x06,0x0e,0x00,0x12,0x00,0x26,0xc7,0x06,0x06,0x00,0x02,0x00,0x26,0xc6 +,0x06,0x19,0x00,0x00,0xe8,0x32,0xfe,0xe8,0xc9,0xfd,0x26,0xc7,0x06,0x26,0x00,0x00 +,0x04,0x26,0xc6,0x06,0x28,0x00,0x30,0x26,0xc6,0x06,0x29,0x00,0x13,0xc3,0x26,0xc6 +,0x05,0x04,0x26,0xc6,0x45,0x01,0x0c,0x26,0xc7,0x45,0x02,0x00,0x01,0x83,0xc7,0x04 +,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x0e,0x26,0xc7,0x45,0x02,0x00,0x02 +,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x21,0x26,0xc7,0x45 +,0x02,0x00,0x00,0x83,0xc7,0x04,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xb3,0x39,0xc9,0x39,0x83,0x3a,0xb3,0x39,0xb3,0x39,0xb3,0x39,0x1c,0x3a,0x1c,0x3a +,0xa3,0xb6,0x34,0xa1,0xe9,0x36,0xa3,0x11,0x37,0xa3,0xd2,0x34,0xa1,0xeb,0x36,0xa3 +,0x13,0x37,0xa3,0xd4,0x34,0xa1,0xed,0x36,0xa3,0x15,0x37,0xa3,0xd6,0x34,0xa1,0x01 +,0x37,0xa3,0xce,0x34,0xa1,0xf7,0x36,0xa3,0x17,0x37,0xa3,0xdc,0x34,0xa1,0xf9,0x36 +,0xa3,0x19,0x37,0xa3,0xde,0x34,0xf7,0x06,0x9b,0x36,0x02,0x00,0x75,0x0c,0x33,0xc0 +,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0x50,0x39,0xe9,0x0f,0x01,0xbe,0x07,0x00 +,0xe9,0x19,0xf1,0xf6,0x06,0x9d,0x36,0x80,0x74,0xf3,0xc6,0x06,0xa0,0x36,0x02,0xc6 +,0x06,0x6e,0x37,0x08,0xc6,0x06,0x70,0x37,0x02,0xb8,0x88,0x03,0xcd,0x39,0xf6,0x06 +,0x6f,0x37,0x01,0x75,0x4a,0xa1,0xd1,0x36,0x3a,0x06,0xe9,0x36,0x75,0x41,0x3a,0x26 +,0xea,0x36,0x75,0x3b,0xa1,0xd3,0x36,0x3a,0x06,0xeb,0x36,0x75,0x32,0x3a,0x26,0xec +,0x36,0x75,0x2c,0xa1,0xd5,0x36,0x3a,0x06,0xed,0x36,0x75,0x23,0x3a,0x26,0xee,0x36 +,0x75,0x1d,0xc6,0x06,0x70,0x37,0x02,0xfe,0x0e,0x6e,0x37,0x75,0x0f,0xb8,0x88,0x03 +,0xcd,0x3a,0x83,0x0e,0x9b,0x36,0x12,0xc6,0x06,0xa0,0x36,0x0c,0xe9,0xa8,0xf0,0xa1 +,0x05,0x37,0x26,0x3b,0x06,0x20,0x00,0x75,0x40,0xa1,0x07,0x37,0x26,0x3b,0x06,0x22 +,0x00,0x75,0x36,0xa1,0x09,0x37,0x26,0x3b,0x06,0x24,0x00,0x75,0x2c,0xa0,0x9e,0x36 +,0x3c,0x02,0x75,0x08,0x26,0xf6,0x06,0x18,0x00,0x08,0x75,0x47,0xc6,0x06,0x6e,0x37 +,0x08,0xfe,0x0e,0x70,0x37,0x75,0x1c,0xc6,0x06,0x70,0x37,0x02,0xe5,0x02,0x0d,0x01 +,0x04,0x25,0xef,0xff,0xe7,0x02,0xe9,0x5e,0xf0,0xc6,0x06,0x70,0x37,0x02,0xc6,0x06 +,0x6e,0x37,0x08,0xe5,0x02,0x25,0xff,0xfb,0x0d,0x01,0x00,0x25,0xef,0xff,0xe7,0x02 +,0xe9,0x44,0xf0,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x25,0x26,0xf6,0x06,0x18,0x00 +,0x08,0x75,0xed,0x81,0x26,0x9b,0x36,0x7f,0xff,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x84 +,0x03,0xcd,0x3a,0xc6,0x06,0xa0,0x36,0x06,0x83,0x26,0xc2,0x34,0xaf,0xe9,0x17,0xf0 +,0xa1,0x01,0x37,0x3a,0x26,0x0f,0x37,0x7f,0xc7,0xe9,0xf7,0xfe,0x83,0x26,0x9b,0x36 +,0xec,0xe8,0x2a,0x0d,0x81,0x0e,0x9b,0x36,0x80,0x00,0xbb,0xff,0x7f,0xcd,0x53,0xc6 +,0x06,0xa0,0x36,0x02,0xe9,0xf0,0xef,0x83,0x0e,0x9b,0x36,0x11,0xc6,0x06,0xa0,0x36 +,0x0c,0xe9,0xf9,0xef,0x44,0x3b,0x2c,0x3b,0xc7,0x2a,0x6b,0x3b,0x44,0x3b,0xc7,0x2a +,0xc7,0x2a,0xc7,0x2a,0xa3,0xb6,0x34,0x81,0x0e,0xc2,0x34,0x00,0x20,0xf7,0x06,0x41 +,0x37,0x01,0x00,0x74,0x1b,0x8c,0xc3,0xc7,0x06,0x41,0x37,0x00,0x00,0xb8,0x7f,0x03 +,0xcd,0x3a,0x33,0xc0,0x8e,0xc0,0xbf,0x54,0x37,0xb9,0x06,0x00,0xf3,0xab,0x8e,0xc3 +,0x33,0xc0,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0xe4,0x3a,0xf7,0x06,0x9b,0x36 +,0x00,0x01,0x75,0x21,0x83,0x26,0xc2,0x34,0xbf,0xa1,0xa9,0x36,0xe7,0x00,0xa1,0x9b +,0x36,0xe9,0x09,0x00,0xa1,0x9b,0x36,0x81,0x26,0x9b,0x36,0xff,0xdf,0xa9,0x00,0x20 +,0x75,0x06,0xe9,0x6e,0x00,0xe9,0x6f,0xef,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37 +,0x37,0x01,0x00,0xc6,0x06,0xca,0x34,0x01,0xe9,0x58,0x00,0x83,0x0e,0x9b,0x36,0x40 +,0xe8,0x58,0x00,0xa1,0x05,0x37,0x3b,0x06,0xe9,0x36,0x75,0x37,0xa1,0x07,0x37,0x3b +,0x06,0xeb,0x36,0x75,0x2e,0xa1,0x09,0x37,0x3b,0x06,0xed,0x36,0x75,0x25,0xfe,0x0e +,0x71,0x37,0x75,0x1c,0xb8,0x87,0x03,0xcd,0x3a,0x83,0x0e,0x99,0x36,0x10,0xa1,0x50 +,0x37,0xc7,0x06,0x50,0x37,0x00,0x00,0x09,0x06,0x99,0x36,0xc6,0x06,0xa0,0x36,0x08 +,0xe9,0x14,0xef,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37,0x37,0x03,0x00,0xc6,0x06 +,0xca,0x34,0x03,0xc6,0x06,0xa0,0x36,0x0a,0xe9,0xfc,0xee,0xa1,0xd1,0x36,0x26,0x3b +,0x06,0x20,0x00,0x75,0x15,0xa1,0xd3,0x36,0x26,0x3b,0x06,0x22,0x00,0x75,0x12,0xa1 +,0xd5,0x36,0x26,0x3b,0x06,0x24,0x00,0x75,0x0f,0xc3,0x8d,0x36,0x20,0x00,0xe9,0x0b +,0x00,0x8d,0x36,0x22,0x00,0xe9,0x04,0x00,0x8d,0x36,0x24,0x00,0x83,0xc4,0x02,0xf7 +,0x06,0xe6,0x34,0x01,0x00,0x74,0x15,0x26,0x3a,0x04,0x77,0x08,0x72,0x0e,0x26,0x3a +,0x64,0x01,0x72,0x08,0xc6,0x06,0xa0,0x36,0x06,0xe9,0xab,0xee,0xe8,0x7c,0x0a,0x8c +,0xc0,0x3d,0xff,0xff,0x74,0x1b,0x26,0xc6,0x06,0x18,0x00,0x10,0x26,0xc7,0x06,0x04 +,0x00,0x49,0x3c,0x26,0xc7,0x06,0x06,0x00,0x0c,0x00,0xcd,0x50,0xb9,0x4e,0x00,0xe2 +,0xfe,0xc6,0x06,0xa0,0x36,0x0a,0xe9,0x94,0xee,0xe9,0x7b,0xee,0x8f,0x3c,0x06,0x3d +,0x06,0x3d,0x06,0x3d,0xd2,0x3c,0xea,0x3c,0x06,0x3d,0x06,0x3d,0xa3,0xb6,0x34,0x81 +,0x26,0xc2,0x34,0xaf,0xdf,0xc7,0x06,0x4c,0x37,0x00,0x00,0xb8,0x8a,0x03,0xcd,0x3a +,0x80,0x3e,0x9d,0x36,0x04,0x75,0x0c,0x80,0x3e,0x9e,0x36,0x06,0x74,0x05,0xc6,0x06 +,0x9f,0x36,0x06,0x33,0xc0,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0x4c,0x3c,0xf7 +,0x06,0x9b,0x36,0x00,0x20,0x75,0x0e,0x81,0x26,0x9b,0x36,0xff,0xbf,0xb8,0x8b,0x03 +,0xcd,0x3a,0xe9,0x54,0x00,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x03,0xe9,0x17,0xee +,0xc7,0x06,0x37,0x37,0x02,0x00,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04 +,0x83,0x0e,0x50,0x37,0x04,0xf6,0x06,0x9d,0x36,0x80,0x75,0x2a,0xe8,0x1f,0x0b,0xe9 +,0x27,0x00,0xf7,0x06,0x9b,0x36,0x00,0x01,0x75,0xd3,0xc7,0x06,0x37,0x37,0x02,0x00 +,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04,0xc6,0x06,0xa0,0x36,0x00,0xf6 +,0x06,0x9d,0x36,0x80,0x74,0x03,0xe8,0xde,0x0a,0x81,0x26,0x9b,0x36,0x7c,0xff,0xbb +,0xff,0xff,0xcd,0x53,0xcd,0x54,0xe9,0xbe,0xed,0xa3,0xb6,0x34,0xe8,0xad,0x01,0xb8 +,0x86,0x03,0xcd,0x39,0xc7,0x06,0x4c,0x37,0x00,0x00,0x81,0x26,0xc2,0x34,0xaf,0xdf +,0xf6,0x06,0x9d,0x36,0x80,0x74,0x34,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x56,0xf7 +,0x06,0x9b,0x36,0x00,0x01,0x74,0x27,0xe8,0x35,0x01,0x72,0x1c,0xbe,0x00,0x40,0x85 +,0x36,0xc2,0x34,0x75,0x08,0x09,0x36,0xc2,0x34,0xff,0x06,0x92,0x34,0xe8,0x8b,0x01 +,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00,0xe9,0x6c,0xed,0xe9,0xb5,0x00,0xc7,0x06 +,0x37,0x37,0x02,0x00,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04,0x83,0x0e +,0x50,0x37,0x04,0x80,0x3e,0x9e,0x36,0x08,0x74,0x03,0xe8,0x5a,0x0a,0xe8,0xef,0x00 +,0x72,0xd6,0xe9,0xc8,0xff,0x80,0x3e,0x9e,0x36,0x0a,0x75,0x12,0xc6,0x06,0xa0,0x36 +,0x00,0xf7,0x06,0x9b,0x36,0x08,0x00,0x74,0x02,0xcd,0x54,0xe8,0x39,0x0a,0x81,0x26 +,0x9b,0x36,0xff,0xbf,0xe8,0xc8,0x00,0x72,0xaf,0xb8,0x8b,0x03,0xcd,0x39,0xe9,0x9c +,0xff,0xf6,0x06,0x9e,0x36,0xff,0x75,0x58,0xa3,0xb6,0x34,0xe8,0xfe,0x00,0x81,0x26 +,0xc2,0x34,0xff,0xbf,0xf6,0x06,0x9d,0x36,0x80,0x74,0x48,0xf7,0x06,0x9b,0x36,0x00 +,0x20,0x74,0x22,0xf7,0x06,0x9b,0x36,0x00,0x40,0x75,0x08,0xe8,0x91,0x00,0x72,0x30 +,0xe9,0x22,0x00,0x26,0xa1,0x0c,0x00,0xa9,0x60,0x00,0x75,0x24,0x81,0x0e,0x66,0x37 +,0x00,0x08,0xe9,0xd2,0xec,0xc7,0x06,0x4c,0x37,0x00,0x00,0xe8,0x71,0x00,0x72,0x10 +,0xb8,0x8b,0x03,0xcd,0x39,0xe8,0xd3,0x00,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00 +,0xe9,0xb4,0xec,0x80,0x3e,0x9d,0x36,0x04,0x75,0x0c,0x80,0x3e,0x9e,0x36,0x06,0x74 +,0x46,0xc6,0x06,0x9f,0x36,0x06,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x0c,0x80,0x3e +,0x9d,0x36,0x08,0x75,0x05,0xc6,0x06,0x9f,0x36,0x0a,0xe8,0x32,0x00,0x72,0xd1,0xe8 +,0x99,0x00,0x80,0x3e,0x9d,0x36,0x08,0x75,0x13,0x81,0x0e,0x99,0x36,0x80,0x00,0xf7 +,0x06,0x9b,0x36,0x00,0x20,0x75,0x08,0xb8,0x8b,0x03,0xcd,0x39,0xe9,0x68,0xec,0xc6 +,0x06,0x9f,0x36,0x0a,0xe9,0x60,0xec,0xb8,0x86,0x03,0xcd,0x3a,0xe9,0x58,0xec,0x26 +,0xa1,0x0c,0x00,0xa9,0x60,0x00,0x74,0x08,0x81,0x26,0xc2,0x34,0xff,0xbf,0xf9,0xc3 +,0xf7,0x06,0x9b,0x36,0x00,0x40,0x74,0x13,0x81,0x0e,0x66,0x37,0x00,0x08,0xe8,0x4a +,0x00,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00,0xf9,0xc3,0x81,0x0e,0x9b,0x36,0x00 +,0x40,0x80,0x26,0x6f,0x37,0xfe,0x81,0x26,0x9b,0x36,0x7f,0xff,0xc6,0x06,0xa0,0x36 +,0x00,0xf8,0xc3,0x81,0x0e,0x99,0x36,0x00,0x01,0xe9,0x21,0xec,0x26,0xa1,0x20,0x00 +,0xa3,0xfb,0x36,0xa3,0xaa,0x34,0x26,0xa1,0x22,0x00,0xa3,0xfd,0x36,0xa3,0xac,0x34 +,0x26,0xa1,0x24,0x00,0xa3,0xff,0x36,0xa3,0xae,0x34,0xc3,0xa1,0x05,0x37,0x26,0x3b +,0x06,0x20,0x00,0x75,0x19,0xa1,0x07,0x37,0x26,0x3b,0x06,0x22,0x00,0x75,0x0f,0xa1 +,0x09,0x37,0x26,0x3b,0x06,0x24,0x00,0x75,0x05,0xe8,0x02,0x00,0xf8,0xc3,0x51,0x1e +,0x06,0x8b,0xc7,0x8d,0x36,0x20,0x00,0xbf,0x05,0x37,0xb9,0x03,0x00,0x1e,0x06,0x1f +,0x07,0xf3,0xa5,0x8b,0xf8,0x8d,0x36,0x20,0x00,0xbf,0xa0,0x34,0xb9,0x03,0x00,0xf3 +,0xa5,0x07,0x1f,0x59,0x8b,0xf8,0xa1,0x07,0x37,0xa3,0xa6,0x34,0xa1,0x09,0x37,0xa3 +,0xa8,0x34,0xf9,0xc3,0xc6,0x06,0xb6,0x34,0x01,0xe9,0x8b,0xeb,0xe8,0x87,0x08,0x8b +,0xf0,0x05,0x12,0x00,0x26,0x29,0x06,0x0e,0x00,0x26,0x8b,0x44,0x2a,0x26,0x3a,0x06 +,0x0e,0x00,0x75,0x5b,0x26,0x83,0x2e,0x0e,0x00,0x02,0x80,0xfc,0x27,0x75,0x50,0x26 +,0x8b,0x44,0x2c,0xa9,0xff,0xff,0x75,0x47,0x8b,0xfe,0x33,0xc0,0x26,0xf6,0x45,0x3c +,0x80,0x74,0x06,0x26,0x8a,0x45,0x3a,0x24,0x1f,0x03,0xf8,0x26,0x80,0x7d,0x45,0x09 +,0x75,0x2d,0x8c,0xc2,0x8e,0x06,0x38,0x34,0x8e,0xda,0x8b,0x0e,0x0e,0x00,0x26,0x89 +,0x0e,0x0e,0x00,0x8d,0x74,0x2c,0xbf,0x18,0x00,0xf3,0xa4,0x33,0xc0,0x8e,0xd8,0x26 +,0xc7,0x06,0x04,0x00,0xb5,0x3f,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0xcd,0x50,0xb8 +,0x06,0x80,0xe9,0xef,0xe9,0x26,0xa1,0x0c,0x00,0xa3,0x93,0x37,0x83,0x0e,0x99,0x36 +,0x01,0xe9,0x00,0xeb,0x26,0x80,0x3e,0x1c,0x00,0xff,0x75,0x2f,0x26,0x80,0x3e,0x1e +,0x00,0xff,0x75,0x27,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00,0x75,0x1b,0xa1,0xd1,0x36 +,0x26,0xa3,0x1a,0x00,0xa1,0xd3,0x36,0x26,0xa3,0x1c,0x00,0xa1,0xd5,0x36,0x26,0xa3 +,0x1e,0x00,0xb8,0x0a,0x80,0xe8,0x36,0x07,0xe9,0xe2,0xea,0xff,0x06,0x90,0x34,0xbe +,0x0a,0x00,0xc6,0x06,0xb6,0x34,0x01,0xf6,0x06,0x9d,0x36,0x80,0x75,0x05,0x83,0x0e +,0xc2,0x34,0x01,0xe9,0xb6,0xea,0x80,0x3e,0x9d,0x36,0x0a,0x75,0x0f,0x26,0xa1,0x0c +,0x00,0x25,0x07,0x00,0x3d,0x04,0x00,0x75,0x03,0xe8,0x79,0x00,0xa1,0xf3,0x36,0x86 +,0xe0,0xe7,0x1e,0xa3,0xe3,0x36,0x81,0x26,0x0b,0x37,0x00,0x03,0x81,0x26,0x0d,0x37 +,0x7b,0x7f,0x83,0x0e,0x0d,0x37,0x48,0xe8,0x1e,0x00,0x26,0xa1,0x0c,0x00,0x25,0x07 +,0x00,0x3d,0x04,0x00,0x74,0x09,0x26,0xf7,0x06,0x0c,0x00,0x20,0x00,0x75,0x06,0xb8 +,0x01,0x00,0xe9,0x3f,0xe9,0xe9,0x5f,0xea,0xc7,0x06,0x41,0x37,0x00,0x00,0xb8,0x7f +,0x03,0xcd,0x3a,0xa1,0x1d,0x37,0xa3,0xc4,0x34,0x86,0xe0,0x68,0x7f,0x03,0x1f,0xa3 +,0x06,0x00,0x33,0xc0,0x8e,0xd8,0xa1,0x0b,0x37,0xa3,0xb2,0x34,0xa1,0x0d,0x37,0xa3 +,0xb4,0x34,0xa1,0xf3,0x36,0xa3,0xc8,0x34,0xa1,0xef,0x36,0xa3,0x9c,0x34,0xa1,0xf1 +,0x36,0xa3,0x9e,0x34,0xc3,0x80,0x0e,0x9d,0x36,0x80,0xbe,0x00,0x00,0xe8,0xb4,0x07 +,0xb8,0x7b,0x03,0xcd,0x3a,0xb8,0x7c,0x03,0xcd,0x39,0xc7,0x06,0x33,0x37,0x02,0x00 +,0xa1,0xe5,0x36,0xe7,0x2e,0xa1,0xe7,0x36,0xe7,0x3e,0xb8,0x82,0x03,0xcd,0x3a,0xf7 +,0x06,0x9b,0x36,0x00,0x20,0x75,0x03,0xe8,0xfd,0x06,0xa1,0xd3,0x36,0xa3,0xef,0x36 +,0xa3,0x9c,0x34,0xa1,0xd5,0x36,0xa3,0xf1,0x36,0xa3,0x9e,0x34,0xc3,0xf6,0x06,0x9d +,0x36,0x80,0x74,0x31,0xbe,0x22,0x00,0xe9,0x17,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74 +,0x24,0xbe,0x23,0x00,0xe9,0x0a,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74,0x17,0xbe,0x24 +,0x00,0x56,0xe8,0xa8,0x05,0x8c,0xc0,0x3d,0xff,0xff,0x5e,0x74,0x05,0xe8,0xd7,0xef +,0xcd,0x50,0xe9,0x1f,0xe8,0xe9,0x9f,0xe9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0xb8,0x84,0x03,0xcd,0x3a,0xb8,0x8a,0x03,0xcd,0x39,0xe9,0xf7,0x00,0x80,0x3e,0xa0 +,0x36,0x08,0x75,0x2e,0xa9,0xd0,0x07,0x75,0x2c,0xa1,0xb1,0x36,0x0d,0x00,0x04,0xe7 +,0x08,0xe5,0x00,0x25,0xff,0x73,0xe7,0x00,0xb8,0x8a,0x03,0xcd,0x3a,0xe8,0xc3,0x06 +,0x33,0xc0,0xe7,0x0e,0xe5,0x0a,0x25,0xc3,0x17,0xe7,0x0a,0xcd,0x54,0xc6,0x06,0xa0 +,0x36,0x00,0xe9,0x68,0xe9,0xbe,0x04,0x00,0xe9,0x3f,0xe9,0x83,0x26,0x9b,0x36,0xbf +,0xc6,0x06,0x71,0x37,0x03,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x88,0x03,0xcd,0x3a,0xb8 +,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x39,0x81,0x0e,0xc2,0x34,0x00,0x20,0xe9 +,0x92,0x00,0xe8,0x49,0x06,0xb8,0x87,0x03,0xcd,0x39,0xbb,0xff,0x7f,0xcd,0x53,0xb8 +,0x84,0x03,0xcd,0x3a,0xb8,0x88,0x03,0xcd,0x3a,0xb8,0x8b,0x03,0xcd,0x3a,0xb8,0x83 +,0x03,0xcd,0x3a,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd,0x3a,0xc3,0xe5,0x00 +,0x25,0xff,0x53,0xe7,0x00,0x83,0x0e,0xc2,0x34,0x40,0x83,0x26,0xc2,0x34,0xef,0xe8 +,0x0c,0x06,0xbb,0xff,0x7f,0xcd,0x53,0xb8,0x8a,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd +,0x3a,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x3a +,0xb8,0x8b,0x03,0xcd,0x3a,0xb8,0x84,0x03,0xcd,0x3a,0xb8,0x89,0x03,0xcd,0x3a,0xc3 +,0x83,0x0e,0xc2,0x34,0x50,0xe8,0x18,0x04,0xe8,0xd3,0x05,0xf6,0x06,0x6f,0x37,0x01 +,0x75,0x12,0xb8,0x89,0x03,0xcd,0x39,0x83,0x3e,0x0f,0x37,0x00,0x75,0x06,0xc7,0x06 +,0x0f,0x37,0x04,0x00,0xa1,0x9d,0x36,0x80,0xfc,0x08,0x74,0x05,0xb8,0x84,0x03,0xcd +,0x39,0xe5,0x02,0x0d,0x01,0x08,0x25,0xef,0xff,0xe7,0x02,0xa1,0x9d,0x36,0x86,0xe0 +,0x32,0xe4,0x8b,0xf0,0xd1,0xee,0x33,0xc0,0x0d,0x20,0x00,0x09,0x06,0xad,0x36,0xa1 +,0xad,0x36,0xe7,0x04,0xe9,0x53,0xe8,0xe9,0x5a,0xe8,0x33,0xc0,0xa0,0x1b,0x37,0xd1 +,0xe0,0x3a,0x06,0xa0,0x36,0x75,0x03,0xe9,0xba,0xff,0xe9,0x60,0xe8,0xc7,0x06,0x41 +,0x37,0x00,0x00,0xe8,0xc1,0xe1,0xe8,0x6a,0x06,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56 +,0xa1,0xb1,0x36,0x0d,0x00,0x10,0xe7,0x08,0xe5,0x02,0x25,0xf9,0xff,0x0d,0x03,0x00 +,0xe7,0x02,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xa1,0xad,0x36,0xe7 +,0x04,0xe8,0x7c,0x03,0xe8,0x9f,0x03,0xc7,0x06,0x1d,0x37,0x00,0xc8,0xc7,0x06,0x0b +,0x37,0x00,0x03,0xc7,0x06,0x0d,0x37,0x7b,0x7f,0x33,0xc0,0xa3,0x99,0x36,0xa3,0x9b +,0x36,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xa3,0x4c,0x37,0xa3,0xf3,0x36,0xa3,0xef,0x36 +,0xa3,0xf1,0x36,0xe8,0x82,0xfd,0xc6,0x06,0x9f,0x36,0x02,0xe9,0xef,0xe7,0xe5,0x02 +,0x0d,0x01,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02,0xe8,0xf2 +,0x05,0xe5,0x0a,0x0d,0x40,0x00,0xe7,0x0a,0x33,0xc0,0xa3,0x81,0x37,0xa3,0x85,0x37 +,0xa3,0x83,0x37,0xa3,0x87,0x37,0xa3,0x89,0x37,0xe5,0x00,0x0d,0x00,0x84,0xe7,0x00 +,0xb8,0x8c,0x03,0xcd,0x39,0xb8,0x80,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff +,0xe5,0x00,0x25,0xff,0x7b,0xe7,0x00,0x81,0x0e,0x9a,0x37,0x80,0x00,0xb8,0x7e,0x03 +,0xcd,0x39,0x33,0xc0,0xe7,0x0e,0xbe,0x08,0x00,0x8e,0x06,0x38,0x34,0xe8,0xa7,0xed +,0x83,0x26,0xef,0x34,0xdf,0xff,0x06,0x81,0x37,0xcd,0x50,0x83,0x0e,0xef,0x34,0x20 +,0xc3,0xf7,0x06,0x9a,0x37,0x80,0x00,0x74,0x3d,0xa9,0xd0,0x07,0x74,0x10,0xa9,0x00 +,0x04,0x74,0x12,0x33,0xc0,0xe7,0x0e,0xff,0x06,0x87,0x37,0xe9,0xd2,0xff,0xff,0x06 +,0x85,0x37,0xe9,0xcb,0xff,0xff,0x06,0x83,0x37,0xe9,0xc4,0xff,0x83,0x26,0x9a,0x37 +,0x7f,0xa1,0x89,0x37,0x03,0x06,0x87,0x37,0x3d,0x05,0x00,0x7f,0x01,0xc3,0xbb,0xff +,0x7f,0xcd,0x53,0xe9,0x00,0x00,0xe5,0x02,0x25,0xff,0xfb,0x25,0xef,0xff,0x0d,0x01 +,0x00,0xe7,0x02,0xa1,0x83,0x37,0x3b,0x06,0x46,0x37,0x7f,0x2a,0xa1,0x85,0x37,0x3b +,0x06,0x48,0x37,0x7c,0x21,0xa1,0x89,0x37,0x03,0x06,0x87,0x37,0x3d,0x05,0x00,0x7f +,0x15,0xc6,0x06,0x9f,0x36,0x04,0xe5,0x02,0x25,0xff,0xf7,0x0d,0x01,0x00,0x25,0xef +,0xff,0xe7,0x02,0xe9,0xf7,0xe6,0xbe,0x01,0x00,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74 +,0x0a,0x83,0x26,0x9b,0x36,0xfc,0x83,0x0e,0xc2,0x34,0x04,0xe9,0xd0,0xe6,0xb8,0x7b +,0x03,0xcd,0x39,0xe5,0x02,0x0d,0x01,0x60,0x25,0xef,0xff,0xe7,0x02,0xc7,0x06,0xf1 +,0x34,0x20,0x03,0xb8,0x8e,0x03,0xcd,0x39,0xc3,0x81,0x26,0xc2,0x34,0x7f,0xff,0x80 +,0x0e,0x6f,0x37,0x01,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74,0xd2,0xb8,0x7b,0x03,0xcd +,0x3a,0xb8,0x7d,0x03,0xcd,0x39,0x83,0x26,0x9b,0x36,0xef,0x33,0xc0,0xb0,0x8a,0xa2 +,0x9f,0x36,0xa2,0x9d,0x36,0xc7,0x06,0x4c,0x37,0x01,0x00,0xc7,0x06,0x0f,0x37,0x04 +,0x00,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06,0x0f,0x37,0x03,0x00,0xb8 +,0x8d,0x03,0xcd,0x39,0xe8,0x00,0xd5,0xe5,0x02,0x0d,0x01,0x40,0x25,0xef,0xff,0x8b +,0xd8,0xb8,0x7c,0x03,0xcd,0x39,0xc7,0x06,0x33,0x37,0x02,0x00,0x8b,0xc3,0x0d,0x00 +,0x20,0x25,0xf9,0xff,0x0b,0x06,0xe8,0x3a,0xe7,0x02,0xc3,0xff,0x0e,0xf1,0x34,0x75 +,0x01,0xc3,0xe5,0x4e,0xa9,0x01,0x00,0x75,0x12,0xe5,0x00,0xa9,0x00,0x04,0x75,0x05 +,0x0d,0x00,0x04,0xe7,0x00,0xb8,0x8e,0x03,0xcd,0x39,0xc3,0xe5,0x00,0xa9,0x00,0x04 +,0x74,0xf3,0x25,0xff,0xfb,0xe7,0x00,0xe9,0xeb,0xff,0xc6,0x06,0xa0,0x36,0x04,0x83 +,0x26,0x9b,0x36,0xfc,0x81,0x0e,0x9b,0x36,0x80,0x00,0xe9,0x10,0xe6,0xb8,0x8e,0x03 +,0xcd,0x3a,0xcd,0x54,0x81,0x0e,0xaf,0x36,0x00,0x18,0xa1,0xaf,0x36,0xe7,0x06,0xb8 +,0x7b,0x03,0xcd,0x39,0xa1,0xd3,0x36,0xa3,0x8f,0x37,0xa1,0xd5,0x36,0xa3,0x91,0x37 +,0xc7,0x06,0x8b,0x37,0x02,0x00,0xc7,0x06,0x8d,0x37,0x02,0x00,0x83,0x0e,0x99,0x36 +,0x40,0xe9,0xd9,0xe5,0x80,0x3e,0x9f,0x36,0x06,0x75,0x15,0xa9,0xd0,0x07,0x75,0xec +,0x25,0x00,0x18,0x75,0x0e,0xff,0x0e,0x8b,0x37,0x75,0xe1,0xc6,0x06,0x9f,0x36,0x08 +,0xe9,0xba,0xe5,0xff,0x0e,0x8d,0x37,0x75,0xd3,0xbe,0x08,0x00,0xe9,0x9f,0xe5,0xb8 +,0x7b,0x03,0xcd,0x39,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x08,0xc6,0x06,0x9f,0x36 +,0x0a,0xe9,0x0d,0x00,0xf7,0x06,0x9b,0x36,0x00,0x40,0x74,0x0b,0xb8,0x8b,0x03,0xcd +,0x39,0x81,0x0e,0x99,0x36,0x80,0x00,0xe9,0x83,0xe5,0xb8,0x7b,0x03,0xcd,0x39,0xc7 +,0x06,0x8b,0x37,0x04,0x00,0xc7,0x06,0x8d,0x37,0x04,0x00,0x81,0x0e,0x99,0x36,0x00 +,0x02,0xe9,0x69,0xe5,0xf6,0x06,0x9d,0x36,0x80,0x75,0x1b,0xa9,0xd0,0x07,0x75,0xeb +,0xa9,0x00,0x18,0x75,0x0c,0xff,0x0e,0x8d,0x37,0x75,0xe0,0xe8,0x17,0xfb,0xe9,0x4c +,0xe5,0xb8,0x82,0x03,0xcd,0x39,0xc3,0xff,0x0e,0x8b,0x37,0x75,0xce,0xbe,0x09,0x00 +,0xe9,0x2b,0xe5,0xc7,0x06,0x3d,0x37,0x00,0x00,0xc7,0x06,0x9b,0x36,0x00,0x00,0xe8 +,0x3c,0x02,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0x81,0x26,0x9b +,0x36,0xff,0x7f,0xe5,0x02,0x0d,0x01,0x00,0x25,0xef,0xff,0x25,0xff,0xdf,0xe7,0x02 +,0xbb,0xff,0x7f,0xcd,0x53,0x33,0xc0,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xe8,0x50,0x00 +,0xe8,0x73,0x00,0xb8,0x81,0x03,0xcd,0x39,0xc3,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74 +,0x0d,0xc6,0x06,0x9f,0x36,0x02,0xc6,0x06,0xa0,0x36,0x00,0xe9,0xdf,0xe4,0x83,0x0e +,0x9b,0x36,0x10,0xc7,0x06,0x99,0x36,0x00,0x00,0xe8,0xe7,0x02,0xe5,0x56,0x0d,0x02 +,0x00,0xe7,0x56,0xc7,0x06,0xa8,0x02,0x00,0x00,0x8b,0x36,0x3d,0x37,0xe8,0x44,0x02 +,0xc6,0x06,0xa0,0x36,0x0e,0xe9,0xb5,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x06,0xb8,0x8a,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd,0x3a,0xb8,0x86,0x03,0xcd,0x3a +,0xb8,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x3a,0xb8,0x8b,0x03,0xcd,0x3a,0xb8 +,0x88,0x03,0xcd,0x3a,0x07,0xc3,0x06,0xb8,0x88,0x03,0xcd,0x3a,0xb8,0x7b,0x03,0xcd +,0x3a,0xb8,0x82,0x03,0xcd,0x3a,0xb8,0x7f,0x03,0xcd,0x3a,0xb8,0x7c,0x03,0xcd,0x3a +,0xb8,0x7e,0x03,0xcd,0x3a,0xb8,0x80,0x03,0xcd,0x3a,0xb8,0x81,0x03,0xcd,0x3a,0xb8 +,0x84,0x03,0xcd,0x3a,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x7d,0x03,0xcd,0x3a,0xb8,0x8d +,0x03,0xcd,0x3a,0xc7,0x06,0x41,0x37,0x00,0x00,0x07,0xc3,0x06,0x8e,0x06,0x38,0x34 +,0x1f,0x8b,0x0e,0x0e,0x00,0x26,0x89,0x0e,0x0e,0x00,0xbe,0x18,0x00,0xbf,0x18,0x00 +,0xf3,0xa4,0x06,0x1e,0x07,0xcd,0x34,0x07,0x33,0xc0,0x8e,0xd8,0xc3,0x26,0xf6,0x06 +,0x20,0x00,0x80,0x74,0x44,0x33,0xc0,0x26,0xa0,0x26,0x00,0x24,0x1f,0x8b,0xf0,0x26 +,0x8b,0x5c,0x28,0x89,0x1e,0x6a,0x37,0x06,0x8e,0x06,0x38,0x34,0x1f,0xc0,0xe3,0x04 +,0x26,0x88,0x5c,0x28,0x8b,0xc6,0xb9,0x06,0x00,0xbe,0x20,0x00,0xbf,0x1a,0x00,0xf3 +,0xa4,0x8b,0xc8,0x83,0xc7,0x06,0xf3,0xa4,0x26,0x81,0x26,0x26,0x00,0x1f,0x80,0x26 +,0x81,0x36,0x26,0x00,0x00,0x80,0xe9,0xa9,0xff,0x26,0x8b,0x1e,0x28,0x00,0x89,0x1e +,0x6a,0x37,0x06,0x8e,0x06,0x38,0x34,0x1f,0xc0,0xe3,0x04,0x26,0x88,0x1e,0x28,0x00 +,0xb9,0x06,0x00,0xbe,0x20,0x00,0xbf,0x1a,0x00,0xf3,0xa4,0xe9,0x84,0xff,0x86,0xc4 +,0xa3,0x68,0x37,0xe8,0x87,0xff,0xf7,0x06,0x6a,0x37,0x0f,0x00,0x74,0x10,0x80,0x3e +,0x9e,0x36,0x00,0x75,0x09,0xbe,0x00,0x00,0xe8,0xac,0xe9,0xcd,0x50,0xc3,0xc3,0x50 +,0x56,0x06,0x33,0xc0,0x26,0xf6,0x06,0x20,0x00,0x80,0x74,0x06,0x26,0xa0,0x26,0x00 +,0x24,0x1f,0x8b,0xf0,0x26,0x8b,0x5c,0x26,0x86,0xfb,0x83,0xeb,0x04,0x74,0x4f,0x83 +,0xc6,0x2a,0x8c,0xc0,0x8e,0xd8,0xb9,0x07,0x00,0x33,0xc0,0x8e,0xc0,0xbf,0x72,0x37 +,0xf3,0xab,0x33,0xc9,0x8a,0x0c,0x80,0xf9,0x00,0x75,0x03,0xe9,0x30,0x00,0x3b,0xd9 +,0x73,0x03,0xe9,0x29,0x00,0x2b,0xd9,0x8a,0x44,0x01,0x25,0x3f,0x00,0x74,0x19,0x3d +,0x0b,0x00,0x7d,0x14,0xd1,0xe0,0x8b,0xf8,0x2e,0x8b,0xbd,0x5c,0x49,0x8d,0x74,0x02 +,0x83,0xe9,0x02,0xf3,0xa4,0xe9,0x02,0x00,0x03,0xf1,0x23,0xdb,0x75,0xc4,0x33,0xc0 +,0x8e,0xd8,0x07,0x5e,0x58,0xc3,0x33,0xc0,0x26,0xf6,0x06,0x20,0x00,0x80,0x74,0x06 +,0x26,0xa0,0x26,0x00,0x24,0x1f,0xc3,0xe5,0x0a,0x25,0xc3,0xbf,0xe7,0x0a,0xb8,0x86 +,0x03,0xcd,0x39,0xb8,0x83,0x03,0xcd,0x39,0x81,0x26,0x9b,0x36,0x7c,0xdf,0xb8,0x85 +,0x03,0xcd,0x3a,0xe5,0x02,0x25,0xff,0xf3,0x0d,0x01,0x00,0x25,0xef,0xff,0xe7,0x02 +,0xe5,0x00,0x25,0xff,0x53,0xe7,0x00,0xa1,0xe7,0x36,0x25,0xff,0xfe,0xa3,0xe7,0x36 +,0xe7,0x3e,0x83,0x26,0x99,0x36,0xcf,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1,0xaf,0x36 +,0xe7,0x06,0xc3,0xe5,0x02,0x0d,0x01,0x0c,0x25,0xef,0xff,0xe7,0x02,0xa1,0xe7,0x36 +,0x0d,0x00,0x01,0xe7,0x3e,0xa3,0xe7,0x36,0x81,0x0e,0x9b,0x36,0x00,0x20,0x83,0x0e +,0x99,0x36,0x20,0x81,0x26,0x9b,0x36,0x7c,0xbf,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1 +,0xaf,0x36,0xe7,0x06,0xb8,0x86,0x03,0xcd,0x39,0xb8,0x85,0x03,0xcd,0x39,0xb8,0x83 +,0x03,0xcd,0x3a,0xc3,0x0b,0xf6,0x75,0x49,0x06,0x8e,0x06,0x32,0x34,0x80,0x3e,0xe0 +,0x34,0x01,0x75,0x1b,0x26,0x89,0x36,0x06,0x00,0x8e,0x06,0x32,0x34,0x26,0xf7,0x06 +,0x0a,0x00,0x00,0x20,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x20,0x07,0xc3,0x80 +,0x3e,0xe3,0x34,0x01,0x75,0x19,0x26,0x89,0x36,0x06,0x00,0x8e,0x06,0x32,0x34,0x26 +,0xf7,0x06,0x0a,0x00,0x00,0x10,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x10,0x07 +,0xc3,0xe9,0xb4,0xff,0x50,0x51,0x57,0x33,0xc0,0xb9,0x06,0x00,0x8e,0xc0,0xbf,0xd1 +,0x36,0xf3,0xae,0x5f,0x74,0x0c,0x26,0xf6,0x06,0x00,0x00,0xc0,0x75,0x04,0xf8,0x59 +,0x58,0xc3,0xf9,0xe9,0xf9,0xff,0x8b,0x05,0x0b,0x45,0x02,0x0b,0x45,0x04,0xc3,0x52 +,0x50,0xe5,0x06,0x25,0x1e,0x00,0x3d,0x1e,0x00,0x75,0xf6,0xb8,0x01,0x80,0xe7,0x5a +,0x58,0x5a,0xc3,0xe8,0xe9,0xff,0x50,0xe5,0x02,0x25,0xff,0x7f,0x0d,0x01,0x00,0x25 +,0xef,0xff,0xe7,0x02,0x0d,0x00,0x80,0xe7,0x02,0xa1,0xad,0x36,0xe7,0x04,0xa1,0xaf +,0x36,0xe7,0x06,0x58,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x2e,0x2b,0xce,0x41,0x10,0x42,0x7b,0x41,0x30,0x41,0xa2,0x41,0xaf,0x45,0x44,0x29 +,0xc7,0x2a,0xc7,0x2a,0x60,0x39,0xf4,0x3a,0x5c,0x3c,0x09,0x3d,0xb1,0x3d,0x34,0x3f +,0xc7,0x2a,0x3c,0x3f,0xc7,0x2a,0xc4,0x3f,0x16,0x40,0x16,0x40,0xed,0x40,0xfa,0x40 +,0x07,0x41,0xc7,0x2a,0xc7,0x2a,0xc7,0x2a,0xc7,0x2a,0xd6,0x52,0x00,0x00,0x01,0x37 +,0xe9,0x36,0xf3,0x36,0xef,0x36,0x1d,0x37,0x0d,0x37,0x0b,0x37,0x9c,0x37,0x03,0x37 +,0xfb,0x36,0x62,0x2d,0x40,0x06,0xd1,0x2d,0xf4,0x01,0xba,0x44,0x40,0x06,0x8c,0x43 +,0x64,0x00,0xe8,0x2c,0xc8,0x00,0xd8,0x2b,0x05,0x00,0xe9,0x45,0x50,0x00,0x97,0x45 +,0xfa,0x00,0xae,0x2d,0x04,0x01,0x6a,0x42,0x02,0x00,0xf6,0x2c,0xbc,0x02,0x93,0x2d +,0xdc,0x05,0x1d,0x2d,0x64,0x00,0xa1,0x2d,0x14,0x00,0xd7,0x3a,0x08,0x07,0x81,0x2d +,0x64,0x00,0xb3,0x3e,0x02,0x00,0x30,0x43,0x64,0x00,0xc5,0x2c,0xf4,0x01,0x8b,0x44 +,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x80,0x3e,0xfd,0x34,0x02,0x74,0x0c,0xe8,0x20,0x05,0xc7,0x06,0xa1,0x36,0x00,0x00 +,0xe9,0x9a,0xf8,0xff,0x06,0xc0,0x33,0xe8,0x10,0x05,0x8b,0x36,0x3d,0x37,0xe8,0x73 +,0xfe,0xc3,0xcd,0x34,0xe9,0xe8,0x05,0xc7,0x06,0xa3,0x36,0x00,0x00,0xc7,0x06,0x41 +,0x37,0x00,0x00,0xe8,0xed,0xfe,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56,0xa1,0xb1,0x36 +,0x0d,0x00,0x10,0xe7,0x08,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xa1 +,0xad,0x36,0xe7,0x04,0xe8,0x2b,0x09,0xc7,0x06,0x1d,0x37,0x00,0xc8,0xc7,0x06,0x0b +,0x37,0x00,0x03,0xc7,0x06,0x0d,0x37,0x7b,0x7f,0x33,0xc0,0xa3,0x9b,0x36,0xa3,0x9d +,0x36,0xc7,0x06,0x4c,0x37,0x01,0x00,0xc6,0x06,0x9e,0x36,0xff,0xc7,0x06,0x05,0x37 +,0x00,0x00,0xc7,0x06,0x07,0x37,0x00,0x00,0xc7,0x06,0x09,0x37,0x00,0x00,0xa3,0xf3 +,0x36,0xa3,0xef,0x36,0xa3,0xf1,0x36,0xe8,0xfe,0xf5,0xe5,0x02,0x25,0xf9,0xff,0x0d +,0x03,0x00,0x0d,0x00,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02 +,0xb8,0x8f,0x03,0xcd,0x39,0xb8,0x80,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff +,0xa1,0xa9,0x36,0xa3,0xa7,0x36,0x0d,0x00,0xa4,0x0d,0x00,0x08,0xe7,0x00,0xa3,0xa9 +,0x36,0xc7,0x06,0xa3,0x36,0x01,0x00,0xc7,0x06,0xa5,0x36,0x0c,0x00,0x83,0x3e,0xa5 +,0x36,0x00,0x75,0x09,0xc7,0x06,0x3d,0x37,0x05,0x00,0xe9,0x13,0xff,0xff,0x0e,0xa5 +,0x36,0xbe,0x11,0x00,0xe8,0x22,0x05,0xb8,0x90,0x03,0xcd,0x39,0xc3,0x83,0x3e,0xa3 +,0x36,0x01,0x74,0xd9,0xc3,0xb8,0x90,0x03,0xcd,0x3a,0x26,0xa0,0x2b,0x00,0x26,0x8b +,0x1e,0x2c,0x00,0xcd,0x34,0x83,0x3e,0xa3,0x36,0x01,0x74,0x03,0xe9,0xf0,0x04,0x3c +,0x0f,0x75,0x1e,0x81,0xfb,0x00,0x02,0x75,0x18,0x26,0xa1,0x20,0x00,0xa3,0x05,0x37 +,0x26,0xa1,0x22,0x00,0xa3,0x07,0x37,0x26,0xa1,0x24,0x00,0xa3,0x09,0x37,0xe9,0x09 +,0x00,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xb6,0xfe,0xc7,0x06,0xa3,0x36,0x02,0x00 +,0xc6,0x06,0x9e,0x36,0xff,0xe8,0xcb,0xfd,0xe8,0x1c,0xd9,0x33,0xc0,0xa3,0x85,0x37 +,0xa3,0x83,0x37,0xa3,0x87,0x37,0xa3,0x89,0x37,0xb8,0x91,0x03,0xcd,0x39,0xb8,0x80 +,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff,0xe5,0x00,0x25,0xff,0x53,0xe7,0x00 +,0x81,0x0e,0x9a,0x37,0x80,0x00,0xb8,0x92,0x03,0xcd,0x39,0x33,0xc0,0xe7,0x0e,0xbe +,0x08,0x00,0x8e,0x06,0x38,0x34,0xe8,0x8e,0xe5,0x26,0xc7,0x06,0x04,0x00,0x7d,0x4b +,0x83,0x26,0xef,0x34,0xdf,0xcd,0x50,0x83,0x0e,0xef,0x34,0x20,0xc3,0xf7,0x06,0x9a +,0x37,0x80,0x00,0x74,0x32,0xa9,0xd0,0x07,0x74,0x0c,0xa9,0x00,0x04,0x74,0x0e,0x33 +,0xc0,0xe7,0x0e,0xe9,0xda,0xff,0xff,0x06,0x85,0x37,0xe9,0xd3,0xff,0xff,0x06,0x83 +,0x37,0xe9,0xcc,0xff,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0x36,0xfe,0x83,0x26,0x9a +,0x37,0x7f,0xbb,0xff,0x7f,0xcd,0x53,0xe5,0x00,0x0d,0x00,0xac,0xe7,0x00,0xe5,0x02 +,0x25,0xff,0xfb,0x25,0xef,0xff,0x25,0xff,0xf7,0x0d,0x01,0x00,0xe7,0x02,0xa1,0x83 +,0x37,0x3b,0x06,0x46,0x37,0x7f,0xcd,0xa1,0x85,0x37,0x3b,0x06,0x48,0x37,0x7c,0xc4 +,0xc7,0x06,0xa3,0x36,0x03,0x00,0xbe,0x13,0x00,0xe8,0xfd,0x03,0xb8,0x93,0x03,0xcd +,0x39,0xb8,0x94,0x03,0xcd,0x39,0xb8,0x96,0x03,0xcd,0x39,0xb8,0x95,0x03,0xcd,0x39 +,0xbe,0x06,0x00,0xe8,0xe3,0x03,0xe9,0xd6,0x03,0x83,0x3e,0xa3,0x36,0x03,0x74,0x01 +,0xc3,0xbe,0x13,0x00,0xe8,0xd2,0x03,0xb8,0x94,0x03,0xcd,0x39,0xc3,0xb8,0x94,0x03 +,0xcd,0x3a,0x26,0xa0,0x2b,0x00,0x26,0x8b,0x1e,0x2c,0x00,0xcd,0x34,0x83,0x3e,0xa3 +,0x36,0x03,0x74,0x03,0xe9,0xa8,0x03,0x3c,0x0d,0x75,0x3e,0x83,0xfb,0x00,0x75,0x39 +,0xe5,0x02,0x0d,0x00,0x20,0xe7,0x02,0xb8,0x93,0x03,0xcd,0x3a,0xc7,0x06,0xa3,0x36 +,0x04,0x00,0xbe,0x00,0x00,0xe8,0x0c,0xfc,0xc6,0x06,0x9d,0x36,0x80,0xc6,0x06,0x9e +,0x36,0x00,0xc7,0x06,0x33,0x37,0x02,0x00,0xb8,0x9a,0x03,0xcd,0x39,0xe8,0xfc,0x00 +,0xc7,0x06,0x4c,0x37,0x00,0x00,0xe9,0x66,0x03,0xc7,0x06,0x3d,0x37,0x08,0x00,0xe9 +,0x61,0xfd,0x83,0x3e,0xa3,0x36,0x03,0x75,0x09,0xc7,0x06,0x3d,0x37,0x05,0x00,0xe9 +,0x51,0xfd,0xe9,0x4a,0x03,0x83,0x3e,0xa3,0x36,0x04,0x74,0x12,0x83,0x3e,0xa3,0x36 +,0x05,0x74,0x0b,0xcd,0x34,0xc7,0x06,0x3d,0x37,0x07,0x00,0xe9,0x35,0xfd,0xc7,0x06 +,0xa3,0x36,0x06,0x00,0xc6,0x06,0x9e,0x36,0xff,0xb8,0x9a,0x03,0xcd,0x3a,0xb8,0x99 +,0x03,0xcd,0x3a,0xb8,0x96,0x03,0xcd,0x3a,0xb8,0x97,0x03,0xcd,0x39,0xb8,0x98,0x03 +,0xcd,0x39,0xb8,0x9b,0x03,0xcd,0x39,0xe9,0x18,0xfd,0xcd,0x34,0x83,0x3e,0xa3,0x36 +,0x04,0x77,0x18,0x83,0x3e,0xa3,0x36,0x03,0x75,0x08,0xf7,0x06,0x9b,0x36,0x00,0x01 +,0x75,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xe8,0xfc,0xe9,0xe1,0x02,0xcd,0x34 +,0x83,0x3e,0xa3,0x36,0x02,0x77,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xd3,0xfc +,0x83,0x3e,0xa3,0x36,0x04,0x77,0x05,0xb8,0x96,0x03,0xcd,0x39,0xe9,0xc0,0x02,0x83 +,0x3e,0xa3,0x36,0x03,0x75,0x10,0x26,0xa1,0x0c,0x00,0x25,0x07,0x00,0x50,0x3d,0x04 +,0x00,0x75,0x03,0xe8,0x36,0x00,0xa1,0xf3,0x36,0x86,0xe0,0xe7,0x1e,0xa3,0xe3,0x36 +,0x81,0x26,0x0b,0x37,0x00,0x03,0x81,0x26,0x0d,0x37,0x7b,0x7f,0x83,0x0e,0x0d,0x37 +,0x48,0xe8,0x14,0xf3,0x58,0x3d,0x04,0x00,0x74,0x09,0x26,0xf7,0x06,0x0c,0x00,0x20 +,0x00,0x75,0x06,0xb8,0x01,0x00,0xe9,0x7a,0x02,0xe9,0x86,0xfc,0xa1,0xe5,0x36,0xe7 +,0x2e,0xa1,0xe7,0x36,0xe7,0x3e,0xa1,0xd3,0x36,0xa3,0x9c,0x34,0xa1,0xd5,0x36,0xa3 +,0x9e,0x34,0xc3,0x26,0x80,0x3e,0x1c,0x00,0xff,0x75,0x2f,0x26,0x80,0x3e,0x1e,0x00 +,0xff,0x75,0x27,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00,0x75,0x1b,0xa1,0xd1,0x36,0x26 +,0xa3,0x1a,0x00,0xa1,0xd3,0x36,0x26,0xa3,0x1c,0x00,0xa1,0xd5,0x36,0x26,0xa3,0x1e +,0x00,0xb8,0x0a,0x80,0xe9,0x2c,0x02,0xe9,0x38,0xfc,0xff,0x06,0x90,0x34,0xbe,0x0a +,0x00,0xc6,0x06,0xb6,0x34,0x01,0xf6,0x06,0x9d,0x36,0x80,0x75,0x05,0x83,0x0e,0xc2 +,0x34,0x01,0xcd,0x34,0xe9,0x0c,0xfc,0x83,0x3e,0xa3,0x36,0x03,0x75,0x09,0xc7,0x06 +,0x3d,0x37,0x05,0x00,0xe9,0xfc,0xfb,0xe5,0x02,0x0d,0x03,0x00,0x0d,0x00,0x88,0x0d +,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02,0xc7,0x06,0xa3,0x36,0x05,0x00,0xc6,0x06,0x9e +,0x36,0xff,0xbe,0x02,0x00,0xe8,0xe1,0x01,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x9a,0x03 +,0xcd,0x3a,0xb8,0x99,0x03,0xcd,0x39,0xb8,0x97,0x03,0xcd,0x39,0xb8,0x98,0x03,0xcd +,0x39,0xe9,0xbb,0x01,0x83,0x3e,0xa3,0x36,0x03,0x74,0x0a,0x83,0x3e,0xa3,0x36,0x04 +,0x74,0x03,0xe9,0xaa,0x01,0xbe,0x06,0x00,0xe8,0xae,0x01,0xb8,0x95,0x03,0xcd,0x39 +,0xe9,0x9c,0x01,0x83,0x3e,0xa3,0x36,0x05,0x74,0x03,0xe9,0x92,0x01,0xbe,0x02,0x00 +,0xe8,0x96,0x01,0xb8,0x99,0x03,0xcd,0x39,0xe9,0x84,0x01,0xc7,0x06,0x0f,0x37,0x05 +,0x00,0xe9,0x7b,0x01,0xe5,0x02,0x25,0xff,0xdf,0xe7,0x02,0xc7,0x06,0xa3,0x36,0x07 +,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xe9,0x65,0x01,0xe8,0xd5,0x04,0xc6,0x06,0x9d +,0x36,0x00,0xc7,0x06,0x9b,0x36,0x00,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xc7,0x06 +,0xa8,0x02,0x00,0x00,0xc7,0x06,0x4c,0x37,0x01,0x00,0xe5,0x02,0x25,0xf9,0xff,0x0d +,0x03,0x00,0x0d,0x00,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02 +,0xe9,0x67,0xfc,0xb8,0x9a,0x03,0xcd,0x39,0xf7,0x06,0xf4,0x33,0x00,0x10,0x75,0x09 +,0xc7,0x06,0x33,0x37,0x02,0x00,0xe9,0x16,0x01,0xff,0x0e,0x33,0x37,0x74,0x03,0xe9 +,0x0d,0x01,0xff,0x06,0x8e,0x34,0x83,0x0e,0xc2,0x34,0x08,0xc7,0x06,0x3d,0x37,0x03 +,0x00,0xe9,0xff,0xfa,0xc3,0x52,0x50,0xba,0xe0,0x00,0xb8,0x00,0x10,0xef,0x58,0x5a +,0xc3,0xc7,0x06,0x3d,0x37,0x00,0x00,0xe9,0xe9,0xfa,0xfa,0xe8,0x54,0x04,0xb8,0x80 +,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04,0x00,0xd8,0x2b,0xb8,0x7f,0x03,0x8e,0xc0,0x26 +,0xc7,0x06,0x04,0x00,0xe8,0x2c,0x33,0xc0,0x8e,0xc0,0xa1,0xa7,0x36,0xa3,0xa9,0x36 +,0xa1,0xa9,0x36,0xe7,0x00,0xa1,0xab,0x36,0xe7,0x02,0xc7,0x06,0x05,0x37,0x00,0x00 +,0xc7,0x06,0x07,0x37,0x00,0x00,0xc7,0x06,0x09,0x37,0x00,0x00,0xc6,0x06,0x9d,0x36 +,0x00,0xc6,0x06,0x9e,0x36,0xff,0xc7,0x06,0x9b,0x36,0x00,0x00,0xc7,0x06,0xa3,0x36 +,0x00,0x00,0xc7,0x06,0x0f,0x37,0x00,0x00,0xc7,0x06,0xa8,0x02,0x00,0x00,0xc7,0x06 +,0x4c,0x37,0x01,0x00,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0xbb +,0xff,0x7f,0xcd,0x53,0xe8,0x7c,0xf9,0xe5,0x56,0x0d,0x02,0x00,0xe7,0x56,0xfb,0xc3 +,0x8d,0x3e,0xc0,0x53,0x8d,0x36,0xf0,0x38,0xb9,0x0e,0x00,0x8b,0x1e,0x30,0x34,0x89 +,0x5c,0x02,0x2e,0x8b,0x45,0x02,0x89,0x44,0x06,0x2e,0x8b,0x05,0x89,0x44,0x04,0x83 +,0xc7,0x04,0x83,0xc6,0x10,0xe2,0xe8,0xb8,0x80,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04 +,0x00,0xe2,0x51,0xb8,0x7f,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04,0x00,0xb2,0x52,0x33 +,0xc0,0x8e,0xc0,0xc7,0x06,0xa1,0x36,0x01,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xc3 +,0x33,0xff,0x8e,0x06,0xa6,0x02,0x8b,0x36,0xa4,0x02,0x2e,0xff,0xa4,0xa0,0x53,0xe8 +,0x8c,0xdb,0xc3,0xe8,0x48,0xf7,0xe9,0xf6,0xff,0x8e,0x06,0x38,0x34,0xe8,0x07,0xe1 +,0x26,0xc7,0x06,0x04,0x00,0xdf,0x4f,0xcd,0x50,0xc3,0x26,0xc7,0x06,0x0a,0x00,0x00 +,0x00,0x26,0xff,0x26,0x04,0x00,0xcd,0x34,0xe9,0xd4,0xff,0xa1,0xd1,0x36,0x26,0x39 +,0x06,0x1a,0x00,0x75,0x22,0xa1,0xd3,0x36,0x26,0x39,0x06,0x1c,0x00,0x75,0x18,0xa1 +,0xd5,0x36,0x26,0x39,0x06,0x1e,0x00,0x75,0x0e,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00 +,0x74,0x05,0x83,0x0e,0x66,0x37,0x40,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1,0xaf,0x36 +,0xe7,0x06,0x83,0x3e,0xa3,0x36,0x02,0x75,0x05,0xcd,0x34,0xe9,0x56,0xfb,0x83,0x3e +,0xa3,0x36,0x00,0x74,0xb1,0x83,0x3e,0xa3,0x36,0x05,0x77,0xaa,0x26,0xf6,0x06,0x0a +,0x00,0xff,0x75,0xa2,0xe8,0xfd,0xdd,0x50,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xe9 +,0x8c,0x00,0x26,0xa1,0x0c,0x00,0x25,0x07,0x00,0x3d,0x07,0x00,0x75,0x03,0xe9,0x76 +,0x00,0x3d,0x05,0x00,0x75,0x03,0xe9,0x6e,0x00,0xf7,0x06,0xe6,0x34,0x18,0x80,0x75 +,0x03,0xe9,0x6a,0x00,0xf7,0x06,0xe6,0x34,0x00,0x80,0x74,0x35,0x26,0x80,0x3e,0x29 +,0x00,0x02,0x75,0x2d,0x51,0x56,0x57,0x8d,0x36,0x3e,0x34,0x8d,0x3e,0x20,0x00,0xb9 +,0x06,0x00,0xf3,0xa6,0x5f,0x5e,0x59,0x75,0x45,0x26,0xa1,0x20,0x00,0xa3,0x3e,0x34 +,0x26,0xa1,0x22,0x00,0xa3,0x40,0x34,0x26,0xa1,0x24,0x00,0xa3,0x42,0x34,0xe9,0x26 +,0x00,0xf7,0x06,0xe6,0x34,0x08,0x00,0x74,0x0b,0x26,0x80,0x3e,0x19,0x00,0x00,0x74 +,0x03,0xe9,0x13,0x00,0xf7,0x06,0xe6,0x34,0x10,0x00,0x74,0x12,0x26,0xa0,0x28,0x00 +,0xc0,0xe8,0x04,0x22,0xc0,0x74,0x07,0x26,0xc7,0x06,0x04,0x00,0xff,0xff,0x58,0x23 +,0xc0,0x74,0x03,0xe9,0xdd,0xfe,0x81,0x26,0x9b,0x36,0xff,0xfe,0x26,0xa1,0x20,0x00 +,0x3b,0x06,0xd1,0x36,0x75,0x1a,0x26,0xa1,0x22,0x00,0x3b,0x06,0xd3,0x36,0x75,0x10 +,0x26,0xa1,0x24,0x00,0x3b,0x06,0xd5,0x36,0x75,0x06,0x81,0x0e,0x9b,0x36,0x00,0x01 +,0x26,0xa1,0x20,0x00,0x25,0x7f,0xff,0xa3,0xb8,0x34,0x26,0xa1,0x22,0x00,0xa3,0xba +,0x34,0x26,0xa1,0x24,0x00,0xa3,0xbc,0x34,0x8b,0xc6,0x86,0xc4,0xa3,0xc0,0x34,0xd1 +,0xe6,0x80,0xfc,0x09,0x74,0x03,0xe8,0xf6,0xf5,0xa1,0x05,0x37,0x0b,0x06,0x07,0x37 +,0x0b,0x06,0x09,0x37,0x74,0x3e,0x26,0xa1,0x20,0x00,0x3b,0x06,0x05,0x37,0x75,0x17 +,0x26,0xa1,0x22,0x00,0x3b,0x06,0x07,0x37,0x75,0x0d,0x26,0xa1,0x24,0x00,0x3b,0x06 +,0x09,0x37,0x75,0x03,0xe9,0x1d,0x00,0x26,0xa0,0x28,0x00,0x24,0x0f,0x3c,0x03,0x74 +,0x1b,0x3c,0x00,0x75,0x0f,0x83,0x3e,0xa3,0x36,0x04,0x74,0x10,0xf7,0x06,0x9b,0x36 +,0x00,0x01,0x74,0x08,0x2e,0xff,0x94,0xf8,0x53,0xe9,0x33,0xfe,0xcd,0x34,0xc7,0x06 +,0x3d,0x37,0x01,0x00,0xe9,0x2c,0xf8,0x83,0x3e,0xa3,0x36,0x05,0x74,0x10,0x83,0x3e +,0xa3,0x36,0x01,0x7e,0x09,0x83,0xee,0x16,0x2e,0xff,0x94,0x24,0x54,0xc3,0xcd,0x34 +,0xc3,0x26,0xa1,0x0c,0x00,0x3d,0xff,0x7f,0x74,0x05,0x26,0xff,0x26,0x04,0x00,0xe9 +,0xfd,0xfd,0xa1,0xf4,0x33,0xa9,0x00,0x88,0x74,0x0b,0xa9,0x00,0x10,0x75,0x09,0x8b +,0x1e,0x43,0x37,0xff,0xe3,0xe9,0x97,0x00,0xc7,0x06,0x35,0x37,0x05,0x00,0xc7,0x06 +,0x43,0x37,0x28,0x52,0xf7,0x06,0xf4,0x33,0x00,0x08,0x74,0x06,0xc7,0x06,0x43,0x37 +,0x1a,0x52,0xb8,0x80,0x03,0xcd,0x39,0xe9,0xc5,0xfd,0xa9,0x00,0x08,0x74,0xd9,0xff +,0x0e,0x35,0x37,0x75,0xed,0xe9,0x30,0x00,0xa9,0x00,0x08,0x75,0xcb,0xff,0x0e,0x35 +,0x37,0x75,0xdf,0x81,0x0e,0xc2,0x34,0xc0,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74,0x0f +,0x81,0x0e,0x9b,0x36,0x00,0x80,0xc7,0x06,0x0f,0x37,0x02,0x00,0xe9,0x90,0xfd,0xc7 +,0x06,0x3d,0x37,0x02,0x00,0xe9,0x8b,0xf7,0x80,0x26,0x9e,0x36,0xff,0x75,0x30,0xf6 +,0x06,0x9d,0x36,0x80,0x74,0x20,0xff,0x06,0x94,0x34,0x83,0x0e,0x66,0x37,0x20,0x8e +,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08 +,0x00,0x00,0x01,0xe9,0x09,0x00,0xc7,0x06,0x3d,0x37,0x04,0x00,0xe9,0x54,0xf7,0x81 +,0x0e,0xaf,0x36,0x00,0x08,0xa1,0xaf,0x36,0xe7,0x06,0xe5,0x0a,0xa9,0x00,0x80,0x74 +,0x0e,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36,0xe7,0x06,0xe9,0x49,0xff,0xe9 +,0x2d,0xfd,0xc7,0x06,0x41,0x37,0x00,0x00,0xbe,0x29,0x00,0xe8,0x2b,0xfd,0xe9,0x1e +,0xfd,0xcd,0x34,0x83,0x3e,0xa3,0x36,0x04,0x77,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00 +,0xe9,0x10,0xf7,0xe9,0x09,0xfd,0xcd,0x34,0xc3,0xc7,0x06,0x9b,0x36,0x00,0x00,0xe8 +,0x0c,0xf5,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0x81,0x26,0x9b +,0x36,0xff,0x7f,0xe5,0x02,0x0d,0x01,0x00,0x25,0xef,0xff,0x25,0xff,0xdf,0xe7,0x02 +,0xbb,0xff,0x7f,0xcd,0x53,0x33,0xc0,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xe8,0x20,0xf3 +,0xe8,0x43,0xf3,0x83,0x0e,0x9b,0x36,0x10,0xc7,0x06,0x99,0x36,0x00,0x00,0xe8,0xd2 +,0xf5,0xe5,0x56,0x0d,0x02,0x00,0xe7,0x56,0xc7,0x06,0xa8,0x02,0x00,0x00,0xbe,0x00 +,0x00,0xe8,0x30,0xf5,0xc6,0x06,0xa0,0x36,0x0e,0xb8,0x9c,0x03,0xcd,0x39,0xb8,0x80 +,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff,0xc7,0x06,0xa1,0x36,0x01,0x00,0xe9 +,0xa5,0xf6,0x06,0xb8,0x8f,0x03,0xcd,0x3a,0xb8,0x90,0x03,0xcd,0x3a,0xb8,0x91,0x03 +,0xcd,0x3a,0xb8,0x92,0x03,0xcd,0x3a,0xb8,0x93,0x03,0xcd,0x3a,0xb8,0x94,0x03,0xcd +,0x3a,0xb8,0x95,0x03,0xcd,0x3a,0xb8,0x96,0x03,0xcd,0x3a,0xb8,0x97,0x03,0xcd,0x3a +,0xb8,0x98,0x03,0xcd,0x3a,0xb8,0x99,0x03,0xcd,0x3a,0xb8,0x9a,0x03,0xcd,0x3a,0xb8 +,0x9b,0x03,0xcd,0x3a,0xb8,0x7f,0x03,0xcd,0x3a,0xb8,0x80,0x03,0xcd,0x3a,0x07,0xc3 +,0xf7,0x49,0xf1,0x4e,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xf8,0x51,0xdf,0x4f +,0xfa,0x4f,0x0b,0x50,0xd1,0x51,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f +,0xe4,0x4e,0x06,0x00,0xcd,0x4a,0x04,0x00,0xe4,0x4e,0x19,0x00,0xad,0x4b,0xfa,0x00 +,0x82,0x4c,0x08,0x07,0x09,0x4c,0x14,0x00,0x24,0x4e,0x64,0x00,0xd7,0x4d,0xf4,0x01 +,0x64,0x4e,0xbc,0x02,0x7a,0x4e,0xe8,0x03,0x43,0x4e,0x02,0x00,0xb3,0x4e,0xf4,0x01 +,0x5b,0x4e,0xf4,0x01,0xe5,0x4e,0x14,0x00,0x06,0x50,0x06,0x50,0x95,0x4c,0xc1,0x52 +,0xc1,0x52,0xfe,0x4c,0xda,0x4c,0x06,0x50,0x06,0x50,0x06,0x50,0x06,0x50,0xb7,0x51 +,0xb7,0x51,0xb7,0x51,0xb7,0x51,0xb7,0x51,0xb7,0x51,0x06,0x50,0xd5,0x4a,0x06,0x50 +,0x1d,0x4c,0x06,0x50,0x83,0x4d,0x1f,0x4d,0x1f,0x4d,0xed,0x40,0xfa,0x40,0x07,0x41 +,0x37,0x37,0x2e,0x37,0x37,0x20,0x20,0x79,0x79,0x2f,0x79,0x79,0x2f,0x79,0x79,0x20 +,0x30,0x31,0x2e,0x39,0x30,0x20,0x20,0x30,0x32,0x2f,0x31,0x37,0x2f,0x39,0x39,0x20 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x90,0xea,0xc0,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x06 +} ; +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tokenring/Config.help linux-2.5/drivers/net/tokenring/Config.help --- linux-2.5.5/drivers/net/tokenring/Config.help Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/net/tokenring/Config.help Tue Feb 26 21:24:49 2002 @@ -129,3 +129,21 @@ The module will be called smctr.o. If you want to compile it as a module, say M here and read . +3COM 3C359 Token Link Velocity XL PCI adapter support +CONFIG_3C359 + This is support for the 3Com PCI Velocity XL cards, specifically + the 3Com 3C359, please note this is not for the 3C339 cards, you + should use the tms380 driver instead. + + If you have such an adapter, say Y and read the Token-Ring + mini-HOWTO, available from . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will will be called 3c359.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + + Also read the file or check the + Linux Token Ring Project site for the latest information at + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tokenring/Config.in linux-2.5/drivers/net/tokenring/Config.in --- linux-2.5.5/drivers/net/tokenring/Config.in Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/net/tokenring/Config.in Tue Feb 26 21:24:49 2002 @@ -18,6 +18,7 @@ fi dep_tristate ' IBM Olympic chipset PCI adapter support' CONFIG_IBMOL $CONFIG_TR $CONFIG_PCI dep_tristate ' IBM Lanstreamer chipset PCI adapter support' CONFIG_IBMLS $CONFIG_TR $CONFIG_PCI + dep_tristate ' 3Com 3C359 Token Link Velocity XL adapter support' CONFIG_3C359 $CONFIG_TR $CONFIG_PCI tristate ' Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR if [ "$CONFIG_TMS380TR" != "n" ]; then dep_tristate ' Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_PCI diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tokenring/Makefile linux-2.5/drivers/net/tokenring/Makefile --- linux-2.5.5/drivers/net/tokenring/Makefile Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/net/tokenring/Makefile Tue Feb 26 21:24:49 2002 @@ -21,6 +21,7 @@ obj-$(CONFIG_TMSPCI) += tmspci.o obj-$(CONFIG_TMSISA) += tmsisa.o obj-$(CONFIG_SMCTR) += smctr.o +obj-$(CONFIG_3C359) += 3c359.o O_TARGET := tr.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tokenring/abyss.c linux-2.5/drivers/net/tokenring/abyss.c --- linux-2.5.5/drivers/net/tokenring/abyss.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/tokenring/abyss.c Sun Feb 17 23:08:54 2002 @@ -433,7 +433,7 @@ return 0; } -static void __exit abyss_detach (struct pci_dev *pdev) +static void __devexit abyss_detach (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -451,7 +451,7 @@ name: "abyss", id_table: abyss_pci_tbl, probe: abyss_attach, - remove: abyss_detach, + remove: __devexit_p(abyss_detach), }; static int __init abyss_init (void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tokenring/lanstreamer.c linux-2.5/drivers/net/tokenring/lanstreamer.c --- linux-2.5.5/drivers/net/tokenring/lanstreamer.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/net/tokenring/lanstreamer.c Tue Feb 5 02:39:13 2002 @@ -60,6 +60,11 @@ * malloc free checks, reviewed code. * 03/13/00 - Added spinlocks for smp * 03/08/01 - Added support for module_init() and module_exit() + * 08/15/01 - Added ioctl() functionality for debugging, changed netif_*_queue + * calls and other incorrectness - Kent Yoder + * 11/05/01 - Restructured the interrupt function, added delays, reduced the + * the number of TX descriptors to 1, which together can prevent + * the card from locking up the box - * * To Do: * @@ -84,6 +89,14 @@ #define STREAMER_NETWORK_MONITOR 0 +/* #define CONFIG_PROC_FS */ + +/* + * Allow or disallow ioctl's for debugging + */ + +#define STREAMER_IOCTL 0 + #include #include @@ -105,6 +118,7 @@ #include #include #include +#include #include #include @@ -121,7 +135,8 @@ * Official releases will only have an a.b.c version number format. */ -static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan"; +static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n" + " v0.5.1 11/14/01 - Kent Yoder"; static struct pci_device_id streamer_pci_tbl[] __initdata = { { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,}, @@ -175,6 +190,10 @@ MODULE_PARM(message_level, "1-" __MODULE_STRING(STREAMER_MAX_ADAPTERS) "i"); +#if STREAMER_IOCTL +static int streamer_ioctl(struct net_device *, struct ifreq *, int); +#endif + static int streamer_reset(struct net_device *dev); static int streamer_open(struct net_device *dev); static int streamer_xmit(struct sk_buff *skb, struct net_device *dev); @@ -206,6 +225,8 @@ __u32 mmio_start, mmio_end, mmio_flags, mmio_len; int rc=0; static int card_no=-1; + u16 pcr; + u8 cls = 0; #if STREAMER_DEBUG printk("lanstreamer::streamer_init_one, entry pdev %p\n",pdev); @@ -281,7 +302,11 @@ dev->hard_start_xmit = &streamer_xmit; dev->change_mtu = &streamer_change_mtu; dev->stop = &streamer_close; +#if STREAMER_IOCTL + dev->do_ioctl = &streamer_ioctl; +#else dev->do_ioctl = NULL; +#endif dev->set_multicast_list = &streamer_set_rx_mode; dev->get_stats = &streamer_get_stats; dev->set_mac_address = &streamer_set_mac_address; @@ -303,6 +328,18 @@ spin_lock_init(&streamer_priv->streamer_lock); + pci_write_config_byte (pdev, PCI_CACHE_LINE_SIZE, cls); + pci_read_config_word (pdev, PCI_COMMAND, &pcr); + + /* Turn off Fast B2B enable */ + pcr &= ~PCI_COMMAND_FAST_BACK; + /* Turn on SERR# enable and others */ + pcr |= (PCI_COMMAND_SERR | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | + PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + + pci_write_config_word (pdev, PCI_COMMAND, pcr); + pci_read_config_word (pdev, PCI_COMMAND, &pcr); + printk("%s \n", version); printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name, streamer_priv->streamer_card_name, @@ -403,6 +440,7 @@ printk("GPR: %x\n", readw(streamer_mmio + GPR)); printk("SISRMASK: %x\n", readw(streamer_mmio + SISR_MASK)); #endif + writew(readw(streamer_mmio + BCTL) | (BCTL_RX_FIFO_8 | BCTL_TX_FIFO_8), streamer_mmio + BCTL ); if (streamer_priv->streamer_ring_speed == 0) { /* Autosense */ writew(readw(streamer_mmio + GPR) | GPR_AUTOSENSE, @@ -558,8 +596,6 @@ do { int i; - save_flags(flags); - cli(); for (i = 0; i < SRB_COMMAND_SIZE; i += 2) { writew(0, streamer_mmio + LAPDINC); } @@ -599,11 +635,12 @@ } printk("\n"); #endif - + spin_lock_irqsave(&streamer_priv->streamer_lock, flags); streamer_priv->srb_queued = 1; /* signal solo that SRB command has been issued */ writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM); + spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags); while (streamer_priv->srb_queued) { interruptible_sleep_on_timeout(&streamer_priv->srb_wait, 5 * HZ); @@ -617,7 +654,6 @@ break; } } - restore_flags(flags); #if STREAMER_DEBUG printk("SISR_MASK: %x\n", readw(streamer_mmio + SISR_MASK)); @@ -767,9 +803,12 @@ streamer_priv->streamer_tx_ring[i].bufcnt_framelen = 0; streamer_priv->streamer_tx_ring[i].buffer = 0; streamer_priv->streamer_tx_ring[i].buflen = 0; + streamer_priv->streamer_tx_ring[i].rsvd1 = 0; + streamer_priv->streamer_tx_ring[i].rsvd2 = 0; + streamer_priv->streamer_tx_ring[i].rsvd3 = 0; } streamer_priv->streamer_tx_ring[STREAMER_TX_RING_SIZE - 1].forward = - virt_to_bus(&streamer_priv->streamer_tx_ring[0]);; + virt_to_bus(&streamer_priv->streamer_tx_ring[0]); streamer_priv->free_tx_ring_entries = STREAMER_TX_RING_SIZE; streamer_priv->tx_ring_free = 0; /* next entry in tx ring to use */ @@ -941,37 +980,30 @@ __u8 *streamer_mmio = streamer_priv->streamer_mmio; __u16 sisr; __u16 misr; - __u16 sisrmask; + u8 max_intr = MAX_INTR; - sisrmask = SISR_MI; - writew(~sisrmask, streamer_mmio + SISR_MASK_RUM); + spin_lock(&streamer_priv->streamer_lock); sisr = readw(streamer_mmio + SISR); - writew(~sisr, streamer_mmio + SISR_RUM); - misr = readw(streamer_mmio + MISR_RUM); - writew(~misr, streamer_mmio + MISR_RUM); - if (!sisr) - { /* Interrupt isn't for us */ - writew(~misr,streamer_mmio+MISR_RUM); - return; - } + while((sisr & (SISR_MI | SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | + SISR_ARB_CMD | SISR_TRB_REPLY | SISR_PAR_ERR | SISR_SERR_ERR)) + && (max_intr > 0)) { - spin_lock(&streamer_priv->streamer_lock); + if(sisr & SISR_PAR_ERR) { + writew(~SISR_PAR_ERR, streamer_mmio + SISR_RUM); + (void)readw(streamer_mmio + SISR_RUM); + } - if ((sisr & (SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY)) - || (misr & (MISR_TX2_EOF | MISR_RX_NOBUF | MISR_RX_EOF))) { - if (sisr & SISR_SRB_REPLY) { - if (streamer_priv->srb_queued == 1) { - wake_up_interruptible(&streamer_priv->srb_wait); - } else if (streamer_priv->srb_queued == 2) { - streamer_srb_bh(dev); - } - streamer_priv->srb_queued = 0; + else if(sisr & SISR_SERR_ERR) { + writew(~SISR_SERR_ERR, streamer_mmio + SISR_RUM); + (void)readw(streamer_mmio + SISR_RUM); } - /* SISR_SRB_REPLY */ + + else if(sisr & SISR_MI) { + misr = readw(streamer_mmio + MISR_RUM); + if (misr & MISR_TX2_EOF) { - while (streamer_priv->streamer_tx_ring[(streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1)].status) - { + while(streamer_priv->streamer_tx_ring[(streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1)].status) { streamer_priv->tx_ring_last_status = (streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1); streamer_priv->free_tx_ring_entries++; streamer_priv->streamer_stats.tx_bytes += streamer_priv->tx_ring_skb[streamer_priv->tx_ring_last_status]->len; @@ -981,6 +1013,9 @@ streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].status = 0; streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].bufcnt_framelen = 0; streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].buflen = 0; + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd1 = 0; + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd2 = 0; + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd3 = 0; } netif_wake_queue(dev); } @@ -989,7 +1024,30 @@ streamer_rx(dev); } /* MISR_RX_EOF */ - if (sisr & SISR_ADAPTER_CHECK) { + + if (misr & MISR_RX_NOBUF) { + /* According to the documentation, we don't have to do anything, + * but trapping it keeps it out of /var/log/messages. + */ + } /* SISR_RX_NOBUF */ + + writew(~misr, streamer_mmio + MISR_RUM); + (void)readw(streamer_mmio + MISR_RUM); + } + + else if (sisr & SISR_SRB_REPLY) { + if (streamer_priv->srb_queued == 1) { + wake_up_interruptible(&streamer_priv->srb_wait); + } else if (streamer_priv->srb_queued == 2) { + streamer_srb_bh(dev); + } + streamer_priv->srb_queued = 0; + + writew(~SISR_SRB_REPLY, streamer_mmio + SISR_RUM); + (void)readw(streamer_mmio + SISR_RUM); + } + + else if (sisr & SISR_ADAPTER_CHECK) { printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name); writel(readl(streamer_mmio + LAPWWO), streamer_mmio + LAPA); printk(KERN_WARNING "%s: Words %x:%x:%x:%x:\n", @@ -1001,38 +1059,37 @@ } /* SISR_ADAPTER_CHECK */ - if (sisr & SISR_ASB_FREE) { + else if (sisr & SISR_ASB_FREE) { /* Wake up anything that is waiting for the asb response */ if (streamer_priv->asb_queued) { streamer_asb_bh(dev); } + writew(~SISR_ASB_FREE, streamer_mmio + SISR_RUM); + (void)readw(streamer_mmio + SISR_RUM); } /* SISR_ASB_FREE */ - if (sisr & SISR_ARB_CMD) { + else if (sisr & SISR_ARB_CMD) { streamer_arb_cmd(dev); + writew(~SISR_ARB_CMD, streamer_mmio + SISR_RUM); + (void)readw(streamer_mmio + SISR_RUM); } /* SISR_ARB_CMD */ - if (sisr & SISR_TRB_REPLY) { + else if (sisr & SISR_TRB_REPLY) { /* Wake up anything that is waiting for the trb response */ if (streamer_priv->trb_queued) { wake_up_interruptible(&streamer_priv-> trb_wait); } streamer_priv->trb_queued = 0; + writew(~SISR_TRB_REPLY, streamer_mmio + SISR_RUM); + (void)readw(streamer_mmio + SISR_RUM); } /* SISR_TRB_REPLY */ - if (misr & MISR_RX_NOBUF) { - /* According to the documentation, we don't have to do anything, but trapping it keeps it out of - /var/log/messages. */ - } /* SISR_RX_NOBUF */ - } else { - printk(KERN_WARNING "%s: Unexpected interrupt: %x\n", - dev->name, sisr); - printk(KERN_WARNING "%s: SISR_MASK: %x\n", dev->name, - readw(streamer_mmio + SISR_MASK)); - } /* One if the interrupts we want */ - writew(SISR_MI, streamer_mmio + SISR_MASK_SUM); + sisr = readw(streamer_mmio + SISR); + max_intr--; + } /* while() */ + spin_unlock(&streamer_priv->streamer_lock) ; } @@ -1044,13 +1101,16 @@ unsigned long flags ; spin_lock_irqsave(&streamer_priv->streamer_lock, flags); - netif_stop_queue(dev); if (streamer_priv->free_tx_ring_entries) { streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0; - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00010000 | skb->len; + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00020000 | skb->len; streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buffer = virt_to_bus(skb->data); + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd1 = skb->len; + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd2 = 0; + streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd3 = 0; streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buflen = skb->len; + streamer_priv->tx_ring_skb[streamer_priv->tx_ring_free] = skb; streamer_priv->free_tx_ring_entries--; #if STREAMER_DEBUG_PACKETS @@ -1067,12 +1127,13 @@ #endif writel(virt_to_bus (&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free]),streamer_mmio + TX2LFDA); + (void)readl(streamer_mmio + TX2LFDA); streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1); - netif_wake_queue(dev); spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); return 0; } else { + netif_stop_queue(dev); spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); return 1; } @@ -1092,12 +1153,13 @@ writew(htons(SRB_CLOSE_ADAPTER << 8),streamer_mmio+LAPDINC); writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); - save_flags(flags); - cli(); + spin_lock_irqsave(&streamer_priv->streamer_lock, flags); streamer_priv->srb_queued = 1; writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM); + spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags); + while (streamer_priv->srb_queued) { interruptible_sleep_on_timeout(&streamer_priv->srb_wait, @@ -1114,7 +1176,6 @@ } } - restore_flags(flags); streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1); for (i = 0; i < STREAMER_RX_RING_SIZE; i++) { @@ -1808,11 +1869,69 @@ #endif #endif +#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static int streamer_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + int i; + struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; + u8 *streamer_mmio = streamer_priv->streamer_mmio; + + switch(cmd) { + case IOCTL_SISR_MASK: + writew(SISR_MI, streamer_mmio + SISR_MASK_SUM); + break; + case IOCTL_SPIN_LOCK_TEST: + printk("spin_lock() called.\n"); + spin_lock(&streamer_priv->streamer_lock); + spin_unlock(&streamer_priv->streamer_lock); + printk("spin_unlock() finished.\n"); + break; + case IOCTL_PRINT_BDAS: + printk("bdas: RXBDA: %x RXLBDA: %x TX2FDA: %x TX2LFDA: %x\n", + readw(streamer_mmio + RXBDA), + readw(streamer_mmio + RXLBDA), + readw(streamer_mmio + TX2FDA), + readw(streamer_mmio + TX2LFDA)); + break; + case IOCTL_PRINT_REGISTERS: + printk("registers:\n"); + printk("SISR: %04x MISR: %04x LISR: %04x BCTL: %04x BMCTL: %04x\nmask %04x mask %04x\n", + readw(streamer_mmio + SISR), + readw(streamer_mmio + MISR_RUM), + readw(streamer_mmio + LISR), + readw(streamer_mmio + BCTL), + readw(streamer_mmio + BMCTL_SUM), + readw(streamer_mmio + SISR_MASK), + readw(streamer_mmio + MISR_MASK)); + break; + case IOCTL_PRINT_RX_BUFS: + printk("Print rx bufs:\n"); + for(i=0; istreamer_rx_ring[i].status); + break; + case IOCTL_PRINT_TX_BUFS: + printk("Print tx bufs:\n"); + for(i=0; istreamer_tx_ring[i].status); + break; + case IOCTL_RX_CMD: + streamer_rx(dev); + printk("Sent rx command.\n"); + break; + default: + printk("Bad ioctl!\n"); + } + return 0; +} +#endif + static struct pci_driver streamer_pci_driver = { name: "lanstreamer", id_table: streamer_pci_tbl, probe: streamer_init_one, - remove: streamer_remove_one, + remove: __devexit_p(streamer_remove_one), }; static int __init streamer_init_module(void) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tokenring/lanstreamer.h linux-2.5/drivers/net/tokenring/lanstreamer.h --- linux-2.5.5/drivers/net/tokenring/lanstreamer.h Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/tokenring/lanstreamer.h Sun Feb 3 18:03:58 2002 @@ -56,11 +56,36 @@ * * 12/10/99 - Alpha Release 0.1.0 * First release to the public + * 08/15/01 - Added ioctl() definitions and others - Kent Yoder * */ +#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#include +#define IOCTL_PRINT_RX_BUFS SIOCDEVPRIVATE +#define IOCTL_PRINT_TX_BUFS SIOCDEVPRIVATE+1 +#define IOCTL_RX_CMD SIOCDEVPRIVATE+2 +#define IOCTL_TX_CMD SIOCDEVPRIVATE+3 +#define IOCTL_PRINT_REGISTERS SIOCDEVPRIVATE+4 +#define IOCTL_PRINT_BDAS SIOCDEVPRIVATE+5 +#define IOCTL_SPIN_LOCK_TEST SIOCDEVPRIVATE+6 +#define IOCTL_SISR_MASK SIOCDEVPRIVATE+7 +#endif + +/* MAX_INTR - the maximum number of times we can loop + * inside the interrupt function before returning + * control to the OS (maximum value is 256) + */ +#define MAX_INTR 5 + +#define CLS 0x0C +#define MLR 0x86 +#define LTR 0x0D + #define BCTL 0x60 #define BCTL_SOFTRESET (1<<15) +#define BCTL_RX_FIFO_8 (1<<1) +#define BCTL_TX_FIFO_8 (1<<3) #define GPR 0x4a #define GPR_AUTOSENSE (1<<2) @@ -89,6 +114,7 @@ #define SISR_MASK_RUM 0x58 #define SISR_MI (1<<15) +#define SISR_SERR_ERR (1<<14) #define SISR_TIMER (1<<11) #define SISR_LAP_PAR_ERR (1<<10) #define SISR_LAP_ACC_ERR (1<<9) @@ -218,7 +244,13 @@ /* Streamer defaults for buffers */ #define STREAMER_RX_RING_SIZE 16 /* should be a power of 2 */ -#define STREAMER_TX_RING_SIZE 8 /* should be a power of 2 */ +/* Setting the number of TX descriptors to 1 is a workaround for an + * undocumented hardware problem with the lanstreamer board. Setting + * this to something higher may slightly increase the throughput you + * can get from the card, but at the risk of locking up the box. - + * + */ +#define STREAMER_TX_RING_SIZE 1 /* should be a power of 2 */ #define PKT_BUF_SZ 4096 /* Default packet size */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tokenring/olympic.c linux-2.5/drivers/net/tokenring/olympic.c --- linux-2.5.5/drivers/net/tokenring/olympic.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/tokenring/olympic.c Tue Feb 19 16:00:14 2002 @@ -433,8 +433,6 @@ do { int i; - save_flags(flags); - cli(); for(i=0;idev_addr,olympic_priv->olympic_laa,dev->addr_len) ; } writeb(1,init_srb+30); - + + spin_lock_irqsave(&olympic_priv->olympic_lock,flags); olympic_priv->srb_queued=1; writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); t = jiffies ; @@ -496,7 +496,6 @@ remove_wait_queue(&olympic_priv->srb_wait,&wait) ; set_current_state(TASK_RUNNING) ; - restore_flags(flags); #if OLYMPIC_DEBUG printk("init_srb(%p): ",init_srb); for(i=0;i<20;i++) @@ -1058,12 +1057,11 @@ writeb(0,srb+1); writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); - save_flags(flags); - cli(); - + spin_lock_irqsave(&olympic_priv->olympic_lock,flags); olympic_priv->srb_queued=1; writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); t = jiffies ; @@ -1088,7 +1086,6 @@ remove_wait_queue(&olympic_priv->srb_wait,&wait) ; set_current_state(TASK_RUNNING) ; - restore_flags(flags) ; olympic_priv->rx_status_last_received++; olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; @@ -1760,7 +1757,7 @@ name: "olympic", id_table: olympic_pci_tbl, probe: olympic_probe, - remove: olympic_remove_one + remove: __devexit_p(olympic_remove_one), }; static int __init olympic_pci_init(void) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tokenring/tmspci.c linux-2.5/drivers/net/tokenring/tmspci.c --- linux-2.5.5/drivers/net/tokenring/tmspci.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/net/tokenring/tmspci.c Sun Feb 17 23:08:54 2002 @@ -220,7 +220,7 @@ return val; } -static void __exit tms_pci_detach (struct pci_dev *pdev) +static void __devexit tms_pci_detach (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -238,7 +238,7 @@ name: "tmspci", id_table: tmspci_pci_tbl, probe: tms_pci_attach, - remove: tms_pci_detach, + remove: __devexit_p(tms_pci_detach), }; static int __init tms_pci_init (void) @@ -253,7 +253,7 @@ return 0; } -static void __exit tms_pci_rmmod (void) +static void __devexit tms_pci_rmmod (void) { pci_unregister_driver (&tms_pci_driver); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tulip/ChangeLog linux-2.5/drivers/net/tulip/ChangeLog --- linux-2.5.5/drivers/net/tulip/ChangeLog Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/net/tulip/ChangeLog Sun Feb 17 22:58:37 2002 @@ -1,14 +1,19 @@ +2002-02-07 Uwe Bonnes + + * tulip_core (tulip_pci_tbl[]): + Add PCI id for comet tulip clone. + 2002-01-28 Stefan Rompf , Jeff Garzik - * 21142.c (t21142_timer): Use return value of - tulip_check_duplex() to indicate to system whether or not - carrier is present. Use carrier presence/absence to determine - when next the 21142 media timer should check for link beat. - - * timer (tulip_timer): Un-comment-out calls to - netif_carrier_{on,off}, as there is now value in - reporting link beta information to userspace. + * 21142.c (t21142_timer): Use return value of + tulip_check_duplex() to indicate to system whether or not + carrier is present. Use carrier presence/absence to determine + when next the 21142 media timer should check for link beat. + + * timer (tulip_timer): Un-comment-out calls to + netif_carrier_{on,off}, as there is now value in + reporting link beta information to userspace. 2002-01-28 Pavel Roskin @@ -22,8 +27,22 @@ 2002-02-07 Uwe Bonnes - * tulip_core (tulip_pci_tbl[]): - Add PCI id for comet tulip clone. + * tulip_core (tulip_pci_tbl[]): + Add PCI id for comet tulip clone. + +2001-12-19 John Zielinski + + * tulip_core.c (tulip_up, tulip_init_one): + More places to revert PHY autoconfiguration bit removal. + +2001-12-18 Jeff Garzik + + * tulip.h: revert PHY autoconfiguration bit removal + +2001-12-16 Andrew Lambeth + + * tulip_core.c (tulip_start_xmit): Use the more-portable + spin_lock_irqsave. 2001-12-11 Jeff Garzik diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tulip/tulip.h linux-2.5/drivers/net/tulip/tulip.h --- linux-2.5.5/drivers/net/tulip/tulip.h Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/net/tulip/tulip.h Tue Feb 19 00:35:27 2002 @@ -198,8 +198,8 @@ csr13_cac = (1<<2), /* CSR13/14/15 autoconfiguration */ csr13_srl = (1<<0), /* When reset, resets all SIA functions, machines */ - csr13_mask_auibnc = (csr13_eng | csr13_aui | csr13_srl), - csr13_mask_10bt = (csr13_eng | csr13_srl), + csr13_mask_auibnc = (csr13_eng | csr13_aui | csr13_srl | csr13_cac), + csr13_mask_10bt = (csr13_eng | csr13_srl | csr13_cac), }; enum t21143_csr6_bits { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/tulip/tulip_core.c linux-2.5/drivers/net/tulip/tulip_core.c --- linux-2.5.5/drivers/net/tulip/tulip_core.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/net/tulip/tulip_core.c Sun Mar 3 17:54:35 2002 @@ -94,6 +94,8 @@ static int csr0 = 0x01A00000 | 0x9000; #elif defined(__arm__) || defined(__sh__) static int csr0 = 0x01A00000 | 0x4800; +#elif defined(__mips__) +static int csr0 = 0x00200000 | 0x4000; #else #warning Processor architecture undefined! static int csr0 = 0x00A00000 | 0x4800; @@ -648,8 +650,9 @@ int entry; u32 flag; dma_addr_t mapping; + unsigned long eflags; - spin_lock_irq(&tp->lock); + spin_lock_irqsave(&tp->lock, eflags); /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % TX_RING_SIZE; @@ -684,7 +687,7 @@ /* Trigger an immediate transmit demand. */ outl(0, dev->base_addr + CSR1); - spin_unlock_irq(&tp->lock); + spin_unlock_irqrestore(&tp->lock, eflags); dev->trans_start = jiffies; @@ -1491,6 +1494,16 @@ tp->flags &= ~HAS_MEDIA_TABLE; } #endif +#ifdef CONFIG_MIPS_COBALT + if ((pdev->bus->number == 0) && + ((PCI_SLOT(pdev->devfn) == 7) || + (PCI_SLOT(pdev->devfn) == 12))) { + /* Cobalt MAC address in first EEPROM locations. */ + sa_offset = 0; + /* No media table either */ + tp->flags &= ~HAS_MEDIA_TABLE; + } +#endif for (i = 0; i < 6; i ++) { dev->dev_addr[i] = ee_data[i + sa_offset]; sum += ee_data[i + sa_offset]; @@ -1528,7 +1541,7 @@ #endif #if defined(__i386__) /* Patch up x86 BIOS bug. */ if (last_irq) - irq = last_irq; + dev->irq = last_irq; #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/via-rhine.c linux-2.5/drivers/net/via-rhine.c --- linux-2.5.5/drivers/net/via-rhine.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/net/via-rhine.c Mon Feb 18 22:54:12 2002 @@ -321,6 +321,7 @@ VT86C100A = 0, VT6102, VT3043, + VT6105, }; struct via_rhine_chip_info { @@ -349,9 +350,9 @@ { "VIA VT6102 Rhine-II", RHINE_IOTYPE, 256, CanHaveMII | HasWOL }, { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, - CanHaveMII | ReqTxAlign } + CanHaveMII | ReqTxAlign }, { "VIA VT6105 Rhine-III", RHINE_IOTYPE, 256, - CanHaveMII | HasWOL }, + CanHaveMII | HasWOL } }; static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = @@ -1753,7 +1754,7 @@ name: "via-rhine", id_table: via_rhine_pci_tbl, probe: via_rhine_init_one, - remove: via_rhine_remove_one, + remove: __devexit_p(via_rhine_remove_one), }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/Makefile linux-2.5/drivers/net/wan/Makefile --- linux-2.5.5/drivers/net/wan/Makefile Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/net/wan/Makefile Mon Feb 4 22:15:16 2002 @@ -1,7 +1,7 @@ # # Makefile for the Linux network (wan) device drivers. # -# 3 Aug 2000, Christoph Hellwig +# 3 Aug 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/comx-hw-locomx.c linux-2.5/drivers/net/wan/comx-hw-locomx.c --- linux-2.5.5/drivers/net/wan/comx-hw-locomx.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/net/wan/comx-hw-locomx.c Mon Jan 14 22:39:45 2002 @@ -154,11 +154,9 @@ return -ENODEV; } - if (check_region(dev->base_addr, hw->io_extent)) { + if (!request_region(dev->base_addr, hw->io_extent, dev->name)) { return -EAGAIN; } - - request_region(dev->base_addr, hw->io_extent, dev->name); hw->board.chanA.ctrlio=dev->base_addr + 5; hw->board.chanA.dataio=dev->base_addr + 7; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/comx-hw-mixcom.c linux-2.5/drivers/net/wan/comx-hw-mixcom.c --- linux-2.5.5/drivers/net/wan/comx-hw-mixcom.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/net/wan/comx-hw-mixcom.c Thu Dec 13 16:32:36 2001 @@ -566,8 +566,6 @@ return 0; -err_restore_flags: - restore_flags(flags); err_release_region: release_region(dev->base_addr, MIXCOM_IO_EXTENT); err_ret: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/cosa.c linux-2.5/drivers/net/wan/cosa.c --- linux-2.5.5/drivers/net/wan/cosa.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/net/wan/cosa.c Wed Feb 6 02:19:20 2002 @@ -105,13 +105,6 @@ #include #include "cosa.h" -/* Linux version stuff */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1) -typedef struct wait_queue *wait_queue_head_t; -#define DECLARE_WAITQUEUE(wait, current) \ - struct wait_queue wait = { current, NULL } -#endif - /* Maximum length of the identification string. */ #define COSA_MAX_ID_STRING 128 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/dscc4.c linux-2.5/drivers/net/wan/dscc4.c --- linux-2.5.5/drivers/net/wan/dscc4.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/wan/dscc4.c Sun Mar 3 20:13:04 2002 @@ -512,8 +512,9 @@ dev_to_hdlc(dev)->stats.rx_bytes += pkt_len; skb->tail += pkt_len; skb->len = pkt_len; - if (netif_running(hdlc_to_dev(&dpriv->hdlc))) + if (netif_running(hdlc_to_dev(&dpriv->hdlc))) skb->protocol = htons(ETH_P_HDLC); + skb->dev->last_rx = jiffies; netif_rx(skb); try_get_rx_skb(dpriv, cur, dev); } else { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/farsync.c linux-2.5/drivers/net/wan/farsync.c --- linux-2.5.5/drivers/net/wan/farsync.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/net/wan/farsync.c Fri Jan 18 22:19:47 2002 @@ -1810,7 +1810,7 @@ name: FST_NAME, id_table: fst_pci_dev_id, probe: fst_add_one, - remove: fst_remove_one, + remove: __devexit_p(fst_remove_one), suspend: NULL, resume: NULL, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/hd6457x.c linux-2.5/drivers/net/wan/hd6457x.c --- linux-2.5.5/drivers/net/wan/hd6457x.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/net/wan/hd6457x.c Sun Mar 3 20:15:15 2002 @@ -295,6 +295,7 @@ #endif port->hdlc.stats.rx_packets++; port->hdlc.stats.rx_bytes += skb->len; + skb->dev->last_rx = jiffies; hdlc_netif_rx(&port->hdlc, skb); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/hdlc.c linux-2.5/drivers/net/wan/hdlc.c --- linux-2.5.5/drivers/net/wan/hdlc.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/net/wan/hdlc.c Sun Mar 3 20:15:15 2002 @@ -138,6 +138,7 @@ case ETH_P_IPV6: skb->protocol = data->protocol; skb->dev = hdlc_to_dev(hdlc); + skb->dev->last_rx = jiffies; netif_rx(skb); return; @@ -686,6 +687,7 @@ skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ skb->protocol = htons(ETH_P_IP); skb->dev = &pvc->netdev; + skb->dev->last_rx = jiffies; netif_rx(skb); return; } @@ -695,6 +697,7 @@ skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ skb->protocol = htons(ETH_P_IPV6); skb->dev = &pvc->netdev; + skb->dev->last_rx = jiffies; netif_rx(skb); return; } @@ -705,6 +708,7 @@ skb_pull(skb, 10); skb->protocol = htons(ETH_P_ARP); skb->dev = &pvc->netdev; + skb->dev->last_rx = jiffies; netif_rx(skb); return; } @@ -895,6 +899,7 @@ skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; + skb->dev->last_rx = jiffies; netif_rx(skb); } @@ -922,6 +927,7 @@ skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; + skb->dev->last_rx = jiffies; return netif_rx(skb); } @@ -1106,6 +1112,7 @@ case MODE_HDLC: skb->protocol = htons(ETH_P_IP); skb->dev = hdlc_to_dev(hdlc); + skb->dev->last_rx = jiffies; netif_rx(skb); return; @@ -1124,6 +1131,7 @@ #else skb->protocol = htons(ETH_P_WAN_PPP); skb->dev = hdlc_to_dev(hdlc); + skb->dev->last_rx = jiffies; netif_rx(skb); #endif return; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/lapbether.c linux-2.5/drivers/net/wan/lapbether.c --- linux-2.5.5/drivers/net/wan/lapbether.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/net/wan/lapbether.c Sun Mar 3 20:15:15 2002 @@ -170,6 +170,7 @@ skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; + skb->dev->last_rx = jiffies; return netif_rx(skb); } @@ -264,6 +265,7 @@ skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; + skb->dev->last_rx = jiffies; netif_rx(skb); } @@ -286,6 +288,7 @@ skb->mac.raw = skb->data; skb->pkt_type = PACKET_HOST; + skb->dev->last_rx = jiffies; netif_rx(skb); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/lmc/lmc_proto.c linux-2.5/drivers/net/wan/lmc/lmc_proto.c --- linux-2.5.5/drivers/net/wan/lmc/lmc_proto.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/net/wan/lmc/lmc_proto.c Sun Mar 3 20:15:15 2002 @@ -254,6 +254,7 @@ case LMC_PPP: case LMC_NET: default: + skb->dev->last_rx = jiffies; netif_rx(skb); break; case LMC_RAW: diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/lmc/lmc_var.h linux-2.5/drivers/net/wan/lmc/lmc_var.h --- linux-2.5.5/drivers/net/wan/lmc/lmc_var.h Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/net/wan/lmc/lmc_var.h Mon Feb 18 21:59:51 2002 @@ -87,7 +87,7 @@ lmc_delay(); \ LMC_CSR_WRITE((sc), csr_9, 0x30000); \ lmc_delay(); \ - n--; }} while(0); + n--; }} while(0) struct lmc_regfile_t { lmc_csrptr_t csr_busmode; /* CSR0 */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/sdla_chdlc.c linux-2.5/drivers/net/wan/sdla_chdlc.c --- linux-2.5.5/drivers/net/wan/sdla_chdlc.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/net/wan/sdla_chdlc.c Sun Mar 3 20:15:16 2002 @@ -2230,6 +2230,7 @@ skb->dev = dev; skb->mac.raw = skb->data; netif_rx(skb); + dev->last_rx = jiffies; } rx_exit: @@ -3285,6 +3286,7 @@ new_skb->mac.raw = new_skb->data; netif_rx(new_skb); + dev->last_rx = jiffies; } else { printk(KERN_INFO "%s: no socket buffers available!\n", diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/sdla_fr.c linux-2.5/drivers/net/wan/sdla_fr.c --- linux-2.5.5/drivers/net/wan/sdla_fr.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/net/wan/sdla_fr.c Sun Mar 3 20:15:16 2002 @@ -163,14 +163,9 @@ #include /* frame relay firmware API definitions */ -#if defined(LINUX_2_1) || defined(LINUX_2_4) - #include - #include - #include - -#else - #include -#endif +#include +#include +#include #include /* Dynamic Route Creation */ #include /* eth_type_trans() used for bridging */ @@ -2358,6 +2353,7 @@ /* Send a packed up the IP stack */ + skb->dev->last_rx = jiffies; netif_rx(skb); ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack; ++chan->ifstats.rx_packets; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/sdla_ppp.c linux-2.5/drivers/net/wan/sdla_ppp.c --- linux-2.5.5/drivers/net/wan/sdla_ppp.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/net/wan/sdla_ppp.c Sun Mar 3 20:15:16 2002 @@ -1463,11 +1463,11 @@ { int cnt = 0; - tokens[0] = strtok(str, "/"); + tokens[0] = strsep(&str, "/"); while (tokens[cnt] && (cnt < 32 - 1)) { tokens[cnt] = strstrip(tokens[cnt], " \t"); - tokens[++cnt] = strtok(NULL, "/"); + tokens[++cnt] = strsep(&str, "/"); } return cnt; } @@ -1903,6 +1903,7 @@ #endif ++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack; netif_rx(skb); + dev->last_rx = jiffies; } } else { @@ -2473,7 +2474,7 @@ #endif default: - printk(KERN_INFO "%s: ERROR: Unsuported PPP Mode Selected\n", + printk(KERN_INFO "%s: ERROR: Unsupported PPP Mode Selected\n", card->devname); printk(KERN_INFO "%s: PPP IP Modes: STATIC, PEER or HOST\n", card->devname); @@ -2965,6 +2966,7 @@ new_skb->dev = dev; new_skb->mac.raw = new_skb->data; netif_rx(new_skb); + dev->last_rx = jiffies; } else { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/sdla_x25.c linux-2.5/drivers/net/wan/sdla_x25.c --- linux-2.5.5/drivers/net/wan/sdla_x25.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/net/wan/sdla_x25.c Sun Mar 3 17:54:35 2002 @@ -1272,7 +1272,7 @@ add_timer(&card->u.x.x25_timer); } } - /* Device is not up untill the we are in connected state */ + /* Device is not up until the we are in connected state */ do_gettimeofday( &tv ); chan->router_start_time = tv.tv_sec; @@ -4756,7 +4756,7 @@ * send_delayed_cmd_result * * Wait commands like PLEACE CALL or CLEAR CALL must wait - * untill the result arrivers. This function passes + * until the result arrives. This function passes * the result to a waiting sock. * *===============================================================*/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/sealevel.c linux-2.5/drivers/net/wan/sealevel.c --- linux-2.5.5/drivers/net/wan/sealevel.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/net/wan/sealevel.c Mon Jan 14 22:39:45 2002 @@ -219,12 +219,11 @@ * Get the needed I/O space */ - if(check_region(iobase, 8)) + if(!request_region(iobase, 8, "Sealevel 4021")) { printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase); return NULL; } - request_region(iobase, 8, "Sealevel 4021"); b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL); if(!b) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/syncppp.c linux-2.5/drivers/net/wan/syncppp.c --- linux-2.5.5/drivers/net/wan/syncppp.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/wan/syncppp.c Sun Mar 3 20:15:16 2002 @@ -275,6 +275,7 @@ printk(KERN_DEBUG "Yow an IP frame.\n"); skb->protocol=htons(ETH_P_IP); netif_rx(skb); + dev->last_rx = jiffies; return; } break; @@ -284,6 +285,7 @@ if (sp->lcp.state == LCP_STATE_OPENED) { skb->protocol=htons(ETH_P_IPX); netif_rx(skb); + dev->last_rx = jiffies; return; } break; @@ -311,12 +313,14 @@ case ETH_P_IP: skb->protocol=htons(ETH_P_IP); netif_rx(skb); + dev->last_rx = jiffies; return; #endif #ifdef CONFIG_IPX case ETH_P_IPX: skb->protocol=htons(ETH_P_IPX); netif_rx(skb); + dev->last_rx = jiffies; return; #endif } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/wanpipe_multppp.c linux-2.5/drivers/net/wan/wanpipe_multppp.c --- linux-2.5.5/drivers/net/wan/wanpipe_multppp.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/net/wan/wanpipe_multppp.c Sun Mar 3 20:15:16 2002 @@ -1572,6 +1572,7 @@ skb->dev = dev; skb->mac.raw = skb->data; netif_rx(skb); + dev->last_rx = jiffies; } rx_exit: @@ -2175,6 +2176,7 @@ new_skb->mac.raw = new_skb->data; netif_rx(new_skb); + dev->last_rx = jiffies; } else { printk(KERN_INFO "%s: no socket buffers available!\n", @@ -2470,6 +2472,7 @@ new_skb->mac.raw = new_skb->data; netif_rx(new_skb); + dev->last_rx = jiffies; } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wan/x25_asy.c linux-2.5/drivers/net/wan/x25_asy.c --- linux-2.5.5/drivers/net/wan/x25_asy.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/net/wan/x25_asy.c Sun Mar 3 20:15:16 2002 @@ -250,6 +250,7 @@ else { netif_rx(skb); + sl->dev->last_rx = jiffies; sl->rx_packets++; } } @@ -397,6 +398,7 @@ static int x25_asy_data_indication(void *token, struct sk_buff *skb) { + skb->dev->last_rx = jiffies; return netif_rx(skb); } @@ -449,6 +451,7 @@ skb->pkt_type = PACKET_HOST; netif_rx(skb); + sl->dev->last_rx = jiffies; } static void x25_asy_disconnected(void *token, int reason) @@ -471,6 +474,7 @@ skb->pkt_type = PACKET_HOST; netif_rx(skb); + sl->dev->last_rx = jiffies; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wavelan.c linux-2.5/drivers/net/wavelan.c --- linux-2.5.5/drivers/net/wavelan.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/wavelan.c Tue Jan 22 17:43:48 2002 @@ -0,0 +1,4342 @@ +/* + * WaveLAN ISA driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * Original copyright follows (also see the end of this file). + * See wavelan.p.h for details. + * + * + * + * AT&T GIS (nee NCR) WaveLAN card: + * An Ethernet-like radio transceiver + * controlled by an Intel 82586 coprocessor. + */ + +#include "wavelan.p.h" /* Private header */ + +/************************* MISC SUBROUTINES **************************/ +/* + * Subroutines which won't fit in one of the following category + * (WaveLAN modem or i82586) + */ + +/*------------------------------------------------------------------*/ +/* + * Wrapper for disabling interrupts and locking the driver. + * (note : inline, so optimised away) + */ +static inline void wv_splhi(net_local * lp, + unsigned long * pflags) +{ + spin_lock_irqsave(&lp->spinlock, *pflags); + /* Note : above does the cli(); itself */ +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper for re-enabling interrupts and un-locking the driver. + */ +static inline void wv_splx(net_local * lp, + unsigned long * pflags) +{ + spin_unlock_irqrestore(&lp->spinlock, *pflags); +} + +/*------------------------------------------------------------------*/ +/* + * Translate irq number to PSA irq parameter + */ +static u8 wv_irq_to_psa(int irq) +{ + if (irq < 0 || irq >= NELS(irqvals)) + return 0; + + return irqvals[irq]; +} + +/*------------------------------------------------------------------*/ +/* + * Translate PSA irq parameter to irq number + */ +static int __init wv_psa_to_irq(u8 irqval) +{ + int irq; + + for (irq = 0; irq < NELS(irqvals); irq++) + if (irqvals[irq] == irqval) + return irq; + + return -1; +} + +#ifdef STRUCT_CHECK +/*------------------------------------------------------------------*/ +/* + * Sanity routine to verify the sizes of the various WaveLAN interface + * structures. + */ +static char *wv_struct_check(void) +{ +#define SC(t,s,n) if (sizeof(t) != s) return(n); + + SC(psa_t, PSA_SIZE, "psa_t"); + SC(mmw_t, MMW_SIZE, "mmw_t"); + SC(mmr_t, MMR_SIZE, "mmr_t"); + SC(ha_t, HA_SIZE, "ha_t"); + +#undef SC + + return ((char *) NULL); +} /* wv_struct_check */ +#endif /* STRUCT_CHECK */ + +/********************* HOST ADAPTER SUBROUTINES *********************/ +/* + * Useful subroutines to manage the WaveLAN ISA interface + * + * One major difference with the PCMCIA hardware (except the port mapping) + * is that we have to keep the state of the Host Control Register + * because of the interrupt enable & bus size flags. + */ + +/*------------------------------------------------------------------*/ +/* + * Read from card's Host Adaptor Status Register. + */ +static inline u16 hasr_read(unsigned long ioaddr) +{ + return (inw(HASR(ioaddr))); +} /* hasr_read */ + +/*------------------------------------------------------------------*/ +/* + * Write to card's Host Adapter Command Register. + */ +static inline void hacr_write(unsigned long ioaddr, u16 hacr) +{ + outw(hacr, HACR(ioaddr)); +} /* hacr_write */ + +/*------------------------------------------------------------------*/ +/* + * Write to card's Host Adapter Command Register. Include a delay for + * those times when it is needed. + */ +static inline void hacr_write_slow(unsigned long ioaddr, u16 hacr) +{ + hacr_write(ioaddr, hacr); + /* delay might only be needed sometimes */ + mdelay(1); +} /* hacr_write_slow */ + +/*------------------------------------------------------------------*/ +/* + * Set the channel attention bit. + */ +static inline void set_chan_attn(unsigned long ioaddr, u16 hacr) +{ + hacr_write(ioaddr, hacr | HACR_CA); +} /* set_chan_attn */ + +/*------------------------------------------------------------------*/ +/* + * Reset, and then set host adaptor into default mode. + */ +static inline void wv_hacr_reset(unsigned long ioaddr) +{ + hacr_write_slow(ioaddr, HACR_RESET); + hacr_write(ioaddr, HACR_DEFAULT); +} /* wv_hacr_reset */ + +/*------------------------------------------------------------------*/ +/* + * Set the I/O transfer over the ISA bus to 8-bit mode + */ +static inline void wv_16_off(unsigned long ioaddr, u16 hacr) +{ + hacr &= ~HACR_16BITS; + hacr_write(ioaddr, hacr); +} /* wv_16_off */ + +/*------------------------------------------------------------------*/ +/* + * Set the I/O transfer over the ISA bus to 8-bit mode + */ +static inline void wv_16_on(unsigned long ioaddr, u16 hacr) +{ + hacr |= HACR_16BITS; + hacr_write(ioaddr, hacr); +} /* wv_16_on */ + +/*------------------------------------------------------------------*/ +/* + * Disable interrupts on the WaveLAN hardware. + * (called by wv_82586_stop()) + */ +static inline void wv_ints_off(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + + lp->hacr &= ~HACR_INTRON; + hacr_write(ioaddr, lp->hacr); +} /* wv_ints_off */ + +/*------------------------------------------------------------------*/ +/* + * Enable interrupts on the WaveLAN hardware. + * (called by wv_hw_reset()) + */ +static inline void wv_ints_on(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + + lp->hacr |= HACR_INTRON; + hacr_write(ioaddr, lp->hacr); +} /* wv_ints_on */ + +/******************* MODEM MANAGEMENT SUBROUTINES *******************/ +/* + * Useful subroutines to manage the modem of the WaveLAN + */ + +/*------------------------------------------------------------------*/ +/* + * Read the Parameter Storage Area from the WaveLAN card's memory + */ +/* + * Read bytes from the PSA. + */ +static void psa_read(unsigned long ioaddr, u16 hacr, int o, /* offset in PSA */ + u8 * b, /* buffer to fill */ + int n) +{ /* size to read */ + wv_16_off(ioaddr, hacr); + + while (n-- > 0) { + outw(o, PIOR2(ioaddr)); + o++; + *b++ = inb(PIOP2(ioaddr)); + } + + wv_16_on(ioaddr, hacr); +} /* psa_read */ + +/*------------------------------------------------------------------*/ +/* + * Write the Parameter Storage Area to the WaveLAN card's memory. + */ +static void psa_write(unsigned long ioaddr, u16 hacr, int o, /* Offset in PSA */ + u8 * b, /* Buffer in memory */ + int n) +{ /* Length of buffer */ + int count = 0; + + wv_16_off(ioaddr, hacr); + + while (n-- > 0) { + outw(o, PIOR2(ioaddr)); + o++; + + outb(*b, PIOP2(ioaddr)); + b++; + + /* Wait for the memory to finish its write cycle */ + count = 0; + while ((count++ < 100) && + (hasr_read(ioaddr) & HASR_PSA_BUSY)) mdelay(1); + } + + wv_16_on(ioaddr, hacr); +} /* psa_write */ + +#ifdef SET_PSA_CRC +/*------------------------------------------------------------------*/ +/* + * Calculate the PSA CRC + * Thanks to Valster, Nico for the code + * NOTE: By specifying a length including the CRC position the + * returned value should be zero. (i.e. a correct checksum in the PSA) + * + * The Windows drivers don't use the CRC, but the AP and the PtP tool + * depend on it. + */ +static inline u16 psa_crc(u8 * psa, /* The PSA */ + int size) +{ /* Number of short for CRC */ + int byte_cnt; /* Loop on the PSA */ + u16 crc_bytes = 0; /* Data in the PSA */ + int bit_cnt; /* Loop on the bits of the short */ + + for (byte_cnt = 0; byte_cnt < size; byte_cnt++) { + crc_bytes ^= psa[byte_cnt]; /* Its an xor */ + + for (bit_cnt = 1; bit_cnt < 9; bit_cnt++) { + if (crc_bytes & 0x0001) + crc_bytes = (crc_bytes >> 1) ^ 0xA001; + else + crc_bytes >>= 1; + } + } + + return crc_bytes; +} /* psa_crc */ +#endif /* SET_PSA_CRC */ + +/*------------------------------------------------------------------*/ +/* + * update the checksum field in the Wavelan's PSA + */ +static void update_psa_checksum(device * dev, unsigned long ioaddr, u16 hacr) +{ +#ifdef SET_PSA_CRC + psa_t psa; + u16 crc; + + /* read the parameter storage area */ + psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa)); + + /* update the checksum */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc[0]) - + sizeof(psa.psa_crc[1]) + - sizeof(psa.psa_crc_status)); + + psa.psa_crc[0] = crc & 0xFF; + psa.psa_crc[1] = (crc & 0xFF00) >> 8; + + /* Write it ! */ + psa_write(ioaddr, hacr, (char *) &psa.psa_crc - (char *) &psa, + (unsigned char *) &psa.psa_crc, 2); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", + dev->name, psa.psa_crc[0], psa.psa_crc[1]); + + /* Check again (luxury !) */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc_status)); + + if (crc != 0) + printk(KERN_WARNING + "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", + dev->name); +#endif /* DEBUG_IOCTL_INFO */ +#endif /* SET_PSA_CRC */ +} /* update_psa_checksum */ + +/*------------------------------------------------------------------*/ +/* + * Write 1 byte to the MMC. + */ +static inline void mmc_out(unsigned long ioaddr, u16 o, u8 d) +{ + /* Wait for MMC to go idle */ + while (inw(HASR(ioaddr)) & HASR_MMC_BUSY); + + outw((u16) (((u16) d << 8) | (o << 1) | 1), MMCR(ioaddr)); +} + +/*------------------------------------------------------------------*/ +/* + * Routine to write bytes to the Modem Management Controller. + * We start at the end because it is the way it should be! + */ +static inline void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n) +{ + o += n; + b += n; + + while (n-- > 0) + mmc_out(ioaddr, --o, *(--b)); +} /* mmc_write */ + +/*------------------------------------------------------------------*/ +/* + * Read a byte from the MMC. + * Optimised version for 1 byte, avoid using memory. + */ +static inline u8 mmc_in(unsigned long ioaddr, u16 o) +{ + while (inw(HASR(ioaddr)) & HASR_MMC_BUSY); + outw(o << 1, MMCR(ioaddr)); + + while (inw(HASR(ioaddr)) & HASR_MMC_BUSY); + return (u8) (inw(MMCR(ioaddr)) >> 8); +} + +/*------------------------------------------------------------------*/ +/* + * Routine to read bytes from the Modem Management Controller. + * The implementation is complicated by a lack of address lines, + * which prevents decoding of the low-order bit. + * (code has just been moved in the above function) + * We start at the end because it is the way it should be! + */ +static inline void mmc_read(unsigned long ioaddr, u8 o, u8 * b, int n) +{ + o += n; + b += n; + + while (n-- > 0) + *(--b) = mmc_in(ioaddr, --o); +} /* mmc_read */ + +/*------------------------------------------------------------------*/ +/* + * Get the type of encryption available. + */ +static inline int mmc_encr(unsigned long ioaddr) +{ /* I/O port of the card */ + int temp; + + temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail)); + if ((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) + return 0; + else + return temp; +} + +/*------------------------------------------------------------------*/ +/* + * Wait for the frequency EEPROM to complete a command. + * I hope this one will be optimally inlined. + */ +static inline void fee_wait(unsigned long ioaddr, /* I/O port of the card */ + int delay, /* Base delay to wait for */ + int number) +{ /* Number of time to wait */ + int count = 0; /* Wait only a limited time */ + + while ((count++ < number) && + (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + MMR_FEE_STATUS_BUSY)) udelay(delay); +} + +/*------------------------------------------------------------------*/ +/* + * Read bytes from the Frequency EEPROM (frequency select cards). + */ +static void fee_read(unsigned long ioaddr, /* I/O port of the card */ + u16 o, /* destination offset */ + u16 * b, /* data buffer */ + int n) +{ /* number of registers */ + b += n; /* Position at the end of the area */ + + /* Write the address */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while (n-- > 0) { + /* Write the read command */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ); + + /* Wait until EEPROM is ready (should be quick). */ + fee_wait(ioaddr, 10, 100); + + /* Read the value. */ + *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) | + mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); + } +} + +#ifdef WIRELESS_EXT /* if the wireless extension exists in the kernel */ + +/*------------------------------------------------------------------*/ +/* + * Write bytes from the Frequency EEPROM (frequency select cards). + * This is a bit complicated, because the frequency EEPROM has to + * be unprotected and the write enabled. + * Jean II + */ +static void fee_write(unsigned long ioaddr, /* I/O port of the card */ + u16 o, /* destination offset */ + u16 * b, /* data buffer */ + int n) +{ /* number of registers */ + b += n; /* Position at the end of the area. */ + +#ifdef EEPROM_IS_PROTECTED /* disabled */ +#ifdef DOESNT_SEEM_TO_WORK /* disabled */ + /* Ask to read the protected register */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); + + fee_wait(ioaddr, 10, 100); + + /* Read the protected register. */ + printk("Protected 2: %02X-%02X\n", + mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)), + mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); +#endif /* DOESNT_SEEM_TO_WORK */ + + /* Enable protected register. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); + + fee_wait(ioaddr, 10, 100); + + /* Unprotect area. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); +#ifdef DOESNT_SEEM_TO_WORK /* disabled */ + /* or use: */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); +#endif /* DOESNT_SEEM_TO_WORK */ + + fee_wait(ioaddr, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ + + /* Write enable. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); + + fee_wait(ioaddr, 10, 100); + + /* Write the EEPROM address. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while (n-- > 0) { + /* Write the value. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); + mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF); + + /* Write the write command. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_WRITE); + + /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */ + mdelay(10); + fee_wait(ioaddr, 10, 100); + } + + /* Write disable. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); + + fee_wait(ioaddr, 10, 100); + +#ifdef EEPROM_IS_PROTECTED /* disabled */ + /* Reprotect EEPROM. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); + + fee_wait(ioaddr, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ +} +#endif /* WIRELESS_EXT */ + +/************************ I82586 SUBROUTINES *************************/ +/* + * Useful subroutines to manage the Ethernet controller + */ + +/*------------------------------------------------------------------*/ +/* + * Read bytes from the on-board RAM. + * Why does inlining this function make it fail? + */ +static /*inline */ void obram_read(unsigned long ioaddr, + u16 o, u8 * b, int n) +{ + outw(o, PIOR1(ioaddr)); + insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); +} + +/*------------------------------------------------------------------*/ +/* + * Write bytes to the on-board RAM. + */ +static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n) +{ + outw(o, PIOR1(ioaddr)); + outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); +} + +/*------------------------------------------------------------------*/ +/* + * Acknowledge the reading of the status issued by the i82586. + */ +static void wv_ack(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 scb_cs; + int i; + + obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + scb_cs &= SCB_ST_INT; + + if (scb_cs == 0) + return; + + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + + set_chan_attn(ioaddr, lp->hacr); + + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + if (scb_cs == 0) + break; + + udelay(10); + } + udelay(100); + +#ifdef DEBUG_CONFIG_ERROR + if (i <= 0) + printk(KERN_INFO + "%s: wv_ack(): board not accepting command.\n", + dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * Set channel attention bit and busy wait until command has + * completed, then acknowledge completion of the command. + */ +static inline int wv_synchronous_cmd(device * dev, const char *str) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 scb_cmd; + ach_t cb; + int i; + + scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO; + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cmd, sizeof(scb_cmd)); + + set_chan_attn(ioaddr, lp->hacr); + + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, + sizeof(cb)); + if (cb.ac_status & AC_SFLD_C) + break; + + udelay(10); + } + udelay(100); + + if (i <= 0 || !(cb.ac_status & AC_SFLD_OK)) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO "%s: %s failed; status = 0x%x\n", + dev->name, str, cb.ac_status); +#endif +#ifdef DEBUG_I82586_SHOW + wv_scb_show(ioaddr); +#endif + return -1; + } + + /* Ack the status */ + wv_ack(dev); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Configuration commands completion interrupt. + * Check if done, and if OK. + */ +static inline int +wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp) +{ + unsigned short mcs_addr; + unsigned short status; + int ret; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name); +#endif + + mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t) + + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t); + + /* Read the status of the last command (set mc list). */ + obram_read(ioaddr, acoff(mcs_addr, ac_status), + (unsigned char *) &status, sizeof(status)); + + /* If not completed -> exit */ + if ((status & AC_SFLD_C) == 0) + ret = 0; /* Not ready to be scrapped */ + else { +#ifdef DEBUG_CONFIG_ERROR + unsigned short cfg_addr; + unsigned short ias_addr; + + /* Check mc_config command */ + if ((status & AC_SFLD_OK) != AC_SFLD_OK) + printk(KERN_INFO + "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n", + dev->name, status); + + /* check ia-config command */ + ias_addr = mcs_addr - sizeof(ac_ias_t); + obram_read(ioaddr, acoff(ias_addr, ac_status), + (unsigned char *) &status, sizeof(status)); + if ((status & AC_SFLD_OK) != AC_SFLD_OK) + printk(KERN_INFO + "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n", + dev->name, status); + + /* Check config command. */ + cfg_addr = ias_addr - sizeof(ac_cfg_t); + obram_read(ioaddr, acoff(cfg_addr, ac_status), + (unsigned char *) &status, sizeof(status)); + if ((status & AC_SFLD_OK) != AC_SFLD_OK) + printk(KERN_INFO + "%s: wv_config_complete(): configure failed; status = 0x%x\n", + dev->name, status); +#endif /* DEBUG_CONFIG_ERROR */ + + ret = 1; /* Ready to be scrapped */ + } + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name, + ret); +#endif + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Command completion interrupt. + * Reclaim as many freed tx buffers as we can. + * (called in wavelan_interrupt()). + * Note : the spinlock is already grabbed for us. + */ +static int wv_complete(device * dev, unsigned long ioaddr, net_local * lp) +{ + int nreaped = 0; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name); +#endif + + /* Loop on all the transmit buffers */ + while (lp->tx_first_in_use != I82586NULL) { + unsigned short tx_status; + + /* Read the first transmit buffer */ + obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), + (unsigned char *) &tx_status, + sizeof(tx_status)); + + /* If not completed -> exit */ + if ((tx_status & AC_SFLD_C) == 0) + break; + + /* Hack for reconfiguration */ + if (tx_status == 0xFFFF) + if (!wv_config_complete(dev, ioaddr, lp)) + break; /* Not completed */ + + /* We now remove this buffer */ + nreaped++; + --lp->tx_n_in_use; + +/* +if (lp->tx_n_in_use > 0) + printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]); +*/ + + /* Was it the last one? */ + if (lp->tx_n_in_use <= 0) + lp->tx_first_in_use = I82586NULL; + else { + /* Next one in the chain */ + lp->tx_first_in_use += TXBLOCKZ; + if (lp->tx_first_in_use >= + OFFSET_CU + + NTXBLOCKS * TXBLOCKZ) lp->tx_first_in_use -= + NTXBLOCKS * TXBLOCKZ; + } + + /* Hack for reconfiguration */ + if (tx_status == 0xFFFF) + continue; + + /* Now, check status of the finished command */ + if (tx_status & AC_SFLD_OK) { + int ncollisions; + + lp->stats.tx_packets++; + ncollisions = tx_status & AC_SFLD_MAXCOL; + lp->stats.collisions += ncollisions; +#ifdef DEBUG_TX_INFO + if (ncollisions > 0) + printk(KERN_DEBUG + "%s: wv_complete(): tx completed after %d collisions.\n", + dev->name, ncollisions); +#endif + } else { + lp->stats.tx_errors++; + if (tx_status & AC_SFLD_S10) { + lp->stats.tx_carrier_errors++; +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG + "%s: wv_complete(): tx error: no CS.\n", + dev->name); +#endif + } + if (tx_status & AC_SFLD_S9) { + lp->stats.tx_carrier_errors++; +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG + "%s: wv_complete(): tx error: lost CTS.\n", + dev->name); +#endif + } + if (tx_status & AC_SFLD_S8) { + lp->stats.tx_fifo_errors++; +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG + "%s: wv_complete(): tx error: slow DMA.\n", + dev->name); +#endif + } + if (tx_status & AC_SFLD_S6) { + lp->stats.tx_heartbeat_errors++; +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG + "%s: wv_complete(): tx error: heart beat.\n", + dev->name); +#endif + } + if (tx_status & AC_SFLD_S5) { + lp->stats.tx_aborted_errors++; +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG + "%s: wv_complete(): tx error: too many collisions.\n", + dev->name); +#endif + } + } + +#ifdef DEBUG_TX_INFO + printk(KERN_DEBUG + "%s: wv_complete(): tx completed, tx_status 0x%04x\n", + dev->name, tx_status); +#endif + } + +#ifdef DEBUG_INTERRUPT_INFO + if (nreaped > 1) + printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n", + dev->name, nreaped); +#endif + + /* + * Inform upper layers. + */ + if (lp->tx_n_in_use < NTXBLOCKS - 1) { + netif_wake_queue(dev); + } +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name); +#endif + return nreaped; +} + +/*------------------------------------------------------------------*/ +/* + * Reconfigure the i82586, or at least ask for it. + * Because wv_82586_config uses a transmission buffer, we must do it + * when we are sure that there is one left, so we do it now + * or in wavelan_packet_xmit() (I can't find any better place, + * wavelan_interrupt is not an option), so you may experience + * delays sometimes. + */ +static inline void wv_82586_reconfig(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long flags; + + /* Arm the flag, will be cleard in wv_82586_config() */ + lp->reconfig_82586 = 1; + + /* Check if we can do it now ! */ + if((netif_running(dev)) && !(netif_queue_stopped(dev))) { + wv_splhi(lp, &flags); + /* May fail */ + wv_82586_config(dev); + wv_splx(lp, &flags); + } + else { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG + "%s: wv_82586_reconfig(): delayed (state = %lX)\n", + dev->name, dev->state); +#endif + } +} + +/********************* DEBUG & INFO SUBROUTINES *********************/ +/* + * This routine is used in the code to show information for debugging. + * Most of the time, it dumps the contents of hardware structures. + */ + +#ifdef DEBUG_PSA_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted contents of the Parameter Storage Area. + */ +static void wv_psa_show(psa_t * p) +{ + printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); + printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", + p->psa_io_base_addr_1, + p->psa_io_base_addr_2, + p->psa_io_base_addr_3, p->psa_io_base_addr_4); + printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", + p->psa_rem_boot_addr_1, + p->psa_rem_boot_addr_2, p->psa_rem_boot_addr_3); + printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); + printk("psa_int_req_no: %d\n", p->psa_int_req_no); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG + "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2], + p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5], + p->psa_unused0[6]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG + "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1], + p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3], + p->psa_univ_mac_addr[4], p->psa_univ_mac_addr[5]); + printk(KERN_DEBUG + "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_local_mac_addr[0], p->psa_local_mac_addr[1], + p->psa_local_mac_addr[2], p->psa_local_mac_addr[3], + p->psa_local_mac_addr[4], p->psa_local_mac_addr[5]); + printk(KERN_DEBUG "psa_univ_local_sel: %d, ", + p->psa_univ_local_sel); + printk("psa_comp_number: %d, ", p->psa_comp_number); + printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); + printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", + p->psa_feature_select); + printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); + printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); + printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); + printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], + p->psa_nwid[1]); + printk("psa_nwid_select: %d\n", p->psa_nwid_select); + printk(KERN_DEBUG "psa_encryption_select: %d, ", + p->psa_encryption_select); + printk + ("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_encryption_key[0], p->psa_encryption_key[1], + p->psa_encryption_key[2], p->psa_encryption_key[3], + p->psa_encryption_key[4], p->psa_encryption_key[5], + p->psa_encryption_key[6], p->psa_encryption_key[7]); + printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); + printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", + p->psa_call_code[0]); + printk + ("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + p->psa_call_code[0], p->psa_call_code[1], p->psa_call_code[2], + p->psa_call_code[3], p->psa_call_code[4], p->psa_call_code[5], + p->psa_call_code[6], p->psa_call_code[7]); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n", + p->psa_reserved[0], + p->psa_reserved[1], p->psa_reserved[2], p->psa_reserved[3]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); + printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); + printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); +} /* wv_psa_show */ +#endif /* DEBUG_PSA_SHOW */ + +#ifdef DEBUG_MMC_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the Modem Management Controller. + * This function needs to be completed. + */ +static void wv_mmc_show(device * dev) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; + mmr_t m; + + /* Basic check */ + if (hasr_read(ioaddr) & HASR_NO_CLK) { + printk(KERN_WARNING + "%s: wv_mmc_show: modem not connected\n", + dev->name); + return; + } + + /* Read the mmc */ + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); + mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m)); + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); + +#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ + /* Don't forget to update statistics */ + lp->wstats.discard.nwid += + (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; +#endif /* WIRELESS_EXT */ + + printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n"); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG + "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused0[0], m.mmr_unused0[1], m.mmr_unused0[2], + m.mmr_unused0[3], m.mmr_unused0[4], m.mmr_unused0[5], + m.mmr_unused0[6], m.mmr_unused0[7]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n", + m.mmr_des_avail, m.mmr_des_status); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused1[0], + m.mmr_unused1[1], + m.mmr_unused1[2], m.mmr_unused1[3], m.mmr_unused1[4]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", + m.mmr_dce_status, + (m. + mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? + "energy detected," : "", + (m. + mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? + "loop test indicated," : "", + (m. + mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? + "transmitter on," : "", + (m. + mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? + "jabber timer expired," : ""); + printk(KERN_DEBUG "Dsp ID: %02X\n", m.mmr_dsp_id); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", + m.mmr_unused2[0], m.mmr_unused2[1]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", + (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, + (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); + printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", + m.mmr_thr_pre_set & MMR_THR_PRE_SET, + (m. + mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : + "below"); + printk(KERN_DEBUG "signal_lvl: %d [%s], ", + m.mmr_signal_lvl & MMR_SIGNAL_LVL, + (m. + mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : + "no new msg"); + printk("silence_lvl: %d [%s], ", + m.mmr_silence_lvl & MMR_SILENCE_LVL, + (m. + mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : + "no new update"); + printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL, + (m. + mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : + "Antenna 0"); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); +#endif /* DEBUG_SHOW_UNUSED */ +} /* wv_mmc_show */ +#endif /* DEBUG_MMC_SHOW */ + +#ifdef DEBUG_I82586_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the last block of the i82586 memory. + */ +static void wv_scb_show(unsigned long ioaddr) +{ + scb_t scb; + + obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, + sizeof(scb)); + + printk(KERN_DEBUG "##### WaveLAN system control block: #####\n"); + + printk(KERN_DEBUG "status: "); + printk("stat 0x%x[%s%s%s%s] ", + (scb. + scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | + SCB_ST_RNR)) >> 12, + (scb. + scb_status & SCB_ST_CX) ? "command completion interrupt," : + "", (scb.scb_status & SCB_ST_FR) ? "frame received," : "", + (scb. + scb_status & SCB_ST_CNA) ? "command unit not active," : "", + (scb. + scb_status & SCB_ST_RNR) ? "receiving unit not ready," : + ""); + printk("cus 0x%x[%s%s%s] ", (scb.scb_status & SCB_ST_CUS) >> 8, + ((scb.scb_status & SCB_ST_CUS) == + SCB_ST_CUS_IDLE) ? "idle" : "", + ((scb.scb_status & SCB_ST_CUS) == + SCB_ST_CUS_SUSP) ? "suspended" : "", + ((scb.scb_status & SCB_ST_CUS) == + SCB_ST_CUS_ACTV) ? "active" : ""); + printk("rus 0x%x[%s%s%s%s]\n", (scb.scb_status & SCB_ST_RUS) >> 4, + ((scb.scb_status & SCB_ST_RUS) == + SCB_ST_RUS_IDLE) ? "idle" : "", + ((scb.scb_status & SCB_ST_RUS) == + SCB_ST_RUS_SUSP) ? "suspended" : "", + ((scb.scb_status & SCB_ST_RUS) == + SCB_ST_RUS_NRES) ? "no resources" : "", + ((scb.scb_status & SCB_ST_RUS) == + SCB_ST_RUS_RDY) ? "ready" : ""); + + printk(KERN_DEBUG "command: "); + printk("ack 0x%x[%s%s%s%s] ", + (scb. + scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR | + SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12, + (scb. + scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "", + (scb. + scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "", + (scb. + scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "", + (scb. + scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : ""); + printk("cuc 0x%x[%s%s%s%s%s] ", + (scb.scb_command & SCB_CMD_CUC) >> 8, + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_NOP) ? "nop" : "", + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_GO) ? "start cbl_offset" : "", + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_RES) ? "resume execution" : "", + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_SUS) ? "suspend execution" : "", + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_ABT) ? "abort execution" : ""); + printk("ruc 0x%x[%s%s%s%s%s]\n", + (scb.scb_command & SCB_CMD_RUC) >> 4, + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_NOP) ? "nop" : "", + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_GO) ? "start rfa_offset" : "", + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_RES) ? "resume reception" : "", + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_SUS) ? "suspend reception" : "", + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_ABT) ? "abort reception" : ""); + + printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset); + printk("rfa_offset 0x%x\n", scb.scb_rfa_offset); + + printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs); + printk("alnerrs %d ", scb.scb_alnerrs); + printk("rscerrs %d ", scb.scb_rscerrs); + printk("ovrnerrs %d\n", scb.scb_ovrnerrs); +} + +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the i82586's receive unit. + */ +static void wv_ru_show(device * dev) +{ + /* net_local *lp = (net_local *) dev->priv; */ + + printk(KERN_DEBUG + "##### WaveLAN i82586 receiver unit status: #####\n"); + printk(KERN_DEBUG "ru:"); + /* + * Not implemented yet + */ + printk("\n"); +} /* wv_ru_show */ + +/*------------------------------------------------------------------*/ +/* + * Display info about one control block of the i82586 memory. + */ +static void wv_cu_show_one(device * dev, net_local * lp, int i, u16 p) +{ + unsigned long ioaddr; + ac_tx_t actx; + + ioaddr = dev->base_addr; + + printk("%d: 0x%x:", i, p); + + obram_read(ioaddr, p, (unsigned char *) &actx, sizeof(actx)); + printk(" status=0x%x,", actx.tx_h.ac_status); + printk(" command=0x%x,", actx.tx_h.ac_command); + + /* + { + tbd_t tbd; + + obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd)); + printk(" tbd_status=0x%x,", tbd.tbd_status); + } + */ + + printk("|"); +} + +/*------------------------------------------------------------------*/ +/* + * Print status of the command unit of the i82586. + */ +static void wv_cu_show(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + unsigned int i; + u16 p; + + printk(KERN_DEBUG + "##### WaveLAN i82586 command unit status: #####\n"); + + printk(KERN_DEBUG); + for (i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++) { + wv_cu_show_one(dev, lp, i, p); + + p += TXBLOCKZ; + if (p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) + p -= NTXBLOCKS * TXBLOCKZ; + } + printk("\n"); +} +#endif /* DEBUG_I82586_SHOW */ + +#ifdef DEBUG_DEVICE_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the WaveLAN PCMCIA device driver. + */ +static void wv_dev_show(device * dev) +{ + printk(KERN_DEBUG "dev:"); + printk(" state=%lX,", dev->state); + printk(" trans_start=%ld,", dev->trans_start); + printk(" flags=0x%x,", dev->flags); + printk("\n"); +} /* wv_dev_show */ + +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the WaveLAN PCMCIA device driver's + * private information. + */ +static void wv_local_show(device * dev) +{ + net_local *lp; + + lp = (net_local *) dev->priv; + + printk(KERN_DEBUG "local:"); + printk(" tx_n_in_use=%d,", lp->tx_n_in_use); + printk(" hacr=0x%x,", lp->hacr); + printk(" rx_head=0x%x,", lp->rx_head); + printk(" rx_last=0x%x,", lp->rx_last); + printk(" tx_first_free=0x%x,", lp->tx_first_free); + printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use); + printk("\n"); +} /* wv_local_show */ +#endif /* DEBUG_DEVICE_SHOW */ + +#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) +/*------------------------------------------------------------------*/ +/* + * Dump packet header (and content if necessary) on the screen + */ +static inline void wv_packet_info(u8 * p, /* Packet to dump */ + int length, /* Length of the packet */ + char *msg1, /* Name of the device */ + char *msg2) +{ /* Name of the function */ + int i; + int maxi; + + printk(KERN_DEBUG + "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", + msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); + printk(KERN_DEBUG + "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", + msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], + p[13]); + +#ifdef DEBUG_PACKET_DUMP + + printk(KERN_DEBUG "data=\""); + + if ((maxi = length) > DEBUG_PACKET_DUMP) + maxi = DEBUG_PACKET_DUMP; + for (i = 14; i < maxi; i++) + if (p[i] >= ' ' && p[i] <= '~') + printk(" %c", p[i]); + else + printk("%02X", p[i]); + if (maxi < length) + printk(".."); + printk("\"\n"); + printk(KERN_DEBUG "\n"); +#endif /* DEBUG_PACKET_DUMP */ +} +#endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ + +/*------------------------------------------------------------------*/ +/* + * This is the information which is displayed by the driver at startup. + * There are lots of flags for configuring it to your liking. + */ +static inline void wv_init_info(device * dev) +{ + short ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; + psa_t psa; + int i; + + /* Read the parameter storage area */ + psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); + +#ifdef DEBUG_PSA_SHOW + wv_psa_show(&psa); +#endif +#ifdef DEBUG_MMC_SHOW + wv_mmc_show(dev); +#endif +#ifdef DEBUG_I82586_SHOW + wv_cu_show(dev); +#endif + +#ifdef DEBUG_BASIC_SHOW + /* Now, let's go for the basic stuff. */ + printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr); + for (i = 0; i < WAVELAN_ADDR_SIZE; i++) + printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); + printk(", IRQ %d", dev->irq); + + /* Print current network ID. */ + if (psa.psa_nwid_select) + printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], + psa.psa_nwid[1]); + else + printk(", nwid off"); + + /* If 2.00 card */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + unsigned short freq; + + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(ioaddr, 0x00, &freq, 1); + + /* Print frequency */ + printk(", 2.00, %ld", (freq >> 6) + 2400L); + + /* Hack! */ + if (freq & 0x20) + printk(".5"); + } else { + printk(", PC"); + switch (psa.psa_comp_number) { + case PSA_COMP_PC_AT_915: + case PSA_COMP_PC_AT_2400: + printk("-AT"); + break; + case PSA_COMP_PC_MC_915: + case PSA_COMP_PC_MC_2400: + printk("-MC"); + break; + case PSA_COMP_PCMCIA_915: + printk("MCIA"); + break; + default: + printk("?"); + } + printk(", "); + switch (psa.psa_subband) { + case PSA_SUBBAND_915: + printk("915"); + break; + case PSA_SUBBAND_2425: + printk("2425"); + break; + case PSA_SUBBAND_2460: + printk("2460"); + break; + case PSA_SUBBAND_2484: + printk("2484"); + break; + case PSA_SUBBAND_2430_5: + printk("2430.5"); + break; + default: + printk("?"); + } + } + + printk(" MHz\n"); +#endif /* DEBUG_BASIC_SHOW */ + +#ifdef DEBUG_VERSION_SHOW + /* Print version information */ + printk(KERN_NOTICE "%s", version); +#endif +} /* wv_init_info */ + +/********************* IOCTL, STATS & RECONFIG *********************/ +/* + * We found here routines that are called by Linux on different + * occasions after the configuration and not for transmitting data + * These may be called when the user use ifconfig, /proc/net/dev + * or wireless extensions + */ + +/*------------------------------------------------------------------*/ +/* + * Get the current Ethernet statistics. This may be called with the + * card open or closed. + * Used when the user read /proc/net/dev + */ +static en_stats *wavelan_get_stats(device * dev) +{ +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); +#endif + + return (&((net_local *) dev->priv)->stats); +} + +/*------------------------------------------------------------------*/ +/* + * Set or clear the multicast filter for this adaptor. + * num_addrs == -1 Promiscuous mode, receive all packets + * num_addrs == 0 Normal mode, clear multicast list + * num_addrs > 0 Multicast mode, receive normal and MC packets, + * and do best-effort filtering. + */ +static void wavelan_set_multicast_list(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", + dev->name); +#endif + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG + "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", + dev->name, dev->flags, dev->mc_count); +#endif + + /* Are we asking for promiscuous mode, + * or all multicast addresses (we don't have that!) + * or too many multicast addresses for the hardware filter? */ + if ((dev->flags & IFF_PROMISC) || + (dev->flags & IFF_ALLMULTI) || + (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) { + /* + * Enable promiscuous mode: receive all packets. + */ + if (!lp->promiscuous) { + lp->promiscuous = 1; + lp->mc_count = 0; + + wv_82586_reconfig(dev); + + /* Tell the kernel that we are doing a really bad job. */ + dev->flags |= IFF_PROMISC; + } + } else + /* Are there multicast addresses to send? */ + if (dev->mc_list != (struct dev_mc_list *) NULL) { + /* + * Disable promiscuous mode, but receive all packets + * in multicast list + */ +#ifdef MULTICAST_AVOID + if (lp->promiscuous || (dev->mc_count != lp->mc_count)) +#endif + { + lp->promiscuous = 0; + lp->mc_count = dev->mc_count; + + wv_82586_reconfig(dev); + } + } else { + /* + * Switch to normal mode: disable promiscuous mode and + * clear the multicast list. + */ + if (lp->promiscuous || lp->mc_count == 0) { + lp->promiscuous = 0; + lp->mc_count = 0; + + wv_82586_reconfig(dev); + } + } +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", + dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * This function doesn't exist. + * (Note : it was a nice way to test the reconfigure stuff...) + */ +#ifdef SET_MAC_ADDRESS +static int wavelan_set_mac_address(device * dev, void *addr) +{ + struct sockaddr *mac = addr; + + /* Copy the address. */ + memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); + + /* Reconfigure the beast. */ + wv_82586_reconfig(dev); + + return 0; +} +#endif /* SET_MAC_ADDRESS */ + +#ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */ + +/*------------------------------------------------------------------*/ +/* + * Frequency setting (for hardware capable of it) + * It's a bit complicated and you don't really want to look into it. + * (called in wavelan_ioctl) + */ +static inline int wv_set_frequency(unsigned long ioaddr, /* I/O port of the card */ + iw_freq * frequency) +{ + const int BAND_NUM = 10; /* Number of bands */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ +#ifdef DEBUG_IOCTL_INFO + int i; +#endif + + /* Setting by frequency */ + /* Theoretically, you may set any frequency between + * the two limits with a 0.5 MHz precision. In practice, + * I don't want you to have trouble with local regulations. + */ + if ((frequency->e == 1) && + (frequency->m >= (int) 2.412e8) + && (frequency->m <= (int) 2.487e8)) { + freq = ((frequency->m / 10000) - 24000L) / 5; + } + + /* Setting by channel (same as wfreqsel) */ + /* Warning: each channel is 22 MHz wide, so some of the channels + * will interfere. */ + if ((frequency->e == 0) && (frequency->m < BAND_NUM)) { + /* Get frequency offset. */ + freq = channel_bands[frequency->m] >> 1; + } + + /* Verify that the frequency is allowed. */ + if (freq != 0L) { + u16 table[10]; /* Authorized frequency table */ + + /* Read the frequency table. */ + fee_read(ioaddr, 0x71, table, 10); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Frequency table: "); + for (i = 0; i < 10; i++) { + printk(" %04X", table[i]); + } + printk("\n"); +#endif + + /* Look in the table to see whether the frequency is allowed. */ + if (!(table[9 - ((freq - 24) / 16)] & + (1 << ((freq - 24) % 16)))) return -EINVAL; /* not allowed */ + } else + return -EINVAL; + + /* if we get a usable frequency */ + if (freq != 0L) { + unsigned short area[16]; + unsigned short dac[2]; + unsigned short area_verify[16]; + unsigned short dac_verify[2]; + /* Corresponding gain (in the power adjust value table) + * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8 + * and WCIN062D.DOC, page 6.2.9. */ + unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; + int power_band = 0; /* Selected band */ + unsigned short power_adjust; /* Correct value */ + + /* Search for the gain. */ + power_band = 0; + while ((freq > power_limit[power_band]) && + (power_limit[++power_band] != 0)); + + /* Read the first area. */ + fee_read(ioaddr, 0x00, area, 16); + + /* Read the DAC. */ + fee_read(ioaddr, 0x60, dac, 2); + + /* Read the new power adjust value. */ + fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, + 1); + if (power_band & 0x1) + power_adjust >>= 8; + else + power_adjust &= 0xFF; + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); + for (i = 0; i < 16; i++) { + printk(" %04X", area[i]); + } + printk("\n"); + + printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", + dac[0], dac[1]); +#endif + + /* Frequency offset (for info only) */ + area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); + + /* Receiver Principle main divider coefficient */ + area[3] = (freq >> 1) + 2400L - 352L; + area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + + /* Transmitter Main divider coefficient */ + area[13] = (freq >> 1) + 2400L; + area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + + /* Other parts of the area are flags, bit streams or unused. */ + + /* Set the value in the DAC. */ + dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); + dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); + + /* Write the first area. */ + fee_write(ioaddr, 0x00, area, 16); + + /* Write the DAC. */ + fee_write(ioaddr, 0x60, dac, 2); + + /* We now should verify here that the writing of the EEPROM went OK. */ + + /* Reread the first area. */ + fee_read(ioaddr, 0x00, area_verify, 16); + + /* Reread the DAC. */ + fee_read(ioaddr, 0x60, dac_verify, 2); + + /* Compare. */ + if (memcmp(area, area_verify, 16 * 2) || + memcmp(dac, dac_verify, 2 * 2)) { +#ifdef DEBUG_IOCTL_ERROR + printk(KERN_INFO + "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n"); +#endif + return -EOPNOTSUPP; + } + + /* We must download the frequency parameters to the + * synthesizers (from the EEPROM - area 1) + * Note: as the EEPROM is automatically decremented, we set the end + * if the area... */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + + /* Wait until the download is finished. */ + fee_wait(ioaddr, 100, 100); + + /* We must now download the power adjust value (gain) to + * the synthesizers (from the EEPROM - area 7 - DAC). */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + + /* Wait for the download to finish. */ + fee_wait(ioaddr, 100, 100); + +#ifdef DEBUG_IOCTL_INFO + /* Verification of what we have done */ + + printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); + for (i = 0; i < 16; i++) { + printk(" %04X", area_verify[i]); + } + printk("\n"); + + printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", + dac_verify[0], dac_verify[1]); +#endif + + return 0; + } else + return -EINVAL; /* Bah, never get there... */ +} + +/*------------------------------------------------------------------*/ +/* + * Give the list of available frequencies. + */ +static inline int wv_frequency_list(unsigned long ioaddr, /* I/O port of the card */ + iw_freq * list, /* List of frequencies to fill */ + int max) +{ /* Maximum number of frequencies */ + u16 table[10]; /* Authorized frequency table */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ + int i; /* index in the table */ + int c = 0; /* Channel number */ + + /* Read the frequency table. */ + fee_read(ioaddr, 0x71 /* frequency table */ , table, 10); + + /* Check all frequencies. */ + i = 0; + for (freq = 0; freq < 150; freq++) + /* Look in the table if the frequency is allowed */ + if (table[9 - (freq / 16)] & (1 << (freq % 16))) { + /* Compute approximate channel number */ + while ((((channel_bands[c] >> 1) - 24) < freq) && + (c < NELS(channel_bands))) + c++; + list[i].i = c; /* Set the list index */ + + /* put in the list */ + list[i].m = (((freq + 24) * 5) + 24000L) * 10000; + list[i++].e = 1; + + /* Check number. */ + if (i >= max) + return (i); + } + + return (i); +} + +#ifdef WIRELESS_SPY +/*------------------------------------------------------------------*/ +/* + * Gather wireless spy statistics: for each packet, compare the source + * address with our list, and if they match, get the statistics. + * Sorry, but this function really needs the wireless extensions. + */ +static inline void wl_spy_gather(device * dev, u8 * mac, /* MAC address */ + u8 * stats) +{ /* Statistics to gather */ + net_local *lp = (net_local *) dev->priv; + int i; + + /* Check all addresses. */ + for (i = 0; i < lp->spy_number; i++) + /* If match */ + if (!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) { + /* Update statistics */ + lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL; + lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL; + lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL; + lp->spy_stat[i].updated = 0x7; + } +} +#endif /* WIRELESS_SPY */ + +#ifdef HISTOGRAM +/*------------------------------------------------------------------*/ +/* + * This function calculates a histogram of the signal level. + * As the noise is quite constant, it's like doing it on the SNR. + * We have defined a set of interval (lp->his_range), and each time + * the level goes in that interval, we increment the count (lp->his_sum). + * With this histogram you may detect if one WaveLAN is really weak, + * or you may also calculate the mean and standard deviation of the level. + */ +static inline void wl_his_gather(device * dev, u8 * stats) +{ /* Statistics to gather */ + net_local *lp = (net_local *) dev->priv; + u8 level = stats[0] & MMR_SIGNAL_LVL; + int i; + + /* Find the correct interval. */ + i = 0; + while ((i < (lp->his_number - 1)) + && (level >= lp->his_range[i++])); + + /* Increment interval counter. */ + (lp->his_sum[i])++; +} +#endif /* HISTOGRAM */ + +/*------------------------------------------------------------------*/ +/* + * Perform ioctl for configuration and information. + * It is here that the wireless extensions are treated (iwconfig). + */ +static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is applied */ + struct ifreq *rq, /* data passed */ + int cmd) +{ /* ioctl number */ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct iwreq *wrq = (struct iwreq *) rq; + psa_t psa; + mm_t m; + unsigned long flags; + int ret = 0; + int err = 0; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, + cmd); +#endif + + /* Disable interrupts and save flags. */ + wv_splhi(lp, &flags); + + /* Look what is the request */ + switch (cmd) { + /* --------------- WIRELESS EXTENSIONS --------------- */ + + case SIOCGIWNAME: + strcpy(wrq->u.name, "WaveLAN"); + break; + + case SIOCSIWNWID: + /* Set NWID in WaveLAN. */ + if (!wrq->u.nwid.disabled) { + /* Set NWID in psa */ + psa.psa_nwid[0] = + (wrq->u.nwid.value & 0xFF00) >> 8; + psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF; + psa.psa_nwid_select = 0x01; + psa_write(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + + /* Set NWID in mmc. */ + m.w.mmw_netw_id_l = psa.psa_nwid[1]; + m.w.mmw_netw_id_h = psa.psa_nwid[0]; + mmc_write(ioaddr, + (char *) &m.w.mmw_netw_id_l - + (char *) &m, + (unsigned char *) &m.w.mmw_netw_id_l, 2); + mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); + } else { + /* Disable NWID in the psa. */ + psa.psa_nwid_select = 0x00; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_nwid_select - + (char *) &psa, + (unsigned char *) &psa.psa_nwid_select, + 1); + + /* Disable NWID in the mmc (no filtering). */ + mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), + MMW_LOOPT_SEL_DIS_NWID); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + break; + + case SIOCGIWNWID: + /* Read the NWID. */ + psa_read(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + wrq->u.nwid.value = + (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrq->u.nwid.disabled = !(psa.psa_nwid_select); + wrq->u.nwid.fixed = 1; /* Superfluous */ + break; + + case SIOCSIWFREQ: + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + ret = wv_set_frequency(ioaddr, &(wrq->u.freq)); + else + ret = -EOPNOTSUPP; + break; + + case SIOCGIWFREQ: + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). + * Does it work for everybody, especially old cards? */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + unsigned short freq; + + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(ioaddr, 0x00, &freq, 1); + wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; + wrq->u.freq.e = 1; + } else { + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_subband - (char *) &psa, + (unsigned char *) &psa.psa_subband, 1); + + if (psa.psa_subband <= 4) { + wrq->u.freq.m = + fixed_bands[psa.psa_subband]; + wrq->u.freq.e = (psa.psa_subband != 0); + } else + ret = -EOPNOTSUPP; + } + break; + + case SIOCSIWSENS: + /* Set the level threshold. */ + /* We should complain loudly if wrq->u.sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), + psa.psa_thr_pre_set); + break; + + case SIOCGIWSENS: + /* Read the level threshold. */ + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; + wrq->u.sens.fixed = 1; + break; + + case SIOCSIWENCODE: + /* Set encryption key */ + if (!mmc_encr(ioaddr)) { + ret = -EOPNOTSUPP; + break; + } + + /* Basic checking... */ + if (wrq->u.encoding.pointer != (caddr_t) 0) { + /* Check the size of the key */ + if (wrq->u.encoding.length != 8) { + ret = -EINVAL; + break; + } + + /* Copy the key in the driver */ + wv_splx(lp, &flags); + err = copy_from_user(psa.psa_encryption_key, + wrq->u.encoding.pointer, + wrq->u.encoding.length); + wv_splhi(lp, &flags); + if (err) { + ret = -EFAULT; + break; + } + + psa.psa_encryption_select = 1; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 8 + 1); + + mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), + MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); + mmc_write(ioaddr, mmwoff(0, mmw_encr_key), + (unsigned char *) &psa. + psa_encryption_key, 8); + } + + if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) { /* disable encryption */ + psa.psa_encryption_select = 0; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1); + + mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + break; + + case SIOCGIWENCODE: + /* Read the encryption key */ + if (!mmc_encr(ioaddr)) { + ret = -EOPNOTSUPP; + break; + } + + /* only super-user can see encryption key */ + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + + /* Basic checking... */ + if (wrq->u.encoding.pointer != (caddr_t) 0) { + /* Verify the user buffer */ + ret = + verify_area(VERIFY_WRITE, + wrq->u.encoding.pointer, 8); + if (ret) + break; + + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1 + 8); + + /* encryption is enabled ? */ + if (psa.psa_encryption_select) + wrq->u.encoding.flags = IW_ENCODE_ENABLED; + else + wrq->u.encoding.flags = IW_ENCODE_DISABLED; + wrq->u.encoding.flags |= mmc_encr(ioaddr); + + /* Copy the key to the user buffer */ + wrq->u.encoding.length = 8; + wv_splx(lp, &flags); + if (copy_to_user(wrq->u.encoding.pointer, + psa.psa_encryption_key, 8)) + ret = -EFAULT; + wv_splhi(lp, &flags); + } + break; + + case SIOCGIWRANGE: + /* basic checking */ + if (wrq->u.data.pointer != (caddr_t) 0) { + struct iw_range range; + + /* Set the length (very important for backward + * compatibility) */ + wrq->u.data.length = sizeof(struct iw_range); + + /* Set all the info we don't care or don't know + * about to zero */ + memset(&range, 0, sizeof(range)); + + /* Set the Wireless Extension versions */ + range.we_version_compiled = WIRELESS_EXT; + range.we_version_source = 9; + + /* Set information in the range struct. */ + range.throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ + range.min_nwid = 0x0000; + range.max_nwid = 0xFFFF; + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + range.num_channels = 10; + range.num_frequency = + wv_frequency_list(ioaddr, range.freq, + IW_MAX_FREQUENCIES); + } else + range.num_channels = range.num_frequency = + 0; + + range.sensitivity = 0x3F; + range.max_qual.qual = MMR_SGNL_QUAL; + range.max_qual.level = MMR_SIGNAL_LVL; + range.max_qual.noise = MMR_SILENCE_LVL; + range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ + /* Need to get better values for those two */ + range.avg_qual.level = 30; + range.avg_qual.noise = 8; + + range.num_bitrates = 1; + range.bitrate[0] = 2000000; /* 2 Mb/s */ + + /* Encryption supported ? */ + if (mmc_encr(ioaddr)) { + range.encoding_size[0] = 8; /* DES = 64 bits key */ + range.num_encoding_sizes = 1; + range.max_encoding_tokens = 1; /* Only one key possible */ + } else { + range.num_encoding_sizes = 0; + range.max_encoding_tokens = 0; + } + + /* Copy structure to the user buffer. */ + wv_splx(lp, &flags); + if (copy_to_user(wrq->u.data.pointer, + &range, + sizeof(struct iw_range))) + ret = -EFAULT; + wv_splhi(lp, &flags); + } + break; + + case SIOCGIWPRIV: + /* Basic checking */ + if (wrq->u.data.pointer != (caddr_t) 0) { + struct iw_priv_args priv[] = { + /* { cmd, + set_args, + get_args, + name } */ + { SIOCSIPQTHR, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + 0, + "setqualthr" }, + { SIOCGIPQTHR, + 0, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, + "getqualthr" }, + { SIOCSIPHISTO, + IW_PRIV_TYPE_BYTE | 16, + 0, + "sethisto" }, + { SIOCGIPHISTO, + 0, + IW_PRIV_TYPE_INT | 16, + "gethisto" }, + }; + + /* Set the number of available ioctls. */ + wrq->u.data.length = 4; + + /* Copy structure to the user buffer. */ + wv_splx(lp, &flags); + if (copy_to_user(wrq->u.data.pointer, + (u8 *) priv, + sizeof(priv))) + ret = -EFAULT; + wv_splhi(lp, &flags); + } + break; + +#ifdef WIRELESS_SPY + case SIOCSIWSPY: + /* Set the spy list */ + + /* Check the number of addresses. */ + if (wrq->u.data.length > IW_MAX_SPY) { + ret = -E2BIG; + break; + } + lp->spy_number = wrq->u.data.length; + + /* Are there are addresses to copy? */ + if (lp->spy_number > 0) { + struct sockaddr address[IW_MAX_SPY]; + int i; + + /* Copy addresses to the driver. */ + wv_splx(lp, &flags); + err = copy_from_user(address, + wrq->u.data.pointer, + sizeof(struct sockaddr) + * lp->spy_number); + wv_splhi(lp, &flags); + if (err) { + ret = -EFAULT; + break; + } + + /* Copy addresses to the lp structure. */ + for (i = 0; i < lp->spy_number; i++) { + memcpy(lp->spy_address[i], + address[i].sa_data, + WAVELAN_ADDR_SIZE); + } + + /* Reset structure. */ + memset(lp->spy_stat, 0x00, + sizeof(iw_qual) * IW_MAX_SPY); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG + "SetSpy: set of new addresses is: \n"); + for (i = 0; i < wrq->u.data.length; i++) + printk(KERN_DEBUG + "%02X:%02X:%02X:%02X:%02X:%02X \n", + lp->spy_address[i][0], + lp->spy_address[i][1], + lp->spy_address[i][2], + lp->spy_address[i][3], + lp->spy_address[i][4], + lp->spy_address[i][5]); +#endif /* DEBUG_IOCTL_INFO */ + } + + break; + + case SIOCGIWSPY: + /* Get the spy list and spy stats. */ + + /* Set the number of addresses */ + wrq->u.data.length = lp->spy_number; + + /* Does the user want to have the addresses back? */ + if ((lp->spy_number > 0) + && (wrq->u.data.pointer != (caddr_t) 0)) { + struct sockaddr address[IW_MAX_SPY]; + int i; + + /* Copy addresses from the lp structure. */ + for (i = 0; i < lp->spy_number; i++) { + memcpy(address[i].sa_data, + lp->spy_address[i], + WAVELAN_ADDR_SIZE); + address[i].sa_family = AF_UNIX; + } + + /* Copy addresses to the user buffer. */ + wv_splx(lp, &flags); + err = copy_to_user(wrq->u.data.pointer, + address, + sizeof(struct sockaddr) + * lp->spy_number); + + /* Copy stats to the user buffer (just after). */ + err |= copy_to_user(wrq->u.data.pointer + + (sizeof(struct sockaddr) + * lp->spy_number), + lp->spy_stat, + sizeof(iw_qual) * lp->spy_number); + wv_splhi(lp, &flags); + if (err) { + ret = -EFAULT; + break; + } + + /* Reset updated flags. */ + for (i = 0; i < lp->spy_number; i++) + lp->spy_stat[i].updated = 0x0; + } + /* if(pointer != NULL) */ + break; +#endif /* WIRELESS_SPY */ + + /* ------------------ PRIVATE IOCTL ------------------ */ + + case SIOCSIPQTHR: + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + psa.psa_quality_thr = *(wrq->u.name) & 0x0F; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), + psa.psa_quality_thr); + break; + + case SIOCGIPQTHR: + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + *(wrq->u.name) = psa.psa_quality_thr & 0x0F; + break; + +#ifdef HISTOGRAM + case SIOCSIPHISTO: + /* Verify that the user is root. */ + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + + /* Check the number of intervals. */ + if (wrq->u.data.length > 16) { + ret = -E2BIG; + break; + } + lp->his_number = wrq->u.data.length; + + /* Are there addresses to copy? */ + if (lp->his_number > 0) { + /* Copy interval ranges to the driver */ + wv_splx(lp, &flags); + err = copy_from_user(lp->his_range, + wrq->u.data.pointer, + sizeof(char) * lp->his_number); + wv_splhi(lp, &flags); + if (err) { + ret = -EFAULT; + break; + } + + /* Reset structure. */ + memset(lp->his_sum, 0x00, sizeof(long) * 16); + } + break; + + case SIOCGIPHISTO: + /* Set the number of intervals. */ + wrq->u.data.length = lp->his_number; + + /* Give back the distribution statistics */ + if ((lp->his_number > 0) + && (wrq->u.data.pointer != (caddr_t) 0)) { + /* Copy data to the user buffer. */ + wv_splx(lp, &flags); + if (copy_to_user(wrq->u.data.pointer, + lp->his_sum, + sizeof(long) * lp->his_number); + ret = -EFAULT; + wv_splhi(lp, &flags); + + } /* if(pointer != NULL) */ + break; +#endif /* HISTOGRAM */ + + /* ------------------- OTHER IOCTL ------------------- */ + + default: + ret = -EOPNOTSUPP; + } /* switch (cmd) */ + + /* Enable interrupts and restore flags. */ + wv_splx(lp, &flags); + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); +#endif + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Get wireless statistics. + * Called by /proc/net/wireless + */ +static iw_stats *wavelan_get_wireless_stats(device * dev) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; + mmr_t m; + iw_stats *wstats; + unsigned long flags; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", + dev->name); +#endif + + /* Check */ + if (lp == (net_local *) NULL) + return (iw_stats *) NULL; + + /* Disable interrupts and save flags. */ + wv_splhi(lp, &flags); + + wstats = &lp->wstats; + + /* Get data from the mmc. */ + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); + + mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); + mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, + 2); + mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, + 4); + + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); + + /* Copy data to wireless stuff. */ + wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; + wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; + wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; + wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; + wstats->qual.updated = (((m. mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) + | ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) + | ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); + wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; + wstats->discard.code = 0L; + wstats->discard.misc = 0L; + + /* Enable interrupts and restore flags. */ + wv_splx(lp, &flags); + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", + dev->name); +#endif + return &lp->wstats; +} +#endif /* WIRELESS_EXT */ + +/************************* PACKET RECEPTION *************************/ +/* + * This part deals with receiving the packets. + * The interrupt handler gets an interrupt when a packet has been + * successfully received and calls this part. + */ + +/*------------------------------------------------------------------*/ +/* + * This routine does the actual copying of data (including the Ethernet + * header structure) from the WaveLAN card to an sk_buff chain that + * will be passed up to the network interface layer. NOTE: we + * currently don't handle trailer protocols (neither does the rest of + * the network interface), so if that is needed, it will (at least in + * part) be added here. The contents of the receive ring buffer are + * copied to a message chain that is then passed to the kernel. + * + * Note: if any errors occur, the packet is "dropped on the floor". + * (called by wv_packet_rcv()) + */ +static inline void +wv_packet_read(device * dev, u16 buf_off, int sksize) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + struct sk_buff *skb; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", + dev->name, buf_off, sksize); +#endif + + /* Allocate buffer for the data */ + if ((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL) { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO + "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n", + dev->name, sksize); +#endif + lp->stats.rx_dropped++; + return; + } + + skb->dev = dev; + + /* Copy the packet to the buffer. */ + obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize); + skb->protocol = eth_type_trans(skb, dev); + +#ifdef DEBUG_RX_INFO + wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read"); +#endif /* DEBUG_RX_INFO */ + + /* Statistics-gathering and associated stuff. + * It seem a bit messy with all the define, but it's really simple... */ +#if defined(WIRELESS_SPY) || defined(HISTOGRAM) + if ( +#ifdef WIRELESS_SPY + (lp->spy_number > 0) || +#endif /* WIRELESS_SPY */ +#ifdef HISTOGRAM + (lp->his_number > 0) || +#endif /* HISTOGRAM */ + 0) { + u8 stats[3]; /* signal level, noise level, signal quality */ + + /* Read signal level, silence level and signal quality bytes. */ + /* Note: in the PCMCIA hardware, these are part of the frame. It seems + * that for the ISA hardware, it's nowhere to be found in the frame, + * so I'm obliged to do this (it has a side effect on /proc/net/wireless). + * Any ideas? + */ + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); + mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3); + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); + +#ifdef DEBUG_RX_INFO + printk(KERN_DEBUG + "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", + dev->name, stats[0] & 0x3F, stats[1] & 0x3F, + stats[2] & 0x0F); +#endif + + /* Spying stuff */ +#ifdef WIRELESS_SPY + wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, + stats); +#endif /* WIRELESS_SPY */ +#ifdef HISTOGRAM + wl_his_gather(dev, stats); +#endif /* HISTOGRAM */ + } +#endif /* defined(WIRELESS_SPY) || defined(HISTOGRAM) */ + + /* + * Hand the packet to the network module. + */ + netif_rx(skb); + + /* Keep statistics up to date */ + dev->last_rx = jiffies; + lp->stats.rx_packets++; + lp->stats.rx_bytes += sksize; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * Transfer as many packets as we can + * from the device RAM. + * (called in wavelan_interrupt()). + * Note : the spinlock is already grabbed for us. + */ +static inline void wv_receive(device * dev) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; + fd_t fd; + rbd_t rbd; + int nreaped = 0; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name); +#endif + + /* Loop on each received packet. */ + for (;;) { + obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, + sizeof(fd)); + + /* Note about the status : + * It start up to be 0 (the value we set). Then, when the RU + * grab the buffer to prepare for reception, it sets the + * FD_STATUS_B flag. When the RU has finished receiving the + * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate + * completion and set the other flags to indicate the eventual + * errors. FD_STATUS_OK indicates that the reception was OK. + */ + + /* If the current frame is not complete, we have reached the end. */ + if ((fd.fd_status & FD_STATUS_C) != FD_STATUS_C) + break; /* This is how we exit the loop. */ + + nreaped++; + + /* Check whether frame was correctly received. */ + if ((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK) { + /* Does the frame contain a pointer to the data? Let's check. */ + if (fd.fd_rbd_offset != I82586NULL) { + /* Read the receive buffer descriptor */ + obram_read(ioaddr, fd.fd_rbd_offset, + (unsigned char *) &rbd, + sizeof(rbd)); + +#ifdef DEBUG_RX_ERROR + if ((rbd.rbd_status & RBD_STATUS_EOF) != + RBD_STATUS_EOF) printk(KERN_INFO + "%s: wv_receive(): missing EOF flag.\n", + dev->name); + + if ((rbd.rbd_status & RBD_STATUS_F) != + RBD_STATUS_F) printk(KERN_INFO + "%s: wv_receive(): missing F flag.\n", + dev->name); +#endif /* DEBUG_RX_ERROR */ + + /* Read the packet and transmit to Linux */ + wv_packet_read(dev, rbd.rbd_bufl, + rbd. + rbd_status & + RBD_STATUS_ACNT); + } +#ifdef DEBUG_RX_ERROR + else /* if frame has no data */ + printk(KERN_INFO + "%s: wv_receive(): frame has no data.\n", + dev->name); +#endif + } else { /* If reception was no successful */ + + lp->stats.rx_errors++; + +#ifdef DEBUG_RX_INFO + printk(KERN_DEBUG + "%s: wv_receive(): frame not received successfully (%X).\n", + dev->name, fd.fd_status); +#endif + +#ifdef DEBUG_RX_ERROR + if ((fd.fd_status & FD_STATUS_S6) != 0) + printk(KERN_INFO + "%s: wv_receive(): no EOF flag.\n", + dev->name); +#endif + + if ((fd.fd_status & FD_STATUS_S7) != 0) { + lp->stats.rx_length_errors++; +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG + "%s: wv_receive(): frame too short.\n", + dev->name); +#endif + } + + if ((fd.fd_status & FD_STATUS_S8) != 0) { + lp->stats.rx_over_errors++; +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG + "%s: wv_receive(): rx DMA overrun.\n", + dev->name); +#endif + } + + if ((fd.fd_status & FD_STATUS_S9) != 0) { + lp->stats.rx_fifo_errors++; +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG + "%s: wv_receive(): ran out of resources.\n", + dev->name); +#endif + } + + if ((fd.fd_status & FD_STATUS_S10) != 0) { + lp->stats.rx_frame_errors++; +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG + "%s: wv_receive(): alignment error.\n", + dev->name); +#endif + } + + if ((fd.fd_status & FD_STATUS_S11) != 0) { + lp->stats.rx_crc_errors++; +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG + "%s: wv_receive(): CRC error.\n", + dev->name); +#endif + } + } + + fd.fd_status = 0; + obram_write(ioaddr, fdoff(lp->rx_head, fd_status), + (unsigned char *) &fd.fd_status, + sizeof(fd.fd_status)); + + fd.fd_command = FD_COMMAND_EL; + obram_write(ioaddr, fdoff(lp->rx_head, fd_command), + (unsigned char *) &fd.fd_command, + sizeof(fd.fd_command)); + + fd.fd_command = 0; + obram_write(ioaddr, fdoff(lp->rx_last, fd_command), + (unsigned char *) &fd.fd_command, + sizeof(fd.fd_command)); + + lp->rx_last = lp->rx_head; + lp->rx_head = fd.fd_link_offset; + } /* for(;;) -> loop on all frames */ + +#ifdef DEBUG_RX_INFO + if (nreaped > 1) + printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n", + dev->name, nreaped); +#endif +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name); +#endif +} + +/*********************** PACKET TRANSMISSION ***********************/ +/* + * This part deals with sending packets through the WaveLAN. + * + */ + +/*------------------------------------------------------------------*/ +/* + * This routine fills in the appropriate registers and memory + * locations on the WaveLAN card and starts the card off on + * the transmit. + * + * The principle: + * Each block contains a transmit command, a NOP command, + * a transmit block descriptor and a buffer. + * The CU read the transmit block which point to the tbd, + * read the tbd and the content of the buffer. + * When it has finish with it, it goes to the next command + * which in our case is the NOP. The NOP points on itself, + * so the CU stop here. + * When we add the next block, we modify the previous nop + * to make it point on the new tx command. + * Simple, isn't it ? + * + * (called in wavelan_packet_xmit()) + */ +static inline int wv_packet_write(device * dev, void *buf, short length) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + unsigned short txblock; + unsigned short txpred; + unsigned short tx_addr; + unsigned short nop_addr; + unsigned short tbd_addr; + unsigned short buf_addr; + ac_tx_t tx; + ac_nop_t nop; + tbd_t tbd; + int clen = length; + unsigned long flags; + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, + length); +#endif + + /* Do we need some padding? */ + if (clen < ETH_ZLEN) + clen = ETH_ZLEN; + + wv_splhi(lp, &flags); + + /* Check nothing bad has happened */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { +#ifdef DEBUG_TX_ERROR + printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n", + dev->name); +#endif + wv_splx(lp, &flags); + return 1; + } + + /* Calculate addresses of next block and previous block. */ + txblock = lp->tx_first_free; + txpred = txblock - TXBLOCKZ; + if (txpred < OFFSET_CU) + txpred += NTXBLOCKS * TXBLOCKZ; + lp->tx_first_free += TXBLOCKZ; + if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) + lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; + + lp->tx_n_in_use++; + + /* Calculate addresses of the different parts of the block. */ + tx_addr = txblock; + nop_addr = tx_addr + sizeof(tx); + tbd_addr = nop_addr + sizeof(nop); + buf_addr = tbd_addr + sizeof(tbd); + + /* + * Transmit command + */ + tx.tx_h.ac_status = 0; + obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), + (unsigned char *) &tx.tx_h.ac_status, + sizeof(tx.tx_h.ac_status)); + + /* + * NOP command + */ + nop.nop_h.ac_status = 0; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), + (unsigned char *) &nop.nop_h.ac_status, + sizeof(nop.nop_h.ac_status)); + nop.nop_h.ac_link = nop_addr; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), + (unsigned char *) &nop.nop_h.ac_link, + sizeof(nop.nop_h.ac_link)); + + /* + * Transmit buffer descriptor + */ + tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen); + tbd.tbd_next_bd_offset = I82586NULL; + tbd.tbd_bufl = buf_addr; + tbd.tbd_bufh = 0; + obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd)); + + /* + * Data + */ + obram_write(ioaddr, buf_addr, buf, length); + + /* + * Overwrite the predecessor NOP link + * so that it points to this txblock. + */ + nop_addr = txpred + sizeof(tx); + nop.nop_h.ac_status = 0; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), + (unsigned char *) &nop.nop_h.ac_status, + sizeof(nop.nop_h.ac_status)); + nop.nop_h.ac_link = txblock; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), + (unsigned char *) &nop.nop_h.ac_link, + sizeof(nop.nop_h.ac_link)); + + /* Keep stats up to date. */ + lp->stats.tx_bytes += length; + + if (lp->tx_first_in_use == I82586NULL) + lp->tx_first_in_use = txblock; + + if (lp->tx_n_in_use < NTXBLOCKS - 1) + netif_wake_queue(dev); + + wv_splx(lp, &flags); + +#ifdef DEBUG_TX_INFO + wv_packet_info((u8 *) buf, length, dev->name, + "wv_packet_write"); +#endif /* DEBUG_TX_INFO */ + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); +#endif + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * This routine is called when we want to send a packet (NET3 callback) + * In this routine, we check if the harware is ready to accept + * the packet. We also prevent reentrance. Then we call the function + * to send the packet. + */ +static int wavelan_packet_xmit(struct sk_buff *skb, device * dev) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long flags; + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, + (unsigned) skb); +#endif + + /* + * Block a timer-based transmit from overlapping. + * In other words, prevent reentering this routine. + */ + netif_stop_queue(dev); + + /* If somebody has asked to reconfigure the controller, + * we can do it now. + */ + if (lp->reconfig_82586) { + wv_splhi(lp, &flags); + wv_82586_config(dev); + wv_splx(lp, &flags); + /* Check that we can continue */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) + return 1; + } +#ifdef DEBUG_TX_ERROR + if (skb->next) + printk(KERN_INFO "skb has next\n"); +#endif + + /* Write packet on the card */ + if(wv_packet_write(dev, skb->data, skb->len)) + return 1; /* We failed */ + + dev_kfree_skb(skb); + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); +#endif + return 0; +} + +/*********************** HARDWARE CONFIGURATION ***********************/ +/* + * This part does the real job of starting and configuring the hardware. + */ + +/*--------------------------------------------------------------------*/ +/* + * Routine to initialize the Modem Management Controller. + * (called by wv_hw_reset()) + */ +static inline int wv_mmc_init(device * dev) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; + psa_t psa; + mmw_t m; + int configured; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); +#endif + + /* Read the parameter storage area. */ + psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); + +#ifdef USE_PSA_CONFIG + configured = psa.psa_conf_status & 1; +#else + configured = 0; +#endif + + /* Is the PSA is not configured */ + if (!configured) { + /* User will be able to configure NWID later (with iwconfig). */ + psa.psa_nwid[0] = 0; + psa.psa_nwid[1] = 0; + + /* no NWID checking since NWID is not set */ + psa.psa_nwid_select = 0; + + /* Disable encryption */ + psa.psa_encryption_select = 0; + + /* Set to standard values: + * 0x04 for AT, + * 0x01 for MCA, + * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) + */ + if (psa.psa_comp_number & 1) + psa.psa_thr_pre_set = 0x01; + else + psa.psa_thr_pre_set = 0x04; + psa.psa_quality_thr = 0x03; + + /* It is configured */ + psa.psa_conf_status |= 1; + +#ifdef USE_PSA_CONFIG + /* Write the psa. */ + psa_write(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 4); + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_conf_status - (char *) &psa, + (unsigned char *) &psa.psa_conf_status, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); +#endif + } + + /* Zero the mmc structure. */ + memset(&m, 0x00, sizeof(m)); + + /* Copy PSA info to the mmc. */ + m.mmw_netw_id_l = psa.psa_nwid[1]; + m.mmw_netw_id_h = psa.psa_nwid[0]; + + if (psa.psa_nwid_select & 1) + m.mmw_loopt_sel = 0x00; + else + m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; + + memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, + sizeof(m.mmw_encr_key)); + + if (psa.psa_encryption_select) + m.mmw_encr_enable = + MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; + else + m.mmw_encr_enable = 0; + + m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; + m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; + + /* + * Set default modem control parameters. + * See NCR document 407-0024326 Rev. A. + */ + m.mmw_jabber_enable = 0x01; + m.mmw_freeze = 0; + m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; + m.mmw_ifs = 0x20; + m.mmw_mod_delay = 0x04; + m.mmw_jam_time = 0x38; + + m.mmw_des_io_invert = 0; + m.mmw_decay_prm = 0; + m.mmw_decay_updat_prm = 0; + + /* Write all info to MMC. */ + mmc_write(ioaddr, 0, (u8 *) & m, sizeof(m)); + + /* The following code starts the modem of the 2.00 frequency + * selectable cards at power on. It's not strictly needed for the + * following boots. + * The original patch was by Joe Finney for the PCMCIA driver, but + * I've cleaned it up a bit and added documentation. + * Thanks to Loeke Brederveld from Lucent for the info. + */ + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) + * Does it work for everybody, especially old cards? */ + /* Note: WFREQSEL verifies that it is able to read a sensible + * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID + * is 0xA (Xilinx version) or 0xB (Ariadne version). + * My test is more crude but does work. */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + /* We must download the frequency parameters to the + * synthesizers (from the EEPROM - area 1) + * Note: as the EEPROM is automatically decremented, we set the end + * if the area... */ + m.mmw_fee_addr = 0x0F; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m, + (unsigned char *) &m.mmw_fee_ctrl, 2); + + /* Wait until the download is finished. */ + fee_wait(ioaddr, 100, 100); + +#ifdef DEBUG_CONFIG_INFO + /* The frequency was in the last word downloaded. */ + mmc_read(ioaddr, (char *) &m.mmw_fee_data_l - (char *) &m, + (unsigned char *) &m.mmw_fee_data_l, 2); + + /* Print some info for the user. */ + printk(KERN_DEBUG + "%s: WaveLAN 2.00 recognised (frequency select). Current frequency = %ld\n", + dev->name, + ((m. + mmw_fee_data_h << 4) | (m.mmw_fee_data_l >> 4)) * + 5 / 2 + 24000L); +#endif + + /* We must now download the power adjust value (gain) to + * the synthesizers (from the EEPROM - area 7 - DAC). */ + m.mmw_fee_addr = 0x61; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m, + (unsigned char *) &m.mmw_fee_ctrl, 2); + + /* Wait until the download is finished. */ + } + /* if 2.00 card */ +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Construct the fd and rbd structures. + * Start the receive unit. + * (called by wv_hw_reset()) + */ +static inline int wv_ru_start(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 scb_cs; + fd_t fd; + rbd_t rbd; + u16 rx; + u16 rx_next; + int i; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); +#endif + + obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + if ((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY) + return 0; + + lp->rx_head = OFFSET_RU; + + for (i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next) { + rx_next = + (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ; + + fd.fd_status = 0; + fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0; + fd.fd_link_offset = rx_next; + fd.fd_rbd_offset = rx + sizeof(fd); + obram_write(ioaddr, rx, (unsigned char *) &fd, sizeof(fd)); + + rbd.rbd_status = 0; + rbd.rbd_next_rbd_offset = I82586NULL; + rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd); + rbd.rbd_bufh = 0; + rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ); + obram_write(ioaddr, rx + sizeof(fd), + (unsigned char *) &rbd, sizeof(rbd)); + + lp->rx_last = rx; + } + + obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset), + (unsigned char *) &lp->rx_head, sizeof(lp->rx_head)); + + scb_cs = SCB_CMD_RUC_GO; + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + + set_chan_attn(ioaddr, lp->hacr); + + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + if (scb_cs == 0) + break; + + udelay(10); + } + + if (i <= 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wavelan_ru_start(): board not accepting command.\n", + dev->name); +#endif + return -1; + } +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Initialise the transmit blocks. + * Start the command unit executing the NOP + * self-loop of the first transmit block. + * + * Here we create the list of send buffers used to transmit packets + * between the PC and the command unit. For each buffer, we create a + * buffer descriptor (pointing on the buffer), a transmit command + * (pointing to the buffer descriptor) and a NOP command. + * The transmit command is linked to the NOP, and the NOP to itself. + * When we will have finished executing the transmit command, we will + * then loop on the NOP. By releasing the NOP link to a new command, + * we may send another buffer. + * + * (called by wv_hw_reset()) + */ +static inline int wv_cu_start(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + int i; + u16 txblock; + u16 first_nop; + u16 scb_cs; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name); +#endif + + lp->tx_first_free = OFFSET_CU; + lp->tx_first_in_use = I82586NULL; + + for (i = 0, txblock = OFFSET_CU; + i < NTXBLOCKS; i++, txblock += TXBLOCKZ) { + ac_tx_t tx; + ac_nop_t nop; + tbd_t tbd; + unsigned short tx_addr; + unsigned short nop_addr; + unsigned short tbd_addr; + unsigned short buf_addr; + + tx_addr = txblock; + nop_addr = tx_addr + sizeof(tx); + tbd_addr = nop_addr + sizeof(nop); + buf_addr = tbd_addr + sizeof(tbd); + + tx.tx_h.ac_status = 0; + tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I; + tx.tx_h.ac_link = nop_addr; + tx.tx_tbd_offset = tbd_addr; + obram_write(ioaddr, tx_addr, (unsigned char *) &tx, + sizeof(tx)); + + nop.nop_h.ac_status = 0; + nop.nop_h.ac_command = acmd_nop; + nop.nop_h.ac_link = nop_addr; + obram_write(ioaddr, nop_addr, (unsigned char *) &nop, + sizeof(nop)); + + tbd.tbd_status = TBD_STATUS_EOF; + tbd.tbd_next_bd_offset = I82586NULL; + tbd.tbd_bufl = buf_addr; + tbd.tbd_bufh = 0; + obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, + sizeof(tbd)); + } + + first_nop = + OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t); + obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset), + (unsigned char *) &first_nop, sizeof(first_nop)); + + scb_cs = SCB_CMD_CUC_GO; + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + + set_chan_attn(ioaddr, lp->hacr); + + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + if (scb_cs == 0) + break; + + udelay(10); + } + + if (i <= 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wavelan_cu_start(): board not accepting command.\n", + dev->name); +#endif + return -1; + } + + lp->tx_n_in_use = 0; + netif_start_queue(dev); +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * This routine does a standard configuration of the WaveLAN + * controller (i82586). + * + * It initialises the scp, iscp and scb structure + * The first two are just pointers to the next. + * The last one is used for basic configuration and for basic + * communication (interrupt status). + * + * (called by wv_hw_reset()) + */ +static inline int wv_82586_start(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + scp_t scp; /* system configuration pointer */ + iscp_t iscp; /* intermediate scp */ + scb_t scb; /* system control block */ + ach_t cb; /* Action command header */ + u8 zeroes[512]; + int i; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name); +#endif + + /* + * Clear the onboard RAM. + */ + memset(&zeroes[0], 0x00, sizeof(zeroes)); + for (i = 0; i < I82586_MEMZ; i += sizeof(zeroes)) + obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes)); + + /* + * Construct the command unit structures: + * scp, iscp, scb, cb. + */ + memset(&scp, 0x00, sizeof(scp)); + scp.scp_sysbus = SCP_SY_16BBUS; + scp.scp_iscpl = OFFSET_ISCP; + obram_write(ioaddr, OFFSET_SCP, (unsigned char *) &scp, + sizeof(scp)); + + memset(&iscp, 0x00, sizeof(iscp)); + iscp.iscp_busy = 1; + iscp.iscp_offset = OFFSET_SCB; + obram_write(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, + sizeof(iscp)); + + /* Our first command is to reset the i82586. */ + memset(&scb, 0x00, sizeof(scb)); + scb.scb_command = SCB_CMD_RESET; + scb.scb_cbl_offset = OFFSET_CU; + scb.scb_rfa_offset = OFFSET_RU; + obram_write(ioaddr, OFFSET_SCB, (unsigned char *) &scb, + sizeof(scb)); + + set_chan_attn(ioaddr, lp->hacr); + + /* Wait for command to finish. */ + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, + sizeof(iscp)); + + if (iscp.iscp_busy == (unsigned short) 0) + break; + + udelay(10); + } + + if (i <= 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wv_82586_start(): iscp_busy timeout.\n", + dev->name); +#endif + return -1; + } + + /* Check command completion. */ + for (i = 15; i > 0; i--) { + obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, + sizeof(scb)); + + if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA)) + break; + + udelay(10); + } + + if (i <= 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n", + dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status); +#endif + return -1; + } + + wv_ack(dev); + + /* Set the action command header. */ + memset(&cb, 0x00, sizeof(cb)); + cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose); + cb.ac_link = OFFSET_CU; + obram_write(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb)); + + if (wv_synchronous_cmd(dev, "diag()") == -1) + return -1; + + obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb)); + if (cb.ac_status & AC_SFLD_FAIL) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wv_82586_start(): i82586 Self Test failed.\n", + dev->name); +#endif + return -1; + } +#ifdef DEBUG_I82586_SHOW + wv_scb_show(ioaddr); +#endif + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * This routine does a standard configuration of the WaveLAN + * controller (i82586). + * + * This routine is a violent hack. We use the first free transmit block + * to make our configuration. In the buffer area, we create the three + * configuration commands (linked). We make the previous NOP point to + * the beginning of the buffer instead of the tx command. After, we go + * as usual to the NOP command. + * Note that only the last command (mc_set) will generate an interrupt. + * + * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit()) + */ +static void wv_82586_config(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + unsigned short txblock; + unsigned short txpred; + unsigned short tx_addr; + unsigned short nop_addr; + unsigned short tbd_addr; + unsigned short cfg_addr; + unsigned short ias_addr; + unsigned short mcs_addr; + ac_tx_t tx; + ac_nop_t nop; + ac_cfg_t cfg; /* Configure action */ + ac_ias_t ias; /* IA-setup action */ + ac_mcs_t mcs; /* Multicast setup */ + struct dev_mc_list *dmi; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name); +#endif + + /* Check nothing bad has happened */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO "%s: wv_82586_config(): Tx queue full.\n", + dev->name); +#endif + return; + } + + /* Calculate addresses of next block and previous block. */ + txblock = lp->tx_first_free; + txpred = txblock - TXBLOCKZ; + if (txpred < OFFSET_CU) + txpred += NTXBLOCKS * TXBLOCKZ; + lp->tx_first_free += TXBLOCKZ; + if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) + lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; + + lp->tx_n_in_use++; + + /* Calculate addresses of the different parts of the block. */ + tx_addr = txblock; + nop_addr = tx_addr + sizeof(tx); + tbd_addr = nop_addr + sizeof(nop); + cfg_addr = tbd_addr + sizeof(tbd_t); /* beginning of the buffer */ + ias_addr = cfg_addr + sizeof(cfg); + mcs_addr = ias_addr + sizeof(ias); + + /* + * Transmit command + */ + tx.tx_h.ac_status = 0xFFFF; /* Fake completion value */ + obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), + (unsigned char *) &tx.tx_h.ac_status, + sizeof(tx.tx_h.ac_status)); + + /* + * NOP command + */ + nop.nop_h.ac_status = 0; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), + (unsigned char *) &nop.nop_h.ac_status, + sizeof(nop.nop_h.ac_status)); + nop.nop_h.ac_link = nop_addr; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), + (unsigned char *) &nop.nop_h.ac_link, + sizeof(nop.nop_h.ac_link)); + + /* Create a configure action. */ + memset(&cfg, 0x00, sizeof(cfg)); + + /* + * For Linux we invert AC_CFG_ALOC() so as to conform + * to the way that net packets reach us from above. + * (See also ac_tx_t.) + * + * Updated from Wavelan Manual WCIN085B + */ + cfg.cfg_byte_cnt = + AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t)); + cfg.cfg_fifolim = AC_CFG_FIFOLIM(4); + cfg.cfg_byte8 = AC_CFG_SAV_BF(1) | AC_CFG_SRDY(0); + cfg.cfg_byte9 = AC_CFG_ELPBCK(0) | + AC_CFG_ILPBCK(0) | + AC_CFG_PRELEN(AC_CFG_PLEN_2) | + AC_CFG_ALOC(1) | AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE); + cfg.cfg_byte10 = AC_CFG_BOFMET(1) | + AC_CFG_ACR(6) | AC_CFG_LINPRIO(0); + cfg.cfg_ifs = 0x20; + cfg.cfg_slotl = 0x0C; + cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | AC_CFG_SLTTMHI(0); + cfg.cfg_byte14 = AC_CFG_FLGPAD(0) | + AC_CFG_BTSTF(0) | + AC_CFG_CRC16(0) | + AC_CFG_NCRC(0) | + AC_CFG_TNCRS(1) | + AC_CFG_MANCH(0) | + AC_CFG_BCDIS(0) | AC_CFG_PRM(lp->promiscuous); + cfg.cfg_byte15 = AC_CFG_ICDS(0) | + AC_CFG_CDTF(0) | AC_CFG_ICSS(0) | AC_CFG_CSTF(0); +/* + cfg.cfg_min_frm_len = AC_CFG_MNFRM(64); +*/ + cfg.cfg_min_frm_len = AC_CFG_MNFRM(8); + + cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure); + cfg.cfg_h.ac_link = ias_addr; + obram_write(ioaddr, cfg_addr, (unsigned char *) &cfg, sizeof(cfg)); + + /* Set up the MAC address */ + memset(&ias, 0x00, sizeof(ias)); + ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup); + ias.ias_h.ac_link = mcs_addr; + memcpy(&ias.ias_addr[0], (unsigned char *) &dev->dev_addr[0], + sizeof(ias.ias_addr)); + obram_write(ioaddr, ias_addr, (unsigned char *) &ias, sizeof(ias)); + + /* Initialize adapter's Ethernet multicast addresses */ + memset(&mcs, 0x00, sizeof(mcs)); + mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup); + mcs.mcs_h.ac_link = nop_addr; + mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count; + obram_write(ioaddr, mcs_addr, (unsigned char *) &mcs, sizeof(mcs)); + + /* Any address to set? */ + if (lp->mc_count) { + for (dmi = dev->mc_list; dmi; dmi = dmi->next) + outsw(PIOP1(ioaddr), (u16 *) dmi->dmi_addr, + WAVELAN_ADDR_SIZE >> 1); + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG + "%s: wv_82586_config(): set %d multicast addresses:\n", + dev->name, lp->mc_count); + for (dmi = dev->mc_list; dmi; dmi = dmi->next) + printk(KERN_DEBUG + " %02x:%02x:%02x:%02x:%02x:%02x\n", + dmi->dmi_addr[0], dmi->dmi_addr[1], + dmi->dmi_addr[2], dmi->dmi_addr[3], + dmi->dmi_addr[4], dmi->dmi_addr[5]); +#endif + } + + /* + * Overwrite the predecessor NOP link + * so that it points to the configure action. + */ + nop_addr = txpred + sizeof(tx); + nop.nop_h.ac_status = 0; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), + (unsigned char *) &nop.nop_h.ac_status, + sizeof(nop.nop_h.ac_status)); + nop.nop_h.ac_link = cfg_addr; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), + (unsigned char *) &nop.nop_h.ac_link, + sizeof(nop.nop_h.ac_link)); + + /* Job done, clear the flag */ + lp->reconfig_82586 = 0; + + if (lp->tx_first_in_use == I82586NULL) + lp->tx_first_in_use = txblock; + + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) + netif_stop_queue(dev); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * This routine, called by wavelan_close(), gracefully stops the + * WaveLAN controller (i82586). + * (called by wavelan_close()) + */ +static inline void wv_82586_stop(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 scb_cmd; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name); +#endif + + /* Suspend both command unit and receive unit. */ + scb_cmd = + (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & + SCB_CMD_RUC_SUS); + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cmd, sizeof(scb_cmd)); + set_chan_attn(ioaddr, lp->hacr); + + /* No more interrupts */ + wv_ints_off(dev); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * Totally reset the WaveLAN and restart it. + * Performs the following actions: + * 1. A power reset (reset DMA) + * 2. Initialize the radio modem (using wv_mmc_init) + * 3. Reset & Configure LAN controller (using wv_82586_start) + * 4. Start the LAN controller's command unit + * 5. Start the LAN controller's receive unit + * (called by wavelan_interrupt(), wavelan_watchdog() & wavelan_open()) + */ +static int wv_hw_reset(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + /* Increase the number of resets done. */ + lp->nresets++; + + wv_hacr_reset(ioaddr); + lp->hacr = HACR_DEFAULT; + + if ((wv_mmc_init(dev) < 0) || (wv_82586_start(dev) < 0)) + return -1; + + /* Enable the card to send interrupts. */ + wv_ints_on(dev); + + /* Start card functions */ + if (wv_cu_start(dev) < 0) + return -1; + + /* Setup the controller and parameters */ + wv_82586_config(dev); + + /* Finish configuration with the receive unit */ + if (wv_ru_start(dev) < 0) + return -1; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Check if there is a WaveLAN at the specific base address. + * As a side effect, this reads the MAC address. + * (called in wavelan_probe() and init_module()) + */ +static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac) +{ + int i; /* Loop counter */ + + /* Check if the base address if available. */ + if (check_region(ioaddr, sizeof(ha_t))) + return -EADDRINUSE; /* ioaddr already used */ + + /* Reset host interface */ + wv_hacr_reset(ioaddr); + + /* Read the MAC address from the parameter storage area. */ + psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr), + mac, 6); + + /* + * Check the first three octets of the address for the manufacturer's code. + * Note: if this can't find your WaveLAN card, you've got a + * non-NCR/AT&T/Lucent ISA card. See wavelan.p.h for detail on + * how to configure your card. + */ + for (i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++) + if ((mac[0] == MAC_ADDRESSES[i][0]) && + (mac[1] == MAC_ADDRESSES[i][1]) && + (mac[2] == MAC_ADDRESSES[i][2])) + return 0; + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_WARNING + "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n", + ioaddr, mac[0], mac[1], mac[2]); +#endif + return -ENODEV; +} + +/************************ INTERRUPT HANDLING ************************/ + +/* + * This function is the interrupt handler for the WaveLAN card. This + * routine will be called whenever: + */ +static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + device *dev; + unsigned long ioaddr; + net_local *lp; + u16 hasr; + u16 status; + u16 ack_cmd; + + dev = dev_id; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); +#endif + + lp = (net_local *) dev->priv; + ioaddr = dev->base_addr; + +#ifdef DEBUG_INTERRUPT_INFO + /* Check state of our spinlock */ + if(spin_is_locked(&lp->spinlock)) + printk(KERN_DEBUG + "%s: wavelan_interrupt(): spinlock is already locked !!!\n", + dev->name); +#endif + + /* Prevent reentrancy. We need to do that because we may have + * multiple interrupt handler running concurrently. + * It is safe because wv_splhi() disables interrupts before acquiring + * the spinlock. */ + spin_lock(&lp->spinlock); + + /* Check modem interrupt */ + if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) { + u8 dce_status; + + /* + * Interrupt from the modem management controller. + * This will clear it -- ignored for now. + */ + mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, + sizeof(dce_status)); +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO + "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", + dev->name, dce_status); +#endif + } + + /* Check if not controller interrupt */ + if ((hasr & HASR_82586_INTR) == 0) { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO + "%s: wavelan_interrupt(): interrupt not coming from i82586\n", + dev->name); +#endif + spin_unlock (&lp->spinlock); + return; + } + + /* Read interrupt data. */ + obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), + (unsigned char *) &status, sizeof(status)); + + /* + * Acknowledge the interrupt(s). + */ + ack_cmd = status & SCB_ST_INT; + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &ack_cmd, sizeof(ack_cmd)); + set_chan_attn(ioaddr, lp->hacr); + +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n", + dev->name, status); +#endif + + /* Command completed. */ + if ((status & SCB_ST_CX) == SCB_ST_CX) { +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG + "%s: wavelan_interrupt(): command completed.\n", + dev->name); +#endif + wv_complete(dev, ioaddr, lp); + } + + /* Frame received. */ + if ((status & SCB_ST_FR) == SCB_ST_FR) { +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG + "%s: wavelan_interrupt(): received packet.\n", + dev->name); +#endif + wv_receive(dev); + } + + /* Check the state of the command unit. */ + if (((status & SCB_ST_CNA) == SCB_ST_CNA) || + (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && + (netif_running(dev)))) { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO + "%s: wavelan_interrupt(): CU inactive -- restarting\n", + dev->name); +#endif + wv_hw_reset(dev); + } + + /* Check the state of the command unit. */ + if (((status & SCB_ST_RNR) == SCB_ST_RNR) || + (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && + (netif_running(dev)))) { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO + "%s: wavelan_interrupt(): RU not ready -- restarting\n", + dev->name); +#endif + wv_hw_reset(dev); + } + + /* Release spinlock */ + spin_unlock (&lp->spinlock); + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * Watchdog: when we start a transmission, a timer is set for us in the + * kernel. If the transmission completes, this timer is disabled. If + * the timer expires, we are called and we try to unlock the hardware. + */ +static void wavelan_watchdog(device * dev) +{ + net_local * lp = (net_local *)dev->priv; + u_long ioaddr = dev->base_addr; + unsigned long flags; + unsigned int nreaped; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); +#endif + +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", + dev->name); +#endif + + /* Check that we came here for something */ + if (lp->tx_n_in_use <= 0) { + return; + } + + wv_splhi(lp, &flags); + + /* Try to see if some buffers are not free (in case we missed + * an interrupt */ + nreaped = wv_complete(dev, ioaddr, lp); + +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG + "%s: wavelan_watchdog(): %d reaped, %d remain.\n", + dev->name, nreaped, lp->tx_n_in_use); +#endif + +#ifdef DEBUG_PSA_SHOW + { + psa_t psa; + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + wv_psa_show(&psa); + } +#endif +#ifdef DEBUG_MMC_SHOW + wv_mmc_show(dev); +#endif +#ifdef DEBUG_I82586_SHOW + wv_cu_show(dev); +#endif + + /* If no buffer has been freed */ + if (nreaped == 0) { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO + "%s: wavelan_watchdog(): cleanup failed, trying reset\n", + dev->name); +#endif + wv_hw_reset(dev); + } + + /* At this point, we should have some free Tx buffer ;-) */ + if (lp->tx_n_in_use < NTXBLOCKS - 1) + netif_wake_queue(dev); + + wv_splx(lp, &flags); + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); +#endif +} + +/********************* CONFIGURATION CALLBACKS *********************/ +/* + * Here are the functions called by the Linux networking code (NET3) + * for initialization, configuration and deinstallations of the + * WaveLAN ISA hardware. + */ + +/*------------------------------------------------------------------*/ +/* + * Configure and start up the WaveLAN PCMCIA adaptor. + * Called by NET3 when it "opens" the device. + */ +static int wavelan_open(device * dev) +{ + net_local * lp = (net_local *)dev->priv; + unsigned long flags; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + /* Check irq */ + if (dev->irq == 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", + dev->name); +#endif + return -ENXIO; + } + + if (request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0) + { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", + dev->name); +#endif + return -EAGAIN; + } + + wv_splhi(lp, &flags); + + if (wv_hw_reset(dev) != -1) { + netif_start_queue(dev); + } else { + free_irq(dev->irq, dev); +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wavelan_open(): impossible to start the card\n", + dev->name); +#endif + wv_splx(lp, &flags); + return -EAGAIN; + } + wv_splx(lp, &flags); + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Shut down the WaveLAN ISA card. + * Called by NET3 when it "closes" the device. + */ +static int wavelan_close(device * dev) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long flags; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + netif_stop_queue(dev); + + /* + * Flush the Tx and disable Rx. + */ + wv_splhi(lp, &flags); + wv_82586_stop(dev); + wv_splx(lp, &flags); + + free_irq(dev->irq, dev); + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Probe an I/O address, and if the WaveLAN is there configure the + * device structure + * (called by wavelan_probe() and via init_module()). + */ +static int __init wavelan_config(device * dev) +{ + unsigned long ioaddr = dev->base_addr; + u8 irq_mask; + int irq; + net_local *lp; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%lx)\n", + dev->name, (unsigned int) dev, ioaddr); +#endif + + /* Check IRQ argument on command line. */ + if (dev->irq != 0) { + irq_mask = wv_irq_to_psa(dev->irq); + + if (irq_mask == 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_WARNING + "%s: wavelan_config(): invalid IRQ %d ignored.\n", + dev->name, dev->irq); +#endif + dev->irq = 0; + } else { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG + "%s: wavelan_config(): changing IRQ to %d\n", + dev->name, dev->irq); +#endif + psa_write(ioaddr, HACR_DEFAULT, + psaoff(0, psa_int_req_no), &irq_mask, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, HACR_DEFAULT); + wv_hacr_reset(ioaddr); + } + } + + psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no), + &irq_mask, 1); + if ((irq = wv_psa_to_irq(irq_mask)) == -1) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wavelan_config(): could not wavelan_map_irq(%d).\n", + dev->name, irq_mask); +#endif + return -EAGAIN; + } + + dev->irq = irq; + + if (!request_region(ioaddr, sizeof(ha_t), "wavelan")) + return -EBUSY; + + dev->mem_start = 0x0000; + dev->mem_end = 0x0000; + dev->if_port = 0; + + /* Initialize device structures */ + dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL); + if (dev->priv == NULL) { + release_region(ioaddr, sizeof(ha_t)); + return -ENOMEM; + } + memset(dev->priv, 0x00, sizeof(net_local)); + lp = (net_local *) dev->priv; + + /* Back link to the device structure. */ + lp->dev = dev; + /* Add the device at the beginning of the linked list. */ + lp->next = wavelan_list; + wavelan_list = lp; + + lp->hacr = HACR_DEFAULT; + + /* Multicast stuff */ + lp->promiscuous = 0; + lp->mc_count = 0; + + /* Init spinlock */ + spin_lock_init(&lp->spinlock); + + /* + * Fill in the fields of the device structure + * with generic Ethernet values. + */ + ether_setup(dev); + + SET_MODULE_OWNER(dev); + dev->open = wavelan_open; + dev->stop = wavelan_close; + dev->hard_start_xmit = wavelan_packet_xmit; + dev->get_stats = wavelan_get_stats; + dev->set_multicast_list = &wavelan_set_multicast_list; + dev->tx_timeout = &wavelan_watchdog; + dev->watchdog_timeo = WATCHDOG_JIFFIES; +#ifdef SET_MAC_ADDRESS + dev->set_mac_address = &wavelan_set_mac_address; +#endif /* SET_MAC_ADDRESS */ + +#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ + dev->do_ioctl = wavelan_ioctl; + dev->get_wireless_stats = wavelan_get_wireless_stats; +#endif + + dev->mtu = WAVELAN_MTU; + + /* Display nice information. */ + wv_init_info(dev); + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Check for a network adaptor of this type. Return '0' iff one + * exists. There seem to be different interpretations of + * the initial value of dev->base_addr. + * We follow the example in drivers/net/ne.c. + * (called in "Space.c") + */ +int __init wavelan_probe(device * dev) +{ + short base_addr; + mac_addr mac; /* MAC address (check existence of WaveLAN) */ + int i; + int r; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG + "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n", + dev->name, (unsigned int) dev, + (unsigned int) dev->base_addr); +#endif + +#ifdef STRUCT_CHECK + if (wv_struct_check() != (char *) NULL) { + printk(KERN_WARNING + "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n", + dev->name, wv_struct_check()); + return -ENODEV; + } +#endif /* STRUCT_CHECK */ + + /* Check the value of the command line parameter for base address. */ + base_addr = dev->base_addr; + + /* Don't probe at all. */ + if (base_addr < 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_WARNING + "%s: wavelan_probe(): invalid base address\n", + dev->name); +#endif + return -ENXIO; + } + + /* Check a single specified location. */ + if (base_addr > 0x100) { + /* Check if there is something at this base address */ + if ((r = wv_check_ioaddr(base_addr, mac)) == 0) { + memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ + r = wavelan_config(dev); + } +#ifdef DEBUG_CONFIG_INFO + if (r != 0) + printk(KERN_DEBUG + "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n", + dev->name, base_addr); +#endif + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); +#endif + return r; + } + + /* Scan all possible addresses of the WaveLAN hardware. */ + for (i = 0; i < NELS(iobase); i++) { + /* Check whether there is something at this base address. */ + if (wv_check_ioaddr(iobase[i], mac) == 0) { + dev->base_addr = iobase[i]; /* Copy base address. */ + memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ + if (wavelan_config(dev) == 0) { +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG + "%s: <-wavelan_probe()\n", + dev->name); +#endif + return 0; + } + } + } + + /* We may have touched base_addr. Another driver may not like it. */ + dev->base_addr = base_addr; + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n", + dev->name); +#endif + + return -ENODEV; +} + +/****************************** MODULE ******************************/ +/* + * Module entry point: insertion and removal + */ + +#ifdef MODULE +/*------------------------------------------------------------------*/ +/* + * Insertion of the module + * I'm now quite proud of the multi-device support. + */ +int init_module(void) +{ + mac_addr mac; /* MAC address (check WaveLAN existence) */ + int ret = -EIO; /* Return error if no cards found */ + int i; + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "-> init_module()\n"); +#endif + + /* If probing is asked */ + if (io[0] == 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_WARNING + "WaveLAN init_module(): doing device probing (bad !)\n"); + printk(KERN_WARNING + "Specify base addresses while loading module to correct the problem\n"); +#endif + + /* Copy the basic set of address to be probed. */ + for (i = 0; i < NELS(iobase); i++) + io[i] = iobase[i]; + } + + + /* Loop on all possible base addresses. */ + i = -1; + while ((io[++i] != 0) && (i < NELS(io))) { + /* Check if there is something at this base address. */ + if (wv_check_ioaddr(io[i], mac) == 0) { + device *dev; + + /* Create device and set basic arguments. */ + dev = + kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (dev == NULL) { + ret = -ENOMEM; + break; + } + memset(dev, 0x00, sizeof(struct net_device)); + memcpy(dev->name, name[i], IFNAMSIZ); /* Copy name */ + dev->base_addr = io[i]; + dev->irq = irq[i]; + dev->init = &wavelan_config; + memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ + + /* Try to create the device. */ + if (register_netdev(dev) != 0) { + /* Deallocate everything. */ + /* Note: if dev->priv is mallocated, there is no way to fail. */ + kfree(dev); + } else { + /* If at least one device OK, we do not fail */ + ret = 0; + } + } /* if there is something at the address */ + } /* Loop on all addresses. */ + +#ifdef DEBUG_CONFIG_ERROR + if (wavelan_list == (net_local *) NULL) + printk(KERN_WARNING + "WaveLAN init_module(): no device found\n"); +#endif + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "<- init_module()\n"); +#endif + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Removal of the module + */ +void cleanup_module(void) +{ +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "-> cleanup_module()\n"); +#endif + + /* Loop on all devices and release them. */ + while (wavelan_list != (net_local *) NULL) { + device *dev = wavelan_list->dev; + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG + "%s: cleanup_module(): removing device at 0x%x\n", + dev->name, (unsigned int) dev); +#endif + + /* Release the ioport region. */ + release_region(dev->base_addr, sizeof(ha_t)); + + /* Definitely remove the device. */ + unregister_netdev(dev); + + /* Unlink the device. */ + wavelan_list = wavelan_list->next; + + /* Free pieces. */ + kfree(dev->priv); + kfree(dev); + } + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "<- cleanup_module()\n"); +#endif +} +#endif /* MODULE */ +MODULE_LICENSE("GPL"); + +/* + * This software may only be used and distributed + * according to the terms of the GNU General Public License. + * + * This software was developed as a component of the + * Linux operating system. + * It is based on other device drivers and information + * either written or supplied by: + * Ajay Bakre (bakre@paul.rutgers.edu), + * Donald Becker (becker@scyld.com), + * Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com), + * Anders Klemets (klemets@it.kth.se), + * Vladimir V. Kolpakov (w@stier.koenig.ru), + * Marc Meertens (Marc.Meertens@Utrecht.NCR.com), + * Pauline Middelink (middelin@polyware.iaf.nl), + * Robert Morris (rtm@das.harvard.edu), + * Jean Tourrilhes (jt@hplb.hpl.hp.com), + * Girish Welling (welling@paul.rutgers.edu), + * + * Thanks go also to: + * James Ashton (jaa101@syseng.anu.edu.au), + * Alan Cox (alan@redhat.com), + * Allan Creighton (allanc@cs.usyd.edu.au), + * Matthew Geier (matthew@cs.usyd.edu.au), + * Remo di Giovanni (remo@cs.usyd.edu.au), + * Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de), + * Vipul Gupta (vgupta@cs.binghamton.edu), + * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), + * Tim Nicholson (tim@cs.usyd.edu.au), + * Ian Parkin (ian@cs.usyd.edu.au), + * John Rosenberg (johnr@cs.usyd.edu.au), + * George Rossi (george@phm.gov.au), + * Arthur Scott (arthur@cs.usyd.edu.au), + * Peter Storey, + * for their assistance and advice. + * + * Please send bug reports, updates, comments to: + * + * Bruce Janson Email: bruce@cs.usyd.edu.au + * Basser Department of Computer Science Phone: +61-2-9351-3423 + * University of Sydney, N.S.W., 2006, AUSTRALIA Fax: +61-2-9351-3838 + */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wavelan.h linux-2.5/drivers/net/wavelan.h --- linux-2.5.5/drivers/net/wavelan.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/wavelan.h Tue Jan 22 17:43:48 2002 @@ -0,0 +1,370 @@ +/* + * WaveLAN ISA driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * Original copyright follows. See wavelan.p.h for details. + * + * This file contains the declarations for the WaveLAN hardware. Note that + * the WaveLAN ISA includes a i82586 controller (see definitions in + * file i82586.h). + * + * The main difference between the ISA hardware and the PCMCIA one is + * the Ethernet controller (i82586 instead of i82593). + * The i82586 allows multiple transmit buffers. The PSA needs to be accessed + * through the host interface. + */ + +#ifndef _WAVELAN_H +#define _WAVELAN_H + +/************************** MAGIC NUMBERS ***************************/ + +/* Detection of the WaveLAN card is done by reading the MAC + * address from the card and checking it. If you have a non-AT&T + * product (OEM, like DEC RoamAbout, Digital Ocean, or Epson), + * you might need to modify this part to accommodate your hardware. + */ +static const char MAC_ADDRESSES[][3] = +{ + { 0x08, 0x00, 0x0E }, /* AT&T WaveLAN (standard) & DEC RoamAbout */ + { 0x08, 0x00, 0x6A }, /* AT&T WaveLAN (alternate) */ + { 0x00, 0x00, 0xE1 }, /* Hitachi Wavelan */ + { 0x00, 0x60, 0x1D } /* Lucent Wavelan (another one) */ + /* Add your card here and send me the patch! */ +}; + +#define WAVELAN_ADDR_SIZE 6 /* Size of a MAC address */ + +#define WAVELAN_MTU 1500 /* Maximum size of WaveLAN packet */ + +#define MAXDATAZ (WAVELAN_ADDR_SIZE + WAVELAN_ADDR_SIZE + 2 + WAVELAN_MTU) + +/* + * Constants used to convert channels to frequencies + */ + +/* Frequency available in the 2.0 modem, in units of 250 kHz + * (as read in the offset register of the dac area). + * Used to map channel numbers used by `wfreqsel' to frequencies + */ +static const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, + 0xD0, 0xF0, 0xF8, 0x150 }; + +/* Frequencies of the 1.0 modem (fixed frequencies). + * Use to map the PSA `subband' to a frequency + * Note : all frequencies apart from the first one need to be multiplied by 10 + */ +static const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; + + + +/*************************** PC INTERFACE ****************************/ + +/* + * Host Adaptor structure. + * (base is board port address). + */ +typedef union hacs_u hacs_u; +union hacs_u +{ + unsigned short hu_command; /* Command register */ +#define HACR_RESET 0x0001 /* Reset board */ +#define HACR_CA 0x0002 /* Set Channel Attention for 82586 */ +#define HACR_16BITS 0x0004 /* 16-bit operation (0 => 8bits) */ +#define HACR_OUT0 0x0008 /* General purpose output pin 0 */ + /* not used - must be 1 */ +#define HACR_OUT1 0x0010 /* General purpose output pin 1 */ + /* not used - must be 1 */ +#define HACR_82586_INT_ENABLE 0x0020 /* Enable 82586 interrupts */ +#define HACR_MMC_INT_ENABLE 0x0040 /* Enable MMC interrupts */ +#define HACR_INTR_CLR_ENABLE 0x0080 /* Enable interrupt status read/clear */ + unsigned short hu_status; /* Status Register */ +#define HASR_82586_INTR 0x0001 /* Interrupt request from 82586 */ +#define HASR_MMC_INTR 0x0002 /* Interrupt request from MMC */ +#define HASR_MMC_BUSY 0x0004 /* MMC busy indication */ +#define HASR_PSA_BUSY 0x0008 /* LAN parameter storage area busy */ +}; + +typedef struct ha_t ha_t; +struct ha_t +{ + hacs_u ha_cs; /* Command and status registers */ +#define ha_command ha_cs.hu_command +#define ha_status ha_cs.hu_status + unsigned short ha_mmcr; /* Modem Management Ctrl Register */ + unsigned short ha_pior0; /* Program I/O Address Register Port 0 */ + unsigned short ha_piop0; /* Program I/O Port 0 */ + unsigned short ha_pior1; /* Program I/O Address Register Port 1 */ + unsigned short ha_piop1; /* Program I/O Port 1 */ + unsigned short ha_pior2; /* Program I/O Address Register Port 2 */ + unsigned short ha_piop2; /* Program I/O Port 2 */ +}; + +#define HA_SIZE 16 + +#define hoff(p,f) (unsigned short)((void *)(&((ha_t *)((void *)0 + (p)))->f) - (void *)0) +#define HACR(p) hoff(p, ha_command) +#define HASR(p) hoff(p, ha_status) +#define MMCR(p) hoff(p, ha_mmcr) +#define PIOR0(p) hoff(p, ha_pior0) +#define PIOP0(p) hoff(p, ha_piop0) +#define PIOR1(p) hoff(p, ha_pior1) +#define PIOP1(p) hoff(p, ha_piop1) +#define PIOR2(p) hoff(p, ha_pior2) +#define PIOP2(p) hoff(p, ha_piop2) + +/* + * Program I/O Mode Register values. + */ +#define STATIC_PIO 0 /* Mode 1: static mode */ + /* RAM access ??? */ +#define AUTOINCR_PIO 1 /* Mode 2: auto increment mode */ + /* RAM access ??? */ +#define AUTODECR_PIO 2 /* Mode 3: auto decrement mode */ + /* RAM access ??? */ +#define PARAM_ACCESS_PIO 3 /* Mode 4: LAN parameter access mode */ + /* Parameter access. */ +#define PIO_MASK 3 /* register mask */ +#define PIOM(cmd,piono) ((u_short)cmd << 10 << (piono * 2)) + +#define HACR_DEFAULT (HACR_OUT0 | HACR_OUT1 | HACR_16BITS | PIOM(STATIC_PIO, 0) | PIOM(AUTOINCR_PIO, 1) | PIOM(PARAM_ACCESS_PIO, 2)) +#define HACR_INTRON (HACR_82586_INT_ENABLE | HACR_MMC_INT_ENABLE | HACR_INTR_CLR_ENABLE) + +/************************** MEMORY LAYOUT **************************/ + +/* + * Onboard 64 k RAM layout. + * (Offsets from 0x0000.) + */ +#define OFFSET_RU 0x0000 /* 75% memory */ +#define OFFSET_CU 0xC000 /* 25% memory */ +#define OFFSET_SCB (OFFSET_ISCP - sizeof(scb_t)) +#define OFFSET_ISCP (OFFSET_SCP - sizeof(iscp_t)) +#define OFFSET_SCP I82586_SCP_ADDR + +#define RXBLOCKZ (sizeof(fd_t) + sizeof(rbd_t) + MAXDATAZ) +#define TXBLOCKZ (sizeof(ac_tx_t) + sizeof(ac_nop_t) + sizeof(tbd_t) + MAXDATAZ) + +#define NRXBLOCKS ((OFFSET_CU - OFFSET_RU) / RXBLOCKZ) +#define NTXBLOCKS ((OFFSET_SCB - OFFSET_CU) / TXBLOCKZ) + +/********************** PARAMETER STORAGE AREA **********************/ + +/* + * Parameter Storage Area (PSA). + */ +typedef struct psa_t psa_t; +struct psa_t +{ + unsigned char psa_io_base_addr_1; /* [0x00] Base address 1 ??? */ + unsigned char psa_io_base_addr_2; /* [0x01] Base address 2 */ + unsigned char psa_io_base_addr_3; /* [0x02] Base address 3 */ + unsigned char psa_io_base_addr_4; /* [0x03] Base address 4 */ + unsigned char psa_rem_boot_addr_1; /* [0x04] Remote Boot Address 1 */ + unsigned char psa_rem_boot_addr_2; /* [0x05] Remote Boot Address 2 */ + unsigned char psa_rem_boot_addr_3; /* [0x06] Remote Boot Address 3 */ + unsigned char psa_holi_params; /* [0x07] HOst Lan Interface (HOLI) Parameters */ + unsigned char psa_int_req_no; /* [0x08] Interrupt Request Line */ + unsigned char psa_unused0[7]; /* [0x09-0x0F] unused */ + + unsigned char psa_univ_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x10-0x15] Universal (factory) MAC Address */ + unsigned char psa_local_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x16-1B] Local MAC Address */ + unsigned char psa_univ_local_sel; /* [0x1C] Universal Local Selection */ +#define PSA_UNIVERSAL 0 /* Universal (factory) */ +#define PSA_LOCAL 1 /* Local */ + unsigned char psa_comp_number; /* [0x1D] Compatibility Number: */ +#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */ +#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */ +#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */ +#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */ +#define PSA_COMP_PCMCIA_915 4 /* PCMCIA 915 MHz or 2.0 */ + unsigned char psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */ + unsigned char psa_feature_select; /* [0x1F] Call code required (1=on) */ +#define PSA_FEATURE_CALL_CODE 0x01 /* Call code required (Japan) */ + unsigned char psa_subband; /* [0x20] Subband */ +#define PSA_SUBBAND_915 0 /* 915 MHz or 2.0 */ +#define PSA_SUBBAND_2425 1 /* 2425 MHz */ +#define PSA_SUBBAND_2460 2 /* 2460 MHz */ +#define PSA_SUBBAND_2484 3 /* 2484 MHz */ +#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */ + unsigned char psa_quality_thr; /* [0x21] Modem Quality Threshold */ + unsigned char psa_mod_delay; /* [0x22] Modem Delay (?) (reserved) */ + unsigned char psa_nwid[2]; /* [0x23-0x24] Network ID */ + unsigned char psa_nwid_select; /* [0x25] Network ID Select On/Off */ + unsigned char psa_encryption_select; /* [0x26] Encryption On/Off */ + unsigned char psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */ + unsigned char psa_databus_width; /* [0x2F] AT bus width select 8/16 */ + unsigned char psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */ + unsigned char psa_nwid_prefix[2]; /* [0x38-0x39] Roaming domain */ + unsigned char psa_reserved[2]; /* [0x3A-0x3B] Reserved - fixed 00 */ + unsigned char psa_conf_status; /* [0x3C] Conf Status, bit 0=1:config*/ + unsigned char psa_crc[2]; /* [0x3D] CRC-16 over PSA */ + unsigned char psa_crc_status; /* [0x3F] CRC Valid Flag */ +}; + +#define PSA_SIZE 64 + +/* Calculate offset of a field in the above structure. + * Warning: only even addresses are used. */ +#define psaoff(p,f) ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL)) + +/******************** MODEM MANAGEMENT INTERFACE ********************/ + +/* + * Modem Management Controller (MMC) write structure. + */ +typedef struct mmw_t mmw_t; +struct mmw_t +{ + unsigned char mmw_encr_key[8]; /* encryption key */ + unsigned char mmw_encr_enable; /* Enable or disable encryption. */ +#define MMW_ENCR_ENABLE_MODE 0x02 /* mode of security option */ +#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option. */ + unsigned char mmw_unused0[1]; /* unused */ + unsigned char mmw_des_io_invert; /* encryption option */ +#define MMW_DES_IO_INVERT_RES 0x0F /* reserved */ +#define MMW_DES_IO_INVERT_CTRL 0xF0 /* control (?) (set to 0) */ + unsigned char mmw_unused1[5]; /* unused */ + unsigned char mmw_loopt_sel; /* looptest selection */ +#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* Disable NWID filtering. */ +#define MMW_LOOPT_SEL_INT 0x20 /* Activate Attention Request. */ +#define MMW_LOOPT_SEL_LS 0x10 /* looptest, no collision avoidance */ +#define MMW_LOOPT_SEL_LT3A 0x08 /* looptest 3a */ +#define MMW_LOOPT_SEL_LT3B 0x04 /* looptest 3b */ +#define MMW_LOOPT_SEL_LT3C 0x02 /* looptest 3c */ +#define MMW_LOOPT_SEL_LT3D 0x01 /* looptest 3d */ + unsigned char mmw_jabber_enable; /* jabber timer enable */ + /* Abort transmissions > 200 ms */ + unsigned char mmw_freeze; /* freeze or unfreeze signal level */ + /* 0 : signal level & qual updated for every new message, 1 : frozen */ + unsigned char mmw_anten_sel; /* antenna selection */ +#define MMW_ANTEN_SEL_SEL 0x01 /* direct antenna selection */ +#define MMW_ANTEN_SEL_ALG_EN 0x02 /* antenna selection algo. enable */ + unsigned char mmw_ifs; /* inter frame spacing */ + /* min time between transmission in bit periods (.5 us) - bit 0 ignored */ + unsigned char mmw_mod_delay; /* modem delay (synchro) */ + unsigned char mmw_jam_time; /* jamming time (after collision) */ + unsigned char mmw_unused2[1]; /* unused */ + unsigned char mmw_thr_pre_set; /* level threshold preset */ + /* Discard all packet with signal < this value (4) */ + unsigned char mmw_decay_prm; /* decay parameters */ + unsigned char mmw_decay_updat_prm; /* decay update parameters */ + unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */ + /* Discard all packet with quality < this value (3) */ + unsigned char mmw_netw_id_l; /* NWID low order byte */ + unsigned char mmw_netw_id_h; /* NWID high order byte */ + /* Network ID or Domain : create virtual net on the air */ + + /* 2.0 Hardware extension - frequency selection support */ + unsigned char mmw_mode_select; /* for analog tests (set to 0) */ + unsigned char mmw_unused3[1]; /* unused */ + unsigned char mmw_fee_ctrl; /* frequency EEPROM control */ +#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions. */ +#define MMW_FEE_CTRL_DWLD 0x08 /* Download EEPROM to mmc. */ +#define MMW_FEE_CTRL_CMD 0x07 /* EEPROM commands: */ +#define MMW_FEE_CTRL_READ 0x06 /* Read */ +#define MMW_FEE_CTRL_WREN 0x04 /* Write enable */ +#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address. */ +#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses. */ +#define MMW_FEE_CTRL_WDS 0x04 /* Write disable */ +#define MMW_FEE_CTRL_PRREAD 0x16 /* Read addr from protect register */ +#define MMW_FEE_CTRL_PREN 0x14 /* Protect register enable */ +#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers. */ +#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write address in protect register */ +#define MMW_FEE_CTRL_PRDS 0x14 /* Protect register disable */ + /* Never issue the PRDS command: it's irreversible! */ + + unsigned char mmw_fee_addr; /* EEPROM address */ +#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel. */ +#define MMW_FEE_ADDR_OFFSET 0x0F /* Offset in channel data */ +#define MMW_FEE_ADDR_EN 0xC0 /* FEE_CTRL enable operations */ +#define MMW_FEE_ADDR_DS 0x00 /* FEE_CTRL disable operations */ +#define MMW_FEE_ADDR_ALL 0x40 /* FEE_CTRL all operations */ +#define MMW_FEE_ADDR_CLEAR 0xFF /* FEE_CTRL clear operations */ + + unsigned char mmw_fee_data_l; /* Write data to EEPROM. */ + unsigned char mmw_fee_data_h; /* high octet */ + unsigned char mmw_ext_ant; /* Setting for external antenna */ +#define MMW_EXT_ANT_EXTANT 0x01 /* Select external antenna */ +#define MMW_EXT_ANT_POL 0x02 /* Polarity of the antenna */ +#define MMW_EXT_ANT_INTERNAL 0x00 /* Internal antenna */ +#define MMW_EXT_ANT_EXTERNAL 0x03 /* External antenna */ +#define MMW_EXT_ANT_IQ_TEST 0x1C /* IQ test pattern (set to 0) */ +}; + +#define MMW_SIZE 37 + +#define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0) + +/* + * Modem Management Controller (MMC) read structure. + */ +typedef struct mmr_t mmr_t; +struct mmr_t +{ + unsigned char mmr_unused0[8]; /* unused */ + unsigned char mmr_des_status; /* encryption status */ + unsigned char mmr_des_avail; /* encryption available (0x55 read) */ +#define MMR_DES_AVAIL_DES 0x55 /* DES available */ +#define MMR_DES_AVAIL_AES 0x33 /* AES (AT&T) available */ + unsigned char mmr_des_io_invert; /* des I/O invert register */ + unsigned char mmr_unused1[5]; /* unused */ + unsigned char mmr_dce_status; /* DCE status */ +#define MMR_DCE_STATUS_RX_BUSY 0x01 /* receiver busy */ +#define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */ +#define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */ +#define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */ +#define MMR_DCE_STATUS 0x0F /* mask to get the bits */ + unsigned char mmr_dsp_id; /* DSP ID (AA = Daedalus rev A) */ + unsigned char mmr_unused2[2]; /* unused */ + unsigned char mmr_correct_nwid_l; /* # of correct NWIDs rxd (low) */ + unsigned char mmr_correct_nwid_h; /* # of correct NWIDs rxd (high) */ + /* Warning: read high-order octet first! */ + unsigned char mmr_wrong_nwid_l; /* # of wrong NWIDs rxd (low) */ + unsigned char mmr_wrong_nwid_h; /* # of wrong NWIDs rxd (high) */ + unsigned char mmr_thr_pre_set; /* level threshold preset */ +#define MMR_THR_PRE_SET 0x3F /* level threshold preset */ +#define MMR_THR_PRE_SET_CUR 0x80 /* Current signal above it */ + unsigned char mmr_signal_lvl; /* signal level */ +#define MMR_SIGNAL_LVL 0x3F /* signal level */ +#define MMR_SIGNAL_LVL_VALID 0x80 /* Updated since last read */ + unsigned char mmr_silence_lvl; /* silence level (noise) */ +#define MMR_SILENCE_LVL 0x3F /* silence level */ +#define MMR_SILENCE_LVL_VALID 0x80 /* Updated since last read */ + unsigned char mmr_sgnl_qual; /* signal quality */ +#define MMR_SGNL_QUAL 0x0F /* signal quality */ +#define MMR_SGNL_QUAL_ANT 0x80 /* current antenna used */ + unsigned char mmr_netw_id_l; /* NWID low order byte (?) */ + unsigned char mmr_unused3[3]; /* unused */ + + /* 2.0 Hardware extension - frequency selection support */ + unsigned char mmr_fee_status; /* Status of frequency EEPROM */ +#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision ID */ +#define MMR_FEE_STATUS_DWLD 0x08 /* Download in progress */ +#define MMR_FEE_STATUS_BUSY 0x04 /* EEPROM busy */ + unsigned char mmr_unused4[1]; /* unused */ + unsigned char mmr_fee_data_l; /* Read data from EEPROM (low) */ + unsigned char mmr_fee_data_h; /* Read data from EEPROM (high) */ +}; + +#define MMR_SIZE 36 + +#define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0) + +/* Make the two above structures one */ +typedef union mm_t +{ + struct mmw_t w; /* Write to the mmc */ + struct mmr_t r; /* Read from the mmc */ +} mm_t; + +#endif /* _WAVELAN_H */ + +/* + * This software may only be used and distributed + * according to the terms of the GNU General Public License. + * + * For more details, see wavelan.c. + */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wavelan.p.h linux-2.5/drivers/net/wavelan.p.h --- linux-2.5.5/drivers/net/wavelan.p.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/wavelan.p.h Tue Jan 22 17:43:48 2002 @@ -0,0 +1,713 @@ +/* + * WaveLAN ISA driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * + * This file contains all definitions and declarations necessary for the + * WaveLAN ISA driver. This file is a private header, so it should + * be included only in wavelan.c! + */ + +#ifndef WAVELAN_P_H +#define WAVELAN_P_H + +/************************** DOCUMENTATION ***************************/ +/* + * This driver provides a Linux interface to the WaveLAN ISA hardware. + * The WaveLAN is a product of Lucent (http://www.wavelan.com/). + * This division was formerly part of NCR and then AT&T. + * WaveLANs are also distributed by DEC (RoamAbout DS) and Digital Ocean. + * + * To learn how to use this driver, read the NET3 HOWTO. + * If you want to exploit the many other functionalities, read the comments + * in the code. + * + * This driver is the result of the effort of many people (see below). + */ + +/* ------------------------ SPECIFIC NOTES ------------------------ */ +/* + * Web page + * -------- + * I try to maintain a web page with the Wireless LAN Howto at : + * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html + * + * SMP + * --- + * We now are SMP compliant (I eventually fixed the remaining bugs). + * The driver has been tested on a dual P6-150 and survived my usual + * set of torture tests. + * Anyway, I spent enough time chasing interrupt re-entrancy during + * errors or reconfigure, and I designed the locked/unlocked sections + * of the driver with great care, and with the recent addition of + * the spinlock (thanks to the new API), we should be quite close to + * the truth. + * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), + * but better safe than sorry (especially at 2 Mb/s ;-). + * + * I have also looked into disabling only our interrupt on the card + * (via HACR) instead of all interrupts in the processor (via cli), + * so that other driver are not impacted, and it look like it's + * possible, but it's very tricky to do right (full of races). As + * the gain would be mostly for SMP systems, it can wait... + * + * Debugging and options + * --------------------- + * You will find below a set of '#define" allowing a very fine control + * on the driver behaviour and the debug messages printed. + * The main options are : + * o SET_PSA_CRC, to have your card correctly recognised by + * an access point and the Point-to-Point diagnostic tool. + * o USE_PSA_CONFIG, to read configuration from the PSA (EEprom) + * (otherwise we always start afresh with some defaults) + * + * wavelan.o is too darned big + * --------------------------- + * That's true! There is a very simple way to reduce the driver + * object by 33%! Comment out the following line: + * #include + * Other compile options can also reduce the size of it... + * + * MAC address and hardware detection: + * ----------------------------------- + * The detection code for the WaveLAN checks that the first three + * octets of the MAC address fit the company code. This type of + * detection works well for AT&T cards (because the AT&T code is + * hardcoded in wavelan.h), but of course will fail for other + * manufacturers. + * + * If you are sure that your card is derived from the WaveLAN, + * here is the way to configure it: + * 1) Get your MAC address + * a) With your card utilities (wfreqsel, instconf, etc.) + * b) With the driver: + * o compile the kernel with DEBUG_CONFIG_INFO enabled + * o Boot and look the card messages + * 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h) + * 3) Compile and verify + * 4) Send me the MAC code. I will include it in the next version. + * + */ + +/* --------------------- WIRELESS EXTENSIONS --------------------- */ +/* + * This driver is the first to support "wireless extensions". + * This set of extensions provides a standard way to control the wireless + * characteristics of the hardware. Applications such as mobile IP may + * take advantage of it. + * + * You will need to enable the CONFIG_NET_RADIO define in the kernel + * configuration to enable the wireless extensions (this is the one + * giving access to the radio network device choice). + * + * It might also be a good idea as well to fetch the wireless tools to + * configure the device and play a bit. + */ + +/* ---------------------------- FILES ---------------------------- */ +/* + * wavelan.c: actual code for the driver: C functions + * + * wavelan.p.h: private header: local types and variables for driver + * + * wavelan.h: description of the hardware interface and structs + * + * i82586.h: description of the Ethernet controller + */ + +/* --------------------------- HISTORY --------------------------- */ +/* + * This is based on information in the drivers' headers. It may not be + * accurate, and I guarantee only my best effort. + * + * The history of the WaveLAN drivers is as complicated as the history of + * the WaveLAN itself (NCR -> AT&T -> Lucent). + * + * It all started with Anders Klemets + * writing a WaveLAN ISA driver for the Mach microkernel. Girish + * Welling had also worked on it. + * Keith Moore modified this for the PCMCIA hardware. + * + * Robert Morris ported these two drivers to BSDI + * and added specific PCMCIA support (there is currently no equivalent + * of the PCMCIA package under BSD). + * + * Jim Binkley ported both BSDI drivers to FreeBSD. + * + * Bruce Janson ported the BSDI ISA driver to Linux. + * + * Anthony D. Joseph started to modify Bruce's driver + * (with help of the BSDI PCMCIA driver) for PCMCIA. + * Yunzhou Li finished this work. + * Joe Finney patched the driver to start + * 2.00 cards correctly (2.4 GHz with frequency selection). + * David Hinds integrated the whole in his + * PCMCIA package (and bug corrections). + * + * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some + * patches to the PCMCIA driver. Later, I added code in the ISA driver + * for Wireless Extensions and full support of frequency selection + * cards. Then, I did the same to the PCMCIA driver, and did some + * reorganisation. Finally, I came back to the ISA driver to + * upgrade it at the same level as the PCMCIA one and reorganise + * the code. + * Loeke Brederveld from Lucent has given me + * much needed information on the WaveLAN hardware. + */ + +/* The original copyrights and literature mention others' names and + * credits. I don't know what their part in this development was. + */ + +/* By the way, for the copyright and legal stuff: + * almost everybody wrote code under the GNU or BSD license (or similar), + * and want their original copyright to remain somewhere in the + * code (for myself, I go with the GPL). + * Nobody wants to take responsibility for anything, except the fame. + */ + +/* --------------------------- CREDITS --------------------------- */ +/* + * This software was developed as a component of the + * Linux operating system. + * It is based on other device drivers and information + * either written or supplied by: + * Ajay Bakre , + * Donald Becker , + * Loeke Brederveld , + * Brent Elphick , + * Anders Klemets , + * Vladimir V. Kolpakov , + * Marc Meertens , + * Pauline Middelink , + * Robert Morris , + * Jean Tourrilhes , + * Girish Welling , + * Clark Woodworth + * Yongguang Zhang + * + * Thanks go also to: + * James Ashton , + * Alan Cox , + * Allan Creighton , + * Matthew Geier , + * Remo di Giovanni , + * Eckhard Grah , + * Vipul Gupta , + * Mark Hagan , + * Tim Nicholson , + * Ian Parkin , + * John Rosenberg , + * George Rossi , + * Arthur Scott , + * Stanislav Sinyagin + * and Peter Storey for their assistance and advice. + * + * Additional Credits: + * + * My development has been done initially under Debian 1.1 (Linux 2.0.x) + * and now under Debian 2.2, initially with an HP Vectra XP/60, and now + * an HP Vectra XP/90. + * + */ + +/* ------------------------- IMPROVEMENTS ------------------------- */ +/* + * I proudly present: + * + * Changes made in first pre-release: + * ---------------------------------- + * - reorganisation of the code, function name change + * - creation of private header (wavelan.p.h) + * - reorganised debug messages + * - more comments, history, etc. + * - mmc_init: configure the PSA if not done + * - mmc_init: correct default value of level threshold for PCMCIA + * - mmc_init: 2.00 detection better code for 2.00 initialization + * - better info at startup + * - IRQ setting (note: this setting is permanent) + * - watchdog: change strategy (and solve module removal problems) + * - add wireless extensions (ioctl and get_wireless_stats) + * get/set nwid/frequency on fly, info for /proc/net/wireless + * - more wireless extensions: SETSPY and GETSPY + * - make wireless extensions optional + * - private ioctl to set/get quality and level threshold, histogram + * - remove /proc/net/wavelan + * - suppress useless stuff from lp (net_local) + * - kernel 2.1 support (copy_to/from_user instead of memcpy_to/fromfs) + * - add message level (debug stuff in /var/adm/debug and errors not + * displayed at console and still in /var/adm/messages) + * - multi device support + * - start fixing the probe (init code) + * - more inlines + * - man page + * - many other minor details and cleanups + * + * Changes made in second pre-release: + * ----------------------------------- + * - clean up init code (probe and module init) + * - better multiple device support (module) + * - name assignment (module) + * + * Changes made in third pre-release: + * ---------------------------------- + * - be more conservative on timers + * - preliminary support for multicast (I still lack some details) + * + * Changes made in fourth pre-release: + * ----------------------------------- + * - multicast (revisited and finished) + * - avoid reset in set_multicast_list (a really big hack) + * if somebody could apply this code for other i82586 based drivers + * - share onboard memory 75% RU and 25% CU (instead of 50/50) + * + * Changes made for release in 2.1.15: + * ----------------------------------- + * - change the detection code for multi manufacturer code support + * + * Changes made for release in 2.1.17: + * ----------------------------------- + * - update to wireless extensions changes + * - silly bug in card initial configuration (psa_conf_status) + * + * Changes made for release in 2.1.27 & 2.0.30: + * -------------------------------------------- + * - small bug in debug code (probably not the last one...) + * - remove extern keyword for wavelan_probe() + * - level threshold is now a standard wireless extension (version 4 !) + * - modules parameters types (new module interface) + * + * Changes made for release in 2.1.36: + * ----------------------------------- + * - byte count stats (courtesy of David Hinds) + * - remove dev_tint stuff (courtesy of David Hinds) + * - encryption setting from Brent Elphick (thanks a lot!) + * - 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) + * + * Other changes (not by me) : + * ------------------------- + * - Spelling and gramar "rectification". + * + * Changes made for release in 2.0.37 & 2.2.2 : + * ------------------------------------------ + * - Correct status in /proc/net/wireless + * - Set PSA CRC to make PtP diagnostic tool happy (Bob Gray) + * - Module init code don't fail if we found at least one card in + * the address list (Karlis Peisenieks) + * - Missing parenthesis (Christopher Peterson) + * - Correct i82586 configuration parameters + * - Encryption initialisation bug (Robert McCormack) + * - New mac addresses detected in the probe + * - Increase watchdog for busy environments + * + * Changes made for release in 2.0.38 & 2.2.7 : + * ------------------------------------------ + * - Correct the reception logic to better report errors and avoid + * sending bogus packet up the stack + * - Delay RU config to avoid corrupting first received packet + * - Change config completion code (to actually check something) + * - Avoid reading out of bound in skbuf to transmit + * - Rectify a lot of (useless) debugging code + * - Change the way to `#ifdef SET_PSA_CRC' + * + * Changes made for release in 2.2.11 & 2.3.13 : + * ------------------------------------------- + * - Change e-mail and web page addresses + * - Watchdog timer is now correctly expressed in HZ, not in jiffies + * - Add channel number to the list of frequencies in range + * - Add the (short) list of bit-rates in range + * - Developp a new sensitivity... (sens.value & sens.fixed) + * + * Changes made for release in 2.2.14 & 2.3.23 : + * ------------------------------------------- + * - Fix check for root permission (break instead of exit) + * - New nwid & encoding setting (Wireless Extension 9) + * + * Changes made for release in 2.3.49 : + * ---------------------------------- + * - Indentation reformating (Alan) + * - Update to new network API (softnet - 2.3.43) : + * o replace dev->tbusy (Alan) + * o replace dev->tstart (Alan) + * o remove dev->interrupt (Alan) + * o add SMP locking via spinlock in splxx (me) + * o add spinlock in interrupt handler (me) + * o use kernel watchdog instead of ours (me) + * o increase watchdog timeout (kernel is more sensitive) (me) + * o verify that all the changes make sense and work (me) + * - Fixup a potential gotcha when reconfiguring and thighten a bit + * the interactions with Tx queue. + * + * Changes made for release in 2.4.0 : + * --------------------------------- + * - Fix spinlock stupid bugs that I left in. The driver is now SMP + * compliant and doesn't lockup at startup. + * + * Wishes & dreams: + * ---------------- + * - roaming (see Pcmcia driver) + */ + +/***************************** INCLUDES *****************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* Wireless extensions */ + +/* WaveLAN declarations */ +#include "i82586.h" +#include "wavelan.h" + +/************************** DRIVER OPTIONS **************************/ +/* + * `#define' or `#undef' the following constant to change the behaviour + * of the driver... + */ +#undef SET_PSA_CRC /* Calculate and set the CRC on PSA (slower) */ +#define USE_PSA_CONFIG /* Use info from the PSA. */ +#undef STRUCT_CHECK /* Verify padding of structures. */ +#undef EEPROM_IS_PROTECTED /* doesn't seem to be necessary */ +#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */ +#undef SET_MAC_ADDRESS /* Experimental */ + +#ifdef WIRELESS_EXT /* If wireless extensions exist in the kernel */ +/* Warning: this stuff will slow down the driver. */ +#define WIRELESS_SPY /* Enable spying addresses. */ +#undef HISTOGRAM /* Enable histogram of signal level. */ +#endif + +/****************************** DEBUG ******************************/ + +#undef DEBUG_MODULE_TRACE /* module insertion/removal */ +#undef DEBUG_CALLBACK_TRACE /* calls made by Linux */ +#undef DEBUG_INTERRUPT_TRACE /* calls to handler */ +#undef DEBUG_INTERRUPT_INFO /* type of interrupt and so on */ +#define DEBUG_INTERRUPT_ERROR /* problems */ +#undef DEBUG_CONFIG_TRACE /* Trace the config functions. */ +#undef DEBUG_CONFIG_INFO /* what's going on */ +#define DEBUG_CONFIG_ERROR /* errors on configuration */ +#undef DEBUG_TX_TRACE /* transmission calls */ +#undef DEBUG_TX_INFO /* header of the transmitted packet */ +#undef DEBUG_TX_FAIL /* Normal failure conditions */ +#define DEBUG_TX_ERROR /* Unexpected conditions */ +#undef DEBUG_RX_TRACE /* transmission calls */ +#undef DEBUG_RX_INFO /* header of the received packet */ +#undef DEBUG_RX_FAIL /* Normal failure conditions */ +#define DEBUG_RX_ERROR /* Unexpected conditions */ + +#undef DEBUG_PACKET_DUMP /* Dump packet on the screen if defined to 32. */ +#undef DEBUG_IOCTL_TRACE /* misc. call by Linux */ +#undef DEBUG_IOCTL_INFO /* various debugging info */ +#define DEBUG_IOCTL_ERROR /* what's going wrong */ +#define DEBUG_BASIC_SHOW /* Show basic startup info. */ +#undef DEBUG_VERSION_SHOW /* Print version info. */ +#undef DEBUG_PSA_SHOW /* Dump PSA to screen. */ +#undef DEBUG_MMC_SHOW /* Dump mmc to screen. */ +#undef DEBUG_SHOW_UNUSED /* Show unused fields too. */ +#undef DEBUG_I82586_SHOW /* Show i82586 status. */ +#undef DEBUG_DEVICE_SHOW /* Show device parameters. */ + +/************************ CONSTANTS & MACROS ************************/ + +#ifdef DEBUG_VERSION_SHOW +static const char *version = "wavelan.c : v23 (SMP + wireless extensions) 05/10/00\n"; +#endif + +/* Watchdog temporisation */ +#define WATCHDOG_JIFFIES (512*HZ/100) + +/* Macro to get the number of elements in an array */ +#define NELS(a) (sizeof(a) / sizeof(a[0])) + +/* ------------------------ PRIVATE IOCTL ------------------------ */ + +#define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ +#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ +#define SIOCSIPLTHR SIOCIWFIRSTPRIV + 2 /* Set level threshold */ +#define SIOCGIPLTHR SIOCIWFIRSTPRIV + 3 /* Get level threshold */ + +#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */ +#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */ + +/****************************** TYPES ******************************/ + +/* Shortcuts */ +typedef struct net_device device; +typedef struct net_device_stats en_stats; +typedef struct iw_statistics iw_stats; +typedef struct iw_quality iw_qual; +typedef struct iw_freq iw_freq; +typedef struct net_local net_local; +typedef struct timer_list timer_list; + +/* Basic types */ +typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ + +/* + * Static specific data for the interface. + * + * For each network interface, Linux keeps data in two structures: "device" + * keeps the generic data (same format for everybody) and "net_local" keeps + * additional specific data. + * Note that some of this specific data is in fact generic (en_stats, for + * example). + */ +struct net_local +{ + net_local * next; /* linked list of the devices */ + device * dev; /* reverse link */ + spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ + en_stats stats; /* Ethernet interface statistics */ + int nresets; /* number of hardware resets */ + u_char reconfig_82586; /* We need to reconfigure the controller. */ + u_char promiscuous; /* promiscuous mode */ + int mc_count; /* number of multicast addresses */ + u_short hacr; /* current host interface state */ + + int tx_n_in_use; + u_short rx_head; + u_short rx_last; + u_short tx_first_free; + u_short tx_first_in_use; + +#ifdef WIRELESS_EXT + iw_stats wstats; /* Wireless-specific statistics */ +#endif + +#ifdef WIRELESS_SPY + int spy_number; /* number of addresses to spy */ + mac_addr spy_address[IW_MAX_SPY]; /* the addresses to spy */ + iw_qual spy_stat[IW_MAX_SPY]; /* statistics gathered */ +#endif /* WIRELESS_SPY */ + +#ifdef HISTOGRAM + int his_number; /* number of intervals */ + u_char his_range[16]; /* boundaries of interval ]n-1; n] */ + u_long his_sum[16]; /* sum in interval */ +#endif /* HISTOGRAM */ +}; + +/**************************** PROTOTYPES ****************************/ + +/* ----------------------- MISC. SUBROUTINES ------------------------ */ +static inline void + wv_splhi(net_local *, /* Disable interrupts, lock driver */ + unsigned long *); /* flags */ +static inline void + wv_splx(net_local *, /* Enable interrupts, unlock driver */ + unsigned long *); /* flags */ +static u_char + wv_irq_to_psa(int); +static int + wv_psa_to_irq(u_char); +/* ------------------- HOST ADAPTER SUBROUTINES ------------------- */ +static inline u_short /* data */ + hasr_read(u_long); /* Read the host interface: base address */ +static inline void + hacr_write(u_long, /* Write to host interface: base address */ + u_short), /* data */ + hacr_write_slow(u_long, + u_short), + set_chan_attn(u_long, /* ioaddr */ + u_short), /* hacr */ + wv_hacr_reset(u_long), /* ioaddr */ + wv_16_off(u_long, /* ioaddr */ + u_short), /* hacr */ + wv_16_on(u_long, /* ioaddr */ + u_short), /* hacr */ + wv_ints_off(device *), + wv_ints_on(device *); +/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ +static void + psa_read(u_long, /* Read the Parameter Storage Area. */ + u_short, /* hacr */ + int, /* offset in PSA */ + u_char *, /* buffer to fill */ + int), /* size to read */ + psa_write(u_long, /* Write to the PSA. */ + u_short, /* hacr */ + int, /* offset in PSA */ + u_char *, /* buffer in memory */ + int); /* length of buffer */ +static inline void + mmc_out(u_long, /* Write 1 byte to the Modem Manag Control. */ + u_short, + u_char), + mmc_write(u_long, /* Write n bytes to the MMC. */ + u_char, + u_char *, + int); +static inline u_char /* Read 1 byte from the MMC. */ + mmc_in(u_long, + u_short); +static inline void + mmc_read(u_long, /* Read n bytes from the MMC. */ + u_char, + u_char *, + int), + fee_wait(u_long, /* Wait for frequency EEPROM: base address */ + int, /* base delay to wait for */ + int); /* time to wait */ +static void + fee_read(u_long, /* Read the frequency EEPROM: base address */ + u_short, /* destination offset */ + u_short *, /* data buffer */ + int); /* number of registers */ +/* ---------------------- I82586 SUBROUTINES ----------------------- */ +static /*inline*/ void + obram_read(u_long, /* ioaddr */ + u_short, /* o */ + u_char *, /* b */ + int); /* n */ +static inline void + obram_write(u_long, /* ioaddr */ + u_short, /* o */ + u_char *, /* b */ + int); /* n */ +static void + wv_ack(device *); +static inline int + wv_synchronous_cmd(device *, + const char *), + wv_config_complete(device *, + u_long, + net_local *); +static int + wv_complete(device *, + u_long, + net_local *); +static inline void + wv_82586_reconfig(device *); +/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ +#ifdef DEBUG_I82586_SHOW +static void + wv_scb_show(unsigned short); +#endif +static inline void + wv_init_info(device *); /* display startup info */ +/* ------------------- IOCTL, STATS & RECONFIG ------------------- */ +static en_stats * + wavelan_get_stats(device *); /* Give stats /proc/net/dev */ +static void + wavelan_set_multicast_list(device *); +/* ----------------------- PACKET RECEPTION ----------------------- */ +static inline void + wv_packet_read(device *, /* Read a packet from a frame. */ + u_short, + int), + wv_receive(device *); /* Read all packets waiting. */ +/* --------------------- PACKET TRANSMISSION --------------------- */ +static inline int + wv_packet_write(device *, /* Write a packet to the Tx buffer. */ + void *, + short); +static int + wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */ + device *); +/* -------------------- HARDWARE CONFIGURATION -------------------- */ +static inline int + wv_mmc_init(device *), /* Initialize the modem. */ + wv_ru_start(device *), /* Start the i82586 receiver unit. */ + wv_cu_start(device *), /* Start the i82586 command unit. */ + wv_82586_start(device *); /* Start the i82586. */ +static void + wv_82586_config(device *); /* Configure the i82586. */ +static inline void + wv_82586_stop(device *); +static int + wv_hw_reset(device *), /* Reset the WaveLAN hardware. */ + wv_check_ioaddr(u_long, /* ioaddr */ + u_char *); /* mac address (read) */ +/* ---------------------- INTERRUPT HANDLING ---------------------- */ +static void + wavelan_interrupt(int, /* interrupt handler */ + void *, + struct pt_regs *); +static void + wavelan_watchdog(device *); /* transmission watchdog */ +/* ------------------- CONFIGURATION CALLBACKS ------------------- */ +static int + wavelan_open(device *), /* Open the device. */ + wavelan_close(device *), /* Close the device. */ + wavelan_config(device *); /* Configure one device. */ +extern int + wavelan_probe(device *); /* See Space.c. */ + +/**************************** VARIABLES ****************************/ + +/* + * This is the root of the linked list of WaveLAN drivers + * It is use to verify that we don't reuse the same base address + * for two different drivers and to clean up when removing the module. + */ +static net_local * wavelan_list = (net_local *) NULL; + +/* + * This table is used to translate the PSA value to IRQ number + * and vice versa. + */ +static u_char irqvals[] = +{ + 0, 0, 0, 0x01, + 0x02, 0x04, 0, 0x08, + 0, 0, 0x10, 0x20, + 0x40, 0, 0, 0x80, +}; + +/* + * Table of the available I/O addresses (base addresses) for WaveLAN + */ +static unsigned short iobase[] = +{ +#if 0 + /* Leave out 0x3C0 for now -- seems to clash with some video + * controllers. + * Leave out the others too -- we will always use 0x390 and leave + * 0x300 for the Ethernet device. + * Jean II: 0x3E0 is fine as well. + */ + 0x300, 0x390, 0x3E0, 0x3C0 +#endif /* 0 */ + 0x390, 0x3E0 +}; + +#ifdef MODULE +/* Parameters set by insmod */ +static int io[4]; +static int irq[4]; +static char name[4][IFNAMSIZ]; +MODULE_PARM(io, "1-4i"); +MODULE_PARM(irq, "1-4i"); +MODULE_PARM(name, "1-4c" __MODULE_STRING(IFNAMSIZ)); +MODULE_PARM_DESC(io, "WaveLAN I/O base address(es),required"); +MODULE_PARM_DESC(irq, "WaveLAN IRQ number(s)"); +MODULE_PARM_DESC(name, "WaveLAN interface neme(s)"); +#endif /* MODULE */ + +#endif /* WAVELAN_P_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wd.c linux-2.5/drivers/net/wd.c --- linux-2.5.5/drivers/net/wd.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/net/wd.c Thu Feb 14 00:48:14 2002 @@ -97,7 +97,7 @@ return -EBUSY; i = wd_probe1(dev, base_addr); if (i != 0) - release_resource(r); + release_region(base_addr, WD_IO_EXTENT); else r->name = dev->name; return i; @@ -114,7 +114,7 @@ r->name = dev->name; return 0; } - release_resource(r); + release_region(ioaddr, WD_IO_EXTENT); } return -ENODEV; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/winbond-840.c linux-2.5/drivers/net/winbond-840.c --- linux-2.5.5/drivers/net/winbond-840.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/net/winbond-840.c Fri Feb 8 01:55:36 2002 @@ -36,8 +36,10 @@ power management. support for big endian descriptors Copyright (C) 2001 Manfred Spraul - * ethtool support (jgarzik) + * ethtool support (jgarzik) * Replace some MII-related magic numbers with constants (jgarzik) + * OOM handling + Copyright (C) 2002 Manfred Spraul TODO: * enable pci_power_off @@ -341,7 +343,6 @@ DescIntr=0x80000000, }; -#define PRIV_ALIGN 15 /* Required alignment mask */ #define MII_CNT 1 /* winbond only supports one MII */ struct netdev_private { struct w840_rx_desc *rx_ring; @@ -363,6 +364,7 @@ struct w840_rx_desc *rx_head_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int rx_buf_sz; /* Based on MTU+slack. */ + int oom; unsigned int cur_tx, dirty_tx; unsigned int tx_q_bytes; unsigned int tx_full; /* The Tx queue is full. */ @@ -378,6 +380,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int netdev_open(struct net_device *dev); static int update_link(struct net_device *dev); +static void refill_rx(struct net_device *dev); static void netdev_timer(unsigned long data); static void init_rxtx_rings(struct net_device *dev); static void free_rxtx_rings(struct netdev_private *np); @@ -828,11 +831,40 @@ np->mii_if.full_duplex = 1; } +static void refill_rx(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + + /* Refill the Rx ring buffers. */ + np->oom = 0; + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + int entry; + entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_addr[entry] = pci_map_single(np->pci_dev, + skb->tail, + skb->len, PCI_DMA_FROMDEVICE); + np->rx_ring[entry].buffer1 = np->rx_addr[entry]; + } + wmb(); + np->rx_ring[entry].status = DescOwn; + } + if (np->cur_rx-np->dirty_rx == RX_RING_SIZE) + np->oom = 1; +} + static void netdev_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; + long next = 10*HZ; if (debug > 2) printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x " @@ -842,8 +874,16 @@ spin_lock_irq(&np->lock); update_csr6(dev, update_link(dev)); spin_unlock_irq(&np->lock); - np->timer.expires = jiffies + 10*HZ; - add_timer(&np->timer); + if (np->oom) { + disable_irq(dev->irq); + refill_rx(dev); + if (np->oom) + next = 1; + else + writel(0, ioaddr + RxStartDemand); + enable_irq(dev->irq); + } + mod_timer(&np->timer, jiffies + next); } static void init_rxtx_rings(struct net_device *dev) @@ -863,22 +903,9 @@ /* Mark the last entry as wrapping the ring. */ np->rx_ring[i-1].length |= DescEndRing; - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_addr[i] = pci_map_single(np->pci_dev,skb->tail, - skb->len,PCI_DMA_FROMDEVICE); - - np->rx_ring[i].buffer1 = np->rx_addr[i]; - np->rx_ring[i].status = DescOwn; - } - - np->cur_rx = 0; - np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + np->cur_rx = RX_RING_SIZE; + np->dirty_rx = 0; + refill_rx(dev); /* Initialize the Tx descriptors */ for (i = 0; i < TX_RING_SIZE; i++) { @@ -1196,8 +1223,9 @@ if (intr_status & (IntrRxDone | RxNoBuf)) netdev_rx(dev); - if (intr_status & RxNoBuf) - writel(0, ioaddr + RxStartDemand); + /* RxNoBuf is an error interrupt, we kick + * RxStartDemand in netdev_error() + */ if (intr_status & (TxIdle | IntrTxDone) && np->cur_tx != np->dirty_tx) { @@ -1329,25 +1357,7 @@ entry = (++np->cur_rx) % RX_RING_SIZE; np->rx_head_desc = &np->rx_ring[entry]; } - - /* Refill the Rx ring buffers. */ - for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { - struct sk_buff *skb; - entry = np->dirty_rx % RX_RING_SIZE; - if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[entry] = skb; - if (skb == NULL) - break; /* Better luck next round. */ - skb->dev = dev; /* Mark as being used by this device. */ - np->rx_addr[entry] = pci_map_single(np->pci_dev, - skb->tail, - skb->len, PCI_DMA_FROMDEVICE); - np->rx_ring[entry].buffer1 = np->rx_addr[entry]; - } - wmb(); - np->rx_ring[entry].status = DescOwn; - } + refill_rx(dev); return 0; } @@ -1391,8 +1401,14 @@ if (netif_device_present(dev)) writel(0x1A0F5, ioaddr + IntrEnable); } + /* strictly only needed with RxNoBuf, but + * kicking too often probably doesn't hurt. + */ + if (np->oom) + mod_timer(&np->timer, jiffies+1); + else + writel(0, ioaddr + RxStartDemand); np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; - writel(0, ioaddr + RxStartDemand); spin_unlock(&np->lock); } @@ -1572,6 +1588,7 @@ dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); } + del_timer_sync(&np->timer); /* Stop the chip's Tx and Rx processes. */ spin_lock_irq(&np->lock); netif_device_detach(dev); @@ -1590,10 +1607,10 @@ if (debug > 2) { int i; - printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + printk(KERN_DEBUG" Tx ring at %8.8x:\n", (int)np->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) - printk(" #%d desc. %4.4x %4.4x %8.8x.\n", + printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x.\n", i, np->tx_ring[i].length, np->tx_ring[i].status, np->tx_ring[i].buffer1); printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", @@ -1606,8 +1623,6 @@ } #endif /* __i386__ debugging only */ - del_timer_sync(&np->timer); - free_rxtx_rings(np); free_ringdesc(np); @@ -1693,7 +1708,6 @@ return 0; } - static int w840_resume (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); @@ -1717,8 +1731,7 @@ netif_wake_queue(dev); - np->timer.expires = jiffies + 1*HZ; - add_timer(&np->timer); + mod_timer(&np->timer, jiffies + 1*HZ); } else { netif_device_attach(dev); } @@ -1732,7 +1745,7 @@ name: DRV_NAME, id_table: w840_pci_tbl, probe: w840_probe1, - remove: w840_remove1, + remove: __devexit_p(w840_remove1), #ifdef CONFIG_PM suspend: w840_suspend, resume: w840_resume, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/airo.c linux-2.5/drivers/net/wireless/airo.c --- linux-2.5.5/drivers/net/wireless/airo.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/net/wireless/airo.c Thu Feb 7 20:00:06 2002 @@ -46,7 +46,7 @@ #include #ifdef CONFIG_PCI -static struct pci_device_id card_ids[] = __devinitdata { +static struct pci_device_id card_ids[] __devinitdata = { { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID }, { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, }, @@ -63,7 +63,7 @@ name: "airo", id_table: card_ids, probe: airo_pci_probe, - remove: airo_pci_remove, + remove: __devexit_p(airo_pci_remove), }; #endif /* CONFIG_PCI */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/airo_cs.c linux-2.5/drivers/net/wireless/airo_cs.c --- linux-2.5.5/drivers/net/wireless/airo_cs.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/net/wireless/airo_cs.c Mon Jan 14 22:39:45 2002 @@ -244,6 +244,11 @@ /* Allocate space for private device-specific data */ local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) { + printk(KERN_ERR "airo_cs: no memory for new device\n"); + kfree (link); + return NULL; + } memset(local, 0, sizeof(local_info_t)); link->priv = local; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/airport.c linux-2.5/drivers/net/wireless/airport.c --- linux-2.5.5/drivers/net/wireless/airport.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/net/wireless/airport.c Wed Jan 23 01:11:51 2002 @@ -1,4 +1,4 @@ -/* airport.c 0.06f +/* airport.c 0.09b * * A driver for "Hermes" chipset based Apple Airport wireless * card. @@ -11,6 +11,8 @@ * 0.06 : fix possible hang on powerup, add sleep support */ +#include + #include #include #include @@ -33,26 +35,27 @@ #include #include -#include +#include +#include #include #include "hermes.h" #include "orinoco.h" -static char version[] __initdata = "airport.c 0.06f (Benjamin Herrenschmidt )"; +static char version[] __initdata = "airport.c 0.09b (Benjamin Herrenschmidt )"; MODULE_AUTHOR("Benjamin Herrenschmidt "); MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); MODULE_LICENSE("Dual MPL/GPL"); EXPORT_NO_SYMBOLS; -typedef struct dldwd_card { +struct airport { struct device_node* node; int irq_requested; int ndev_registered; int open; /* Common structure (fully included), see orinoco.h */ - struct dldwd_priv priv; -} dldwd_card_t; + struct orinoco_private priv; +}; #ifdef CONFIG_PMAC_PBOOK static int airport_sleep_notify(struct pmu_sleep_notifier *self, int when); @@ -65,9 +68,8 @@ * Function prototypes */ -static dldwd_priv_t* airport_attach(struct device_node *of_node); -static void airport_detach(dldwd_priv_t* priv); -static int airport_init(struct net_device *dev); +static struct orinoco_private* airport_attach(struct device_node *of_node); +static void airport_detach(struct orinoco_private* priv); static int airport_open(struct net_device *dev); static int airport_stop(struct net_device *dev); @@ -81,58 +83,38 @@ device numbers are used to derive the corresponding array index. */ -static dldwd_priv_t *airport_dev; - -static int airport_init(struct net_device *dev) -{ - dldwd_priv_t *priv = dev->priv; - int rc; - - TRACE_ENTER(priv->ndev.name); - - MOD_INC_USE_COUNT; - - rc = dldwd_init(dev); - if (!rc) - priv->hw_ready = 1; - - MOD_DEC_USE_COUNT; - - return rc; -} +static struct orinoco_private *airport_dev; static int airport_open(struct net_device *dev) { - dldwd_priv_t *priv = dev->priv; - dldwd_card_t* card = (dldwd_card_t *)priv->card; + struct orinoco_private *priv = dev->priv; + struct airport* card = (struct airport *)priv->card; int rc; - TRACE_ENTER(priv->ndev.name); + netif_device_attach(dev); - rc = dldwd_reset(priv); + rc = orinoco_reset(priv); if (rc) airport_stop(dev); else { card->open = 1; - netif_device_attach(dev); + netif_start_queue(dev); } -// TRACE_EXIT(priv->ndev.name); - return rc; } static int airport_stop(struct net_device *dev) { - dldwd_priv_t *priv = dev->priv; - dldwd_card_t* card = (dldwd_card_t *)priv->card; + struct orinoco_private *priv = dev->priv; + struct airport* card = (struct airport *)priv->card; TRACE_ENTER(priv->ndev.name); netif_stop_queue(dev); - dldwd_shutdown(priv); + orinoco_shutdown(priv); card->open = 0; TRACE_EXIT(priv->ndev.name); @@ -144,16 +126,14 @@ static int airport_sleep_notify(struct pmu_sleep_notifier *self, int when) { - dldwd_priv_t *priv; - struct net_device *ndev; - dldwd_card_t* card; + struct orinoco_private *priv = airport_dev; + struct hermes *hw = &priv->hw; + struct net_device *dev = &priv->ndev; + struct airport* card = (struct airport *)priv->card; int rc; - if (!airport_dev) + if (! airport_dev) return PBOOK_SLEEP_OK; - priv = airport_dev; - ndev = &priv->ndev; - card = (dldwd_card_t *)priv->card; switch (when) { case PBOOK_SLEEP_REQUEST: @@ -161,41 +141,41 @@ case PBOOK_SLEEP_REJECT: break; case PBOOK_SLEEP_NOW: - printk(KERN_INFO "%s: Airport entering sleep mode\n", ndev->name); - netif_device_detach(ndev); - if (card->open) - dldwd_shutdown(priv); - disable_irq(ndev->irq); - feature_set_airport_power(card->node, 0); - priv->hw_ready = 0; + printk(KERN_INFO "%s: Airport entering sleep mode\n", dev->name); + if (card->open) { + netif_stop_queue(dev); + orinoco_shutdown(priv); + netif_device_detach(dev); + } + disable_irq(dev->irq); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); break; case PBOOK_WAKE: - printk(KERN_INFO "%s: Airport waking up\n", ndev->name); - feature_set_airport_power(card->node, 1); + printk(KERN_INFO "%s: Airport waking up\n", dev->name); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); mdelay(200); - hermes_reset(&priv->hw); - priv->hw_ready = 1; - rc = dldwd_reset(priv); + hermes_reset(hw); + rc = orinoco_reset(priv); if (rc) printk(KERN_ERR "airport: Error %d re-initing card !\n", rc); else if (card->open) - netif_device_attach(ndev); - enable_irq(ndev->irq); + netif_device_attach(dev); + enable_irq(dev->irq); break; } return PBOOK_SLEEP_OK; } #endif /* CONFIG_PMAC_PBOOK */ -static dldwd_priv_t* +static struct orinoco_private* airport_attach(struct device_node* of_node) { - dldwd_priv_t *priv; + struct orinoco_private *priv; struct net_device *ndev; - dldwd_card_t* card; + struct airport* card; hermes_t *hw; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); if (of_node->n_addrs < 1 || of_node->n_intrs < 1) { printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n"); @@ -216,14 +196,24 @@ hw = &priv->hw; card->node = of_node; + if (!request_OF_resource(of_node, 0, " (airport)")) { + printk(KERN_ERR "airport: can't request IO resource !\n"); + kfree(card); + return NULL; + } + /* Setup the common part */ - if (dldwd_setup(priv) < 0) { + if (orinoco_setup(priv) < 0) { + release_OF_resource(of_node, 0); kfree(card); return NULL; } + + ndev->name[0] = '\0'; /* register_netdev will give us an ethX name */ + SET_MODULE_OWNER(ndev); + /* Overrides */ - ndev->init = airport_init; ndev->open = airport_open; ndev->stop = airport_stop; @@ -234,21 +224,19 @@ hermes_struct_init(hw, ndev->base_addr); /* Power up card */ - feature_set_airport_power(card->node, 1); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(HZ); /* Reset it before we get the interrupt */ hermes_reset(hw); - if (request_irq(ndev->irq, dldwd_interrupt, 0, "Airport", (void *)priv)) { + if (request_irq(ndev->irq, orinoco_interrupt, 0, "Airport", (void *)priv)) { printk(KERN_ERR "airport: Couldn't get IRQ %d\n", ndev->irq); goto failed; } card->irq_requested = 1; - /* register_netdev will give us an ethX name */ - ndev->name[0] = '\0'; /* Tell the stack we exist */ if (register_netdev(ndev) != 0) { printk(KERN_ERR "airport: register_netdev() failed\n"); @@ -257,10 +245,8 @@ printk(KERN_DEBUG "airport: card registered for interface %s\n", ndev->name); card->ndev_registered = 1; - SET_MODULE_OWNER(ndev); - /* And give us the proc nodes for debugging */ - if (dldwd_proc_dev_init(priv) != 0) + if (orinoco_proc_dev_init(priv) != 0) printk(KERN_ERR "airport: Failed to create /proc node for %s\n", ndev->name); @@ -279,14 +265,12 @@ ======================================================================*/ static void -airport_detach(dldwd_priv_t *priv) +airport_detach(struct orinoco_private *priv) { - dldwd_card_t* card = (dldwd_card_t *)priv->card; + struct airport* card = (struct airport *)priv->card; - priv->hw_ready = 0; - /* Unregister proc entry */ - dldwd_proc_dev_cleanup(priv); + orinoco_proc_dev_cleanup(priv); #ifdef CONFIG_PMAC_PBOOK pmu_unregister_sleep_notifier(&airport_sleep_notifier); @@ -299,12 +283,13 @@ free_irq(priv->ndev.irq, priv); card->irq_requested = 0; -// FIXME -// if (ndev->base_addr) -// iounmap(ndev->base_addr + _IO_BASE); -// ndev->base_addr = 0; + if (priv->ndev.base_addr) + iounmap((void *)(priv->ndev.base_addr + (unsigned long)_IO_BASE)); + priv->ndev.base_addr = 0; + + release_OF_resource(card->node, 0); - feature_set_airport_power(card->node, 0); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(HZ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/hermes.c linux-2.5/drivers/net/wireless/hermes.c --- linux-2.5.5/drivers/net/wireless/hermes.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/net/wireless/hermes.c Fri Feb 8 16:05:37 2002 @@ -53,7 +53,7 @@ #include "hermes.h" -static char version[] __initdata = "hermes.c: 3 Oct 2001 David Gibson "; +static char version[] __initdata = "hermes.c: 16 Jan 2002 David Gibson "; MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller"); MODULE_AUTHOR("David Gibson "); MODULE_LICENSE("Dual MPL/GPL"); @@ -75,9 +75,9 @@ #include #define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \ - printk(#stuff);} while (0) + printk(stuff);} while (0) -#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff) +#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff) #else /* ! HERMES_DEBUG */ @@ -98,10 +98,17 @@ */ static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0) { + int k = CMD_BUSY_TIMEOUT; u16 reg; - /* First check that the command register is not busy */ + /* First wait for the command register to unbusy */ reg = hermes_read_regn(hw, CMD); + while ( (reg & HERMES_CMD_BUSY) && k ) { + k--; + udelay(1); + reg = hermes_read_regn(hw, CMD); + } + DEBUG(3, "hermes_issue_cmd: did %d retries.\n", CMD_BUSY_TIMEOUT-k); if (reg & HERMES_CMD_BUSY) { return -EBUSY; } @@ -223,8 +230,8 @@ hw->iobase); err = -ENODEV; } else - printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n", - hw->iobase); + printk(KERN_ERR "hermes @ 0x%x: Error %d issuing command.\n", + hw->iobase, err); goto out; } @@ -325,7 +332,7 @@ k = BAP_BUSY_TIMEOUT; reg = hermes_read_reg(hw, oreg); - while ((reg & HERMES_OFFSET_BUSY) & k) { + while ((reg & HERMES_OFFSET_BUSY) && k) { k--; udelay(1); reg = hermes_read_reg(hw, oreg); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/hermes.h linux-2.5/drivers/net/wireless/hermes.h --- linux-2.5.5/drivers/net/wireless/hermes.h Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/net/wireless/hermes.h Mon Feb 18 22:01:07 2002 @@ -138,7 +138,7 @@ /*--- Regulate Commands --------------------------*/ #define HERMES_CMD_NOTIFY (0x0010) -#define HERMES_CMD_INQ (0x0011) +#define HERMES_CMD_INQUIRE (0x0011) /*--- Configure Commands --------------------------*/ #define HERMES_CMD_ACCESS (0x0021) @@ -150,88 +150,106 @@ #define HERMES_MONITOR_DISABLE (0x000f) /* - * Configuration RIDs + * Frame structures and constants */ -#define HERMES_RID_CNF_PORTTYPE (0xfc00) -#define HERMES_RID_CNF_MACADDR (0xfc01) -#define HERMES_RID_CNF_DESIRED_SSID (0xfc02) -#define HERMES_RID_CNF_CHANNEL (0xfc03) -#define HERMES_RID_CNF_OWN_SSID (0xfc04) -#define HERMES_RID_CNF_SYSTEM_SCALE (0xfc06) -#define HERMES_RID_CNF_MAX_DATA_LEN (0xfc07) -#define HERMES_RID_CNF_PM_ENABLE (0xfc09) -#define HERMES_RID_CNF_PM_MCAST_RX (0xfc0b) -#define HERMES_RID_CNF_PM_PERIOD (0xfc0c) -#define HERMES_RID_CNF_PM_HOLDOVER (0xfc0d) -#define HERMES_RID_CNF_NICKNAME (0xfc0e) -#define HERMES_RID_CNF_WEP_ON (0xfc20) -#define HERMES_RID_CNF_MWO_ROBUST (0xfc25) -#define HERMES_RID_CNF_MULTICAST_LIST (0xfc80) -#define HERMES_RID_CNF_CREATEIBSS (0xfc81) -#define HERMES_RID_CNF_FRAG_THRESH (0xfc82) -#define HERMES_RID_CNF_RTS_THRESH (0xfc83) -#define HERMES_RID_CNF_TX_RATE_CTRL (0xfc84) -#define HERMES_RID_CNF_PROMISCUOUS (0xfc85) -#define HERMES_RID_CNF_KEYS (0xfcb0) -#define HERMES_RID_CNF_TX_KEY (0xfcb1) -#define HERMES_RID_CNF_TICKTIME (0xfce0) - -#define HERMES_RID_CNF_INTERSIL_WEP_ON (0xfc28) -#define HERMES_RID_CNF_INTERSIL_TX_KEY (0xfc23) -#define HERMES_RID_CNF_INTERSIL_KEY0 (0xfc24) -#define HERMES_RID_CNF_INTERSIL_KEY1 (0xfc25) -#define HERMES_RID_CNF_INTERSIL_KEY2 (0xfc26) -#define HERMES_RID_CNF_INTERSIL_KEY3 (0xfc27) -#define HERMES_RID_CNF_SYMBOL_MANDATORY_BSSID (0xfc21) -#define HERMES_RID_CNF_SYMBOL_AUTH_TYPE (0xfc2A) -#define HERMES_RID_CNF_SYMBOL_BASIC_RATES (0xfc8A) -#define HERMES_RID_CNF_SYMBOL_PREAMBLE (0xfc8C) - -/* - * Information RIDs - */ -#define HERMES_RID_CHANNEL_LIST (0xfd10) -#define HERMES_RID_STAIDENTITY (0xfd20) -#define HERMES_RID_CURRENT_SSID (0xfd41) -#define HERMES_RID_CURRENT_BSSID (0xfd42) -#define HERMES_RID_COMMSQUALITY (0xfd43) -#define HERMES_RID_CURRENT_TX_RATE (0xfd44) -#define HERMES_RID_SHORT_RETRY_LIMIT (0xfd48) -#define HERMES_RID_LONG_RETRY_LIMIT (0xfd49) -#define HERMES_RID_MAX_TX_LIFETIME (0xfd4A) -#define HERMES_RID_WEP_AVAIL (0xfd4f) -#define HERMES_RID_CURRENT_CHANNEL (0xfdc1) -#define HERMES_RID_DATARATES (0xfdc6) -#define HERMES_RID_SYMBOL_SECONDARY_VER (0xfd24) -#define HERMES_RID_SYMBOL_KEY_LENGTH (0xfc2B) +#define HERMES_DESCRIPTOR_OFFSET 0 +#define HERMES_802_11_OFFSET (14) +#define HERMES_802_3_OFFSET (14+32) +#define HERMES_802_2_OFFSET (14+32+14) -/* - * Frame structures and constants - */ +struct hermes_rx_descriptor { + u16 status; + u32 time; + u8 silence; + u8 signal; + u8 rate; + u8 rxflow; + u32 reserved; +} __attribute__ ((packed)); + +#define HERMES_RXSTAT_ERR (0x0003) +#define HERMES_RXSTAT_BADCRC (0x0001) +#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) +#define HERMES_RXSTAT_MACPORT (0x0700) +#define HERMES_RXSTAT_MSGTYPE (0xE000) +#define HERMES_RXSTAT_1042 (0x2000) /* RFC-1042 frame */ +#define HERMES_RXSTAT_TUNNEL (0x4000) /* bridge-tunnel encoded frame */ +#define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */ -typedef struct hermes_frame_desc { - /* Hermes - i.e. little-endian byte-order */ +struct hermes_tx_descriptor { u16 status; - u16 res1, res2; - u16 q_info; - u16 res3, res4; - u16 tx_ctl; -} __attribute__ ((packed)) hermes_frame_desc_t; - -#define HERMES_RXSTAT_ERR (0x0003) -#define HERMES_RXSTAT_MACPORT (0x0700) -#define HERMES_RXSTAT_MSGTYPE (0xE000) - -#define HERMES_RXSTAT_BADCRC (0x0001) -#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002) - -/* RFC-1042 encoded frame */ -#define HERMES_RXSTAT_1042 (0x2000) -/* Bridge-tunnel encoded frame */ -#define HERMES_RXSTAT_TUNNEL (0x4000) -/* Wavelan-II Management Protocol frame */ -#define HERMES_RXSTAT_WMP (0x6000) + u16 reserved1; + u16 reserved2; + u32 sw_support; + u8 retry_count; + u8 tx_rate; + u16 tx_control; +} __attribute__ ((packed)); + +#define HERMES_TXSTAT_RETRYERR (0x0001) +#define HERMES_TXSTAT_AGEDERR (0x0002) +#define HERMES_TXSTAT_DISCON (0x0004) +#define HERMES_TXSTAT_FORMERR (0x0008) + +#define HERMES_TXCTRL_TX_OK (0x0002) /* ?? interrupt on Tx complete */ +#define HERMES_TXCTRL_TX_EX (0x0004) /* ?? interrupt on Tx exception */ +#define HERMES_TXCTRL_802_11 (0x0008) /* We supply 802.11 header */ +#define HERMES_TXCTRL_ALT_RTRY (0x0020) + +/* Inquiry constants and data types */ + +#define HERMES_INQ_TALLIES (0xF100) +#define HERMES_INQ_SCAN (0xF101) +#define HERMES_INQ_LINKSTATUS (0xF200) + +struct hermes_tallies_frame { + u16 TxUnicastFrames; + u16 TxMulticastFrames; + u16 TxFragments; + u16 TxUnicastOctets; + u16 TxMulticastOctets; + u16 TxDeferredTransmissions; + u16 TxSingleRetryFrames; + u16 TxMultipleRetryFrames; + u16 TxRetryLimitExceeded; + u16 TxDiscards; + u16 RxUnicastFrames; + u16 RxMulticastFrames; + u16 RxFragments; + u16 RxUnicastOctets; + u16 RxMulticastOctets; + u16 RxFCSErrors; + u16 RxDiscards_NoBuffer; + u16 TxDiscardsWrongSA; + u16 RxWEPUndecryptable; + u16 RxMsgInMsgFragments; + u16 RxMsgInBadMsgFragments; + /* Those last are probably not available in very old firmwares */ + u16 RxDiscards_WEPICVError; + u16 RxDiscards_WEPExcluded; +} __attribute__ ((packed)); + +/* Grabbed from wlan-ng - Thanks Mark... - Jean II + * This is the result of a scan inquiry command */ +/* Structure describing info about an Access Point */ +struct hermes_scan_apinfo { + u16 channel; /* Channel where the AP sits */ + u16 noise; /* Noise level */ + u16 level; /* Signal level */ + u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */ + u16 beacon_interv; /* Beacon interval ? */ + u16 capabilities; /* Capabilities ? */ + u8 essid[32]; /* ESSID of the network */ + u8 rates[10]; /* Bit rate supported */ + u16 proberesp_rate; /* ???? */ +} __attribute__ ((packed)); +/* Container */ +struct hermes_scan_frame { + u16 rsvd; /* ??? */ + u16 scanreason; /* ??? */ + struct hermes_scan_apinfo aps[35]; /* Scan result */ +} __attribute__ ((packed)); #ifdef __KERNEL__ @@ -246,16 +264,6 @@ u16 status, resp0, resp1, resp2; } hermes_response_t; -/* "ID" structure - used for ESSID and station nickname */ -typedef struct hermes_id { - u16 len; - u16 val[16]; -} __attribute__ ((packed)) hermes_id_t; - -typedef struct hermes_multicast { - u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; -} __attribute__ ((packed)) hermes_multicast_t; - /* Register access convenience macros */ #define hermes_read_reg(hw, off) (inw((hw)->iobase + (off))) #define hermes_write_reg(hw, off, val) (outw_p((val), (hw)->iobase + (off))) @@ -310,8 +318,17 @@ { hermes_response_t resp; - return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), + return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), 0, &resp); +} + +/* Initiate an INQUIRE command (tallies or scan). The result will come as an + * information frame in __dldwd_ev_info() */ +static inline int hermes_inquire(hermes_t *hw, u16 rid) +{ + hermes_response_t resp; + + return hermes_docmd_wait(hw, HERMES_CMD_INQUIRE, rid, &resp); } #define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 ) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/hermes_rid.h linux-2.5/drivers/net/wireless/hermes_rid.h --- linux-2.5.5/drivers/net/wireless/hermes_rid.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/wireless/hermes_rid.h Fri Jan 11 14:53:27 2002 @@ -0,0 +1,153 @@ +#ifndef _HERMES_RID_H +#define _HERMES_RID_H + +/* + * Configuration RIDs + */ +#define HERMES_RID_CNFPORTTYPE 0xFC00 /* used */ +#define HERMES_RID_CNFOWNMACADDR 0xFC01 /* used */ +#define HERMES_RID_CNFDESIREDSSID 0xFC02 /* used */ +#define HERMES_RID_CNFOWNCHANNEL 0xFC03 /* used */ +#define HERMES_RID_CNFOWNSSID 0xFC04 /* used */ +#define HERMES_RID_CNFOWNATIMWINDOW 0xFC05 +#define HERMES_RID_CNFSYSTEMSCALE 0xFC06 /* used */ +#define HERMES_RID_CNFMAXDATALEN 0xFC07 +#define HERMES_RID_CNFWDSADDRESS 0xFC08 +#define HERMES_RID_CNFPMENABLED 0xFC09 /* used */ +#define HERMES_RID_CNFPMEPS 0xFC0A +#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B /* used */ +#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C /* used */ +#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D /* used */ +#define HERMES_RID_CNFOWNNAME 0xFC0E /* used */ +#define HERMES_RID_CNFOWNDTIMPERIOD 0xFC10 +#define HERMES_RID_CNFWDSADDRESS1 0xFC11 +#define HERMES_RID_CNFWDSADDRESS2 0xFC12 +#define HERMES_RID_CNFWDSADDRESS3 0xFC13 +#define HERMES_RID_CNFWDSADDRESS4 0xFC14 +#define HERMES_RID_CNFWDSADDRESS5 0xFC15 +#define HERMES_RID_CNFWDSADDRESS6 0xFC16 +#define HERMES_RID_CNFMULTICASTPMBUFFERING 0xFC17 +#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20 /* used */ +#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21 +#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23 /* used */ +#define HERMES_RID_CNFDEFAULTKEY0 0xFC24 /* used */ +#define HERMES_RID_CNFDEFAULTKEY1 0xFC25 /* used */ +#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25 /* used */ +#define HERMES_RID_CNFDEFAULTKEY2 0xFC26 /* used */ +#define HERMES_RID_CNFDEFAULTKEY3 0xFC27 /* used */ +#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28 /* used */ +#define HERMES_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 +#define HERMES_RID_CNFAUTHENTICATION 0xFC2A /* used */ +#define HERMES_RID_CNFMAXASSOCSTA 0xFC2B +#define HERMES_RID_CNFKEYLENGTH_SYMBOL 0xFC2B +#define HERMES_RID_CNFTXCONTROL 0xFC2C +#define HERMES_RID_CNFROAMINGMODE 0xFC2D +#define HERMES_RID_CNFHOSTAUTHENTICATION 0xFC2E +#define HERMES_RID_CNFRCVCRCERROR 0xFC30 +#define HERMES_RID_CNFMMLIFE 0xFC31 +#define HERMES_RID_CNFALTRETRYCOUNT 0xFC32 +#define HERMES_RID_CNFBEACONINT 0xFC33 +#define HERMES_RID_CNFAPPCFINFO 0xFC34 +#define HERMES_RID_CNFSTAPCFINFO 0xFC35 +#define HERMES_RID_CNFPRIORITYQUSAGE 0xFC37 +#define HERMES_RID_CNFTIMCTRL 0xFC40 +#define HERMES_RID_CNFTHIRTY2TALLY 0xFC42 +#define HERMES_RID_CNFENHSECURITY 0xFC43 +#define HERMES_RID_CNFGROUPADDRESSES 0xFC80 /* used */ +#define HERMES_RID_CNFCREATEIBSS 0xFC81 /* used */ +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82 /* used */ +#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83 /* used */ +#define HERMES_RID_CNFTXRATECONTROL 0xFC84 /* used */ +#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85 /* used */ +#define HERMES_RID_CNFBASICRATES_SYMBOL 0xFC8A +#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C /* used */ +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0 0xFC90 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1 0xFC91 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2 0xFC92 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3 0xFC93 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4 0xFC94 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5 0xFC95 +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6 0xFC96 +#define HERMES_RID_CNFRTSTHRESHOLD0 0xFC97 +#define HERMES_RID_CNFRTSTHRESHOLD1 0xFC98 +#define HERMES_RID_CNFRTSTHRESHOLD2 0xFC99 +#define HERMES_RID_CNFRTSTHRESHOLD3 0xFC9A +#define HERMES_RID_CNFRTSTHRESHOLD4 0xFC9B +#define HERMES_RID_CNFRTSTHRESHOLD5 0xFC9C +#define HERMES_RID_CNFRTSTHRESHOLD6 0xFC9D +#define HERMES_RID_CNFSHORTPREAMBLE 0xFCB0 +#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0 /* used */ +#define HERMES_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 +#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1 /* used */ +#define HERMES_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 +#define HERMES_RID_CNFBASICRATES 0xFCB3 +#define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4 +#define HERMES_RID_CNFTICKTIME 0xFCE0 /* used */ +#define HERMES_RID_CNFSCANREQUEST 0xFCE1 +#define HERMES_RID_CNFJOINREQUEST 0xFCE2 +#define HERMES_RID_CNFAUTHENTICATESTATION 0xFCE3 +#define HERMES_RID_CNFCHANNELINFOREQUEST 0xFCE4 + +/* + * Information RIDs + */ +#define HERMES_RID_MAXLOADTIME 0xFD00 +#define HERMES_RID_DOWNLOADBUFFER 0xFD01 +#define HERMES_RID_PRIID 0xFD02 +#define HERMES_RID_PRISUPRANGE 0xFD03 +#define HERMES_RID_CFIACTRANGES 0xFD04 +#define HERMES_RID_NICSERNUM 0xFD0A +#define HERMES_RID_NICID 0xFD0B +#define HERMES_RID_MFISUPRANGE 0xFD0C +#define HERMES_RID_CFISUPRANGE 0xFD0D +#define HERMES_RID_CHANNELLIST 0xFD10 /* used */ +#define HERMES_RID_REGULATORYDOMAINS 0xFD11 +#define HERMES_RID_TEMPTYPE 0xFD12 +#define HERMES_RID_CIS 0xFD13 +#define HERMES_RID_STAID 0xFD20 /* used */ +#define HERMES_RID_STASUPRANGE 0xFD21 +#define HERMES_RID_MFIACTRANGES 0xFD22 +#define HERMES_RID_CFIACTRANGES2 0xFD23 +#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24 /* used */ +#define HERMES_RID_PORTSTATUS 0xFD40 +#define HERMES_RID_CURRENTSSID 0xFD41 /* used */ +#define HERMES_RID_CURRENTBSSID 0xFD42 /* used */ +#define HERMES_RID_COMMSQUALITY 0xFD43 /* used */ +#define HERMES_RID_CURRENTTXRATE 0xFD44 /* used */ +#define HERMES_RID_CURRENTBEACONINTERVAL 0xFD45 +#define HERMES_RID_CURRENTSCALETHRESHOLDS 0xFD46 +#define HERMES_RID_PROTOCOLRSPTIME 0xFD47 +#define HERMES_RID_SHORTRETRYLIMIT 0xFD48 /* used */ +#define HERMES_RID_LONGRETRYLIMIT 0xFD49 /* used */ +#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A /* used */ +#define HERMES_RID_MAXRECEIVELIFETIME 0xFD4B +#define HERMES_RID_CFPOLLABLE 0xFD4C +#define HERMES_RID_AUTHENTICATIONALGORITHMS 0xFD4D +#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F +#define HERMES_RID_CURRENTTXRATE1 0xFD80 +#define HERMES_RID_CURRENTTXRATE2 0xFD81 +#define HERMES_RID_CURRENTTXRATE3 0xFD82 +#define HERMES_RID_CURRENTTXRATE4 0xFD83 +#define HERMES_RID_CURRENTTXRATE5 0xFD84 +#define HERMES_RID_CURRENTTXRATE6 0xFD85 +#define HERMES_RID_OWNMACADDR 0xFD86 +#define HERMES_RID_SCANRESULTSTABLE 0xFD88 +#define HERMES_RID_PHYTYPE 0xFDC0 +#define HERMES_RID_CURRENTCHANNEL 0xFDC1 /* used */ +#define HERMES_RID_CURRENTPOWERSTATE 0xFDC2 +#define HERMES_RID_CCAMODE 0xFDC3 +#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6 /* used */ +#define HERMES_RID_BUILDSEQ 0xFFFE +#define HERMES_RID_FWID 0xFFFF + +/* "ID" structure - used for ESSID and station nickname */ +struct hermes_idstring { + u16 len; + u16 val[16]; +} __attribute__ ((packed)); + +typedef struct hermes_multicast { + u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN]; +} __attribute__ ((packed)) hermes_multicast_t; + +#endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/ieee802_11.h linux-2.5/drivers/net/wireless/ieee802_11.h --- linux-2.5.5/drivers/net/wireless/ieee802_11.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/net/wireless/ieee802_11.h Fri Jan 11 14:53:27 2002 @@ -0,0 +1,67 @@ +#ifndef _IEEE802_11_H +#define _IEEE802_11_H + +struct ieee802_11_hdr { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctl; + u8 addr4[ETH_ALEN]; + u16 data_len; +} __attribute__ ((packed)); + +/* Frame control field constants */ +#define IEEE802_11_FCTL_VERS 0x0002 +#define IEEE802_11_FCTL_FTYPE 0x000c +#define IEEE802_11_FCTL_STYPE 0x00f0 +#define IEEE802_11_FCTL_TODS 0x0100 +#define IEEE802_11_FCTL_FROMDS 0x0200 +#define IEEE802_11_FCTL_MOREFRAGS 0x0400 +#define IEEE802_11_FCTL_RETRY 0x0800 +#define IEEE802_11_FCTL_PM 0x1000 +#define IEEE802_11_FCTL_MOREDATA 0x2000 +#define IEEE802_11_FCTL_WEP 0x4000 +#define IEEE802_11_FCTL_ORDER 0x8000 + +#define IEEE802_11_FTYPE_MGMT 0x0000 +#define IEEE802_11_FTYPE_CTL 0x0004 +#define IEEE802_11_FTYPE_DATA 0x0008 + +/* management */ +#define IEEE802_11_STYPE_ASSOC_REQ 0x0000 +#define IEEE802_11_STYPE_ASSOC_RESP 0x0010 +#define IEEE802_11_STYPE_REASSOC_REQ 0x0020 +#define IEEE802_11_STYPE_REASSOC_RESP 0x0030 +#define IEEE802_11_STYPE_PROBE_REQ 0x0040 +#define IEEE802_11_STYPE_PROBE_RESP 0x0050 +#define IEEE802_11_STYPE_BEACON 0x0080 +#define IEEE802_11_STYPE_ATIM 0x0090 +#define IEEE802_11_STYPE_DISASSOC 0x00A0 +#define IEEE802_11_STYPE_AUTH 0x00B0 +#define IEEE802_11_STYPE_DEAUTH 0x00C0 + +/* control */ +#define IEEE802_11_STYPE_PSPOLL 0x00A0 +#define IEEE802_11_STYPE_RTS 0x00B0 +#define IEEE802_11_STYPE_CTS 0x00C0 +#define IEEE802_11_STYPE_ACK 0x00D0 +#define IEEE802_11_STYPE_CFEND 0x00E0 +#define IEEE802_11_STYPE_CFENDACK 0x00F0 + +/* data */ +#define IEEE802_11_STYPE_DATA 0x0000 +#define IEEE802_11_STYPE_DATA_CFACK 0x0010 +#define IEEE802_11_STYPE_DATA_CFPOLL 0x0020 +#define IEEE802_11_STYPE_DATA_CFACKPOLL 0x0030 +#define IEEE802_11_STYPE_NULLFUNC 0x0040 +#define IEEE802_11_STYPE_CFACK 0x0050 +#define IEEE802_11_STYPE_CFPOLL 0x0060 +#define IEEE802_11_STYPE_CFACKPOLL 0x0070 + +#define IEEE802_11_SCTL_FRAG 0x000F +#define IEEE802_11_SCTL_SEQ 0xFFF0 + +#endif /* _IEEE802_11_H */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/netwave_cs.c linux-2.5/drivers/net/wireless/netwave_cs.c --- linux-2.5.5/drivers/net/wireless/netwave_cs.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/net/wireless/netwave_cs.c Tue Feb 26 21:24:49 2002 @@ -63,6 +63,9 @@ #ifdef CONFIG_NET_RADIO #include +#if WIRELESS_EXT > 12 +#include +#endif /* WIRELESS_EXT > 12 */ #endif #include @@ -269,6 +272,16 @@ because they generally can't be allocated dynamically. */ +#if WIRELESS_EXT <= 12 +/* Wireless extensions backward compatibility */ + +/* Part of iw_handler prototype we need */ +struct iw_request_info +{ + __u16 cmd; /* Wireless Extension command */ + __u16 flags; /* More to come ;-) */ +}; + /* Wireless Extension Backward compatibility - Jean II * If the new wireless device private ioctl range is not defined, * default to standard device private ioctl range */ @@ -276,8 +289,11 @@ #define SIOCIWFIRSTPRIV SIOCDEVPRIVATE #endif /* SIOCIWFIRSTPRIV */ -#define SIOCGIPSNAP SIOCIWFIRSTPRIV /* Site Survey Snapshot */ -/*#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1*/ +#else /* WIRELESS_EXT <= 12 */ +static const struct iw_handler_def netwave_handler_def; +#endif /* WIRELESS_EXT <= 12 */ + +#define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1 /* Site Survey Snapshot */ #define MAX_ESA 10 @@ -483,7 +499,10 @@ /* wireless extensions */ #ifdef WIRELESS_EXT dev->get_wireless_stats = &netwave_get_wireless_stats; -#endif +#if WIRELESS_EXT > 12 + dev->wireless_handlers = (struct iw_handler_def *)&netwave_handler_def; +#endif /* WIRELESS_EXT > 12 */ +#endif /* WIRELESS_EXT */ dev->do_ioctl = &netwave_ioctl; dev->tx_timeout = &netwave_watchdog; @@ -596,6 +615,303 @@ } /* netwave_flush_stale_links */ /* + * Wireless Handler : get protocol name + */ +static int netwave_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + strcpy(wrqu->name, "Netwave"); + return 0; +} + +/* + * Wireless Handler : set Network ID + */ +static int netwave_set_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long flags; + ioaddr_t iobase = dev->base_addr; + netwave_private *priv = (netwave_private *) dev->priv; + u_char *ramBase = priv->ramBase; + + /* Disable interrupts & save flags */ + save_flags(flags); + cli(); + +#if WIRELESS_EXT > 8 + if(!wrqu->nwid.disabled) { + domain = wrqu->nwid.value; +#else /* WIRELESS_EXT > 8 */ + if(wrqu->nwid.on) { + domain = wrqu->nwid.nwid; +#endif /* WIRELESS_EXT > 8 */ + printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", + (domain >> 8) & 0x01, domain & 0xff); + wait_WOC(iobase); + writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0); + writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + } + + /* ReEnable interrupts & restore flags */ + restore_flags(flags); + + return 0; +} + +/* + * Wireless Handler : get Network ID + */ +static int netwave_get_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ +#if WIRELESS_EXT > 8 + wrqu->nwid.value = domain; + wrqu->nwid.disabled = 0; + wrqu->nwid.fixed = 1; +#else /* WIRELESS_EXT > 8 */ + wrqu->nwid.nwid = domain; + wrqu->nwid.on = 1; +#endif /* WIRELESS_EXT > 8 */ + + return 0; +} + +/* + * Wireless Handler : set scramble key + */ +static int netwave_set_scramble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *key) +{ + unsigned long flags; + ioaddr_t iobase = dev->base_addr; + netwave_private *priv = (netwave_private *) dev->priv; + u_char *ramBase = priv->ramBase; + + /* Disable interrupts & save flags */ + save_flags(flags); + cli(); + + scramble_key = (key[0] << 8) | key[1]; + wait_WOC(iobase); + writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); + writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + + /* ReEnable interrupts & restore flags */ + restore_flags(flags); + + return 0; +} + +/* + * Wireless Handler : get scramble key + */ +static int netwave_get_scramble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *key) +{ + key[1] = scramble_key & 0xff; + key[0] = (scramble_key>>8) & 0xff; +#if WIRELESS_EXT > 8 + wrqu->encoding.flags = IW_ENCODE_ENABLED; + wrqu->encoding.length = 2; +#else /* WIRELESS_EXT > 8 */ + wrqu->encoding.method = 1; +#endif /* WIRELESS_EXT > 8 */ + + return 0; +} + +#if WIRELESS_EXT > 8 +/* + * Wireless Handler : get mode + */ +static int netwave_get_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + if(domain & 0x100) + wrqu->mode = IW_MODE_INFRA; + else + wrqu->mode = IW_MODE_ADHOC; + + return 0; +} +#endif /* WIRELESS_EXT > 8 */ + +/* + * Wireless Handler : get range info + */ +static int netwave_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_range *range = (struct iw_range *) extra; + int ret = 0; + + /* Set the length (very important for backward compatibility) */ + wrqu->data.length = sizeof(struct iw_range); + + /* Set all the info we don't care or don't know about to zero */ + memset(range, 0, sizeof(struct iw_range)); + +#if WIRELESS_EXT > 10 + /* Set the Wireless Extension versions */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 9; /* Nothing for us in v10 and v11 */ +#endif /* WIRELESS_EXT > 10 */ + + /* Set information in the range struct */ + range->throughput = 450 * 1000; /* don't argue on this ! */ + range->min_nwid = 0x0000; + range->max_nwid = 0x01FF; + + range->num_channels = range->num_frequency = 0; + + range->sensitivity = 0x3F; + range->max_qual.qual = 255; + range->max_qual.level = 255; + range->max_qual.noise = 0; + +#if WIRELESS_EXT > 7 + range->num_bitrates = 1; + range->bitrate[0] = 1000000; /* 1 Mb/s */ +#endif /* WIRELESS_EXT > 7 */ + +#if WIRELESS_EXT > 8 + range->encoding_size[0] = 2; /* 16 bits scrambling */ + range->num_encoding_sizes = 1; + range->max_encoding_tokens = 1; /* Only one key possible */ +#endif /* WIRELESS_EXT > 8 */ + + return ret; +} + +/* + * Wireless Private Handler : get snapshot + */ +static int netwave_get_snap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long flags; + ioaddr_t iobase = dev->base_addr; + netwave_private *priv = (netwave_private *) dev->priv; + u_char *ramBase = priv->ramBase; + + /* Disable interrupts & save flags */ + save_flags(flags); + cli(); + + /* Take snapshot of environment */ + netwave_snapshot( priv, ramBase, iobase); + wrqu->data.length = priv->nss.length; + memcpy(extra, (u_char *) &priv->nss, sizeof( struct site_survey)); + + priv->lastExec = jiffies; + + /* ReEnable interrupts & restore flags */ + restore_flags(flags); + + return(0); +} + +/* + * Structures to export the Wireless Handlers + * This is the stuff that are treated the wireless extensions (iwconfig) + */ + +static const struct iw_priv_args netwave_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + { SIOCGIPSNAP, 0, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof(struct site_survey), + "getsitesurvey" }, +}; + +#if WIRELESS_EXT > 12 + +static const iw_handler netwave_handler[] = +{ + NULL, /* SIOCSIWNAME */ + netwave_get_name, /* SIOCGIWNAME */ + netwave_set_nwid, /* SIOCSIWNWID */ + netwave_get_nwid, /* SIOCGIWNWID */ + NULL, /* SIOCSIWFREQ */ + NULL, /* SIOCGIWFREQ */ + NULL, /* SIOCSIWMODE */ + netwave_get_mode, /* SIOCGIWMODE */ + NULL, /* SIOCSIWSENS */ + NULL, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + netwave_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ + NULL, /* SIOCSIWSPY */ + NULL, /* SIOCGIWSPY */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWAP */ + NULL, /* SIOCGIWAP */ + NULL, /* -- hole -- */ + NULL, /* SIOCGIWAPLIST */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWESSID */ + NULL, /* SIOCGIWESSID */ + NULL, /* SIOCSIWNICKN */ + NULL, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWRATE */ + NULL, /* SIOCGIWRATE */ + NULL, /* SIOCSIWRTS */ + NULL, /* SIOCGIWRTS */ + NULL, /* SIOCSIWFRAG */ + NULL, /* SIOCGIWFRAG */ + NULL, /* SIOCSIWTXPOW */ + NULL, /* SIOCGIWTXPOW */ + NULL, /* SIOCSIWRETRY */ + NULL, /* SIOCGIWRETRY */ + netwave_set_scramble, /* SIOCSIWENCODE */ + netwave_get_scramble, /* SIOCGIWENCODE */ +}; + +static const iw_handler netwave_private_handler[] = +{ + NULL, /* SIOCIWFIRSTPRIV */ + netwave_get_snap, /* SIOCIWFIRSTPRIV + 1 */ +}; + +static const struct iw_handler_def netwave_handler_def = +{ + num_standard: sizeof(netwave_handler)/sizeof(iw_handler), + num_private: sizeof(netwave_private_handler)/sizeof(iw_handler), + num_private_args: sizeof(netwave_private_args)/sizeof(struct iw_priv_args), + standard: (iw_handler *) netwave_handler, + private: (iw_handler *) netwave_private_handler, + private_args: (struct iw_priv_args *) netwave_private_args, +}; +#endif /* WIRELESS_EXT > 12 */ + +/* * Function netwave_ioctl (dev, rq, cmd) * * Perform ioctl : config & info stuff @@ -606,56 +922,28 @@ struct ifreq *rq, /* Data passed */ int cmd) /* Ioctl number */ { - unsigned long flags; int ret = 0; #ifdef WIRELESS_EXT - ioaddr_t iobase = dev->base_addr; - netwave_private *priv = (netwave_private *) dev->priv; - u_char *ramBase = priv->ramBase; +#if WIRELESS_EXT <= 12 struct iwreq *wrq = (struct iwreq *) rq; #endif +#endif DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd); - /* Disable interrupts & save flags */ - save_flags(flags); - cli(); - /* Look what is the request */ switch(cmd) { /* --------------- WIRELESS EXTENSIONS --------------- */ #ifdef WIRELESS_EXT +#if WIRELESS_EXT <= 12 case SIOCGIWNAME: - /* Get name */ - strcpy(wrq->u.name, "Netwave"); + netwave_get_name(dev, NULL, &(wrq->u), NULL); break; case SIOCSIWNWID: - /* Set domain */ -#if WIRELESS_EXT > 8 - if(!wrq->u.nwid.disabled) { - domain = wrq->u.nwid.value; -#else /* WIRELESS_EXT > 8 */ - if(wrq->u.nwid.on) { - domain = wrq->u.nwid.nwid; -#endif /* WIRELESS_EXT > 8 */ - printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", - (domain >> 8) & 0x01, domain & 0xff); - wait_WOC(iobase); - writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0); - writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1); - writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); - } break; + ret = netwave_set_nwid(dev, NULL, &(wrq->u), NULL); + break; case SIOCGIWNWID: - /* Read domain*/ -#if WIRELESS_EXT > 8 - wrq->u.nwid.value = domain; - wrq->u.nwid.disabled = 0; - wrq->u.nwid.fixed = 1; -#else /* WIRELESS_EXT > 8 */ - wrq->u.nwid.nwid = domain; - wrq->u.nwid.on = 1; -#endif /* WIRELESS_EXT > 8 */ + ret = netwave_get_nwid(dev, NULL, &(wrq->u), NULL); break; #if WIRELESS_EXT > 8 /* Note : The API did change... */ case SIOCGIWENCODE: @@ -663,10 +951,7 @@ if(wrq->u.encoding.pointer != (caddr_t) 0) { char key[2]; - key[1] = scramble_key & 0xff; - key[0] = (scramble_key>>8) & 0xff; - wrq->u.encoding.flags = IW_ENCODE_ENABLED; - wrq->u.encoding.length = 2; + ret = netwave_get_scramble(dev, NULL, &(wrq->u), key); if(copy_to_user(wrq->u.encoding.pointer, key, 2)) ret = -EFAULT; } @@ -681,127 +966,68 @@ ret = -EFAULT; break; } - scramble_key = (key[0] << 8) | key[1]; - wait_WOC(iobase); - writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); - writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); - writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + ret = netwave_set_scramble(dev, NULL, &(wrq->u), key); } break; case SIOCGIWMODE: - /* Mode of operation */ - if(domain & 0x100) - wrq->u.mode = IW_MODE_INFRA; - else - wrq->u.mode = IW_MODE_ADHOC; - break; + /* Mode of operation */ + ret = netwave_get_mode(dev, NULL, &(wrq->u), NULL); + break; #else /* WIRELESS_EXT > 8 */ case SIOCGIWENCODE: /* Get scramble key */ - wrq->u.encoding.code = scramble_key; - wrq->u.encoding.method = 1; + ret = netwave_get_scramble(dev, NULL, &(wrq->u), + (char *) &wrq->u.encoding.code); break; case SIOCSIWENCODE: /* Set scramble key */ - scramble_key = wrq->u.encoding.code; - wait_WOC(iobase); - writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); - writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); - writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + ret = netwave_set_scramble(dev, NULL, &(wrq->u), + (char *) &wrq->u.encoding.code); break; #endif /* WIRELESS_EXT > 8 */ case SIOCGIWRANGE: /* Basic checking... */ if(wrq->u.data.pointer != (caddr_t) 0) { - struct iw_range range; - - /* Set the length (very important for backward compatibility) */ - wrq->u.data.length = sizeof(struct iw_range); - - /* Set all the info we don't care or don't know about to zero */ - memset(&range, 0, sizeof(range)); - -#if WIRELESS_EXT > 10 - /* Set the Wireless Extension versions */ - range.we_version_compiled = WIRELESS_EXT; - range.we_version_source = 9; /* Nothing for us in v10 and v11 */ -#endif /* WIRELESS_EXT > 10 */ - - /* Set information in the range struct */ - range.throughput = 450 * 1000; /* don't argue on this ! */ - range.min_nwid = 0x0000; - range.max_nwid = 0x01FF; - - range.num_channels = range.num_frequency = 0; - - range.sensitivity = 0x3F; - range.max_qual.qual = 255; - range.max_qual.level = 255; - range.max_qual.noise = 0; - -#if WIRELESS_EXT > 7 - range.num_bitrates = 1; - range.bitrate[0] = 1000000; /* 1 Mb/s */ -#endif /* WIRELESS_EXT > 7 */ - -#if WIRELESS_EXT > 8 - range.encoding_size[0] = 2; /* 16 bits scrambling */ - range.num_encoding_sizes = 1; - range.max_encoding_tokens = 1; /* Only one key possible */ -#endif /* WIRELESS_EXT > 8 */ - - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, &range, - sizeof(struct iw_range))) - ret = -EFAULT; + struct iw_range range; + ret = netwave_get_range(dev, NULL, &(wrq->u), (char *) &range); + if (copy_to_user(wrq->u.data.pointer, &range, + sizeof(struct iw_range))) + ret = -EFAULT; } break; case SIOCGIWPRIV: /* Basic checking... */ if(wrq->u.data.pointer != (caddr_t) 0) { - struct iw_priv_args priv[] = - { /* cmd, set_args, get_args, name */ - { SIOCGIPSNAP, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 0, - sizeof(struct site_survey), - "getsitesurvey" }, - }; - /* Set the number of ioctl available */ - wrq->u.data.length = 1; + wrq->u.data.length = sizeof(netwave_private_args) / sizeof(netwave_private_args[0]); /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, - sizeof(priv))) + if(copy_to_user(wrq->u.data.pointer, + (u_char *) netwave_private_args, + sizeof(netwave_private_args))) ret = -EFAULT; } break; case SIOCGIPSNAP: if(wrq->u.data.pointer != (caddr_t) 0) { - /* Take snapshot of environment */ - netwave_snapshot( priv, ramBase, iobase); - wrq->u.data.length = priv->nss.length; + char buffer[sizeof( struct site_survey)]; + ret = netwave_get_snap(dev, NULL, &(wrq->u), buffer); /* Copy structure to the user buffer */ if(copy_to_user(wrq->u.data.pointer, - (u_char *) &priv->nss, - sizeof( struct site_survey))) + buffer, + sizeof( struct site_survey))) { printk(KERN_DEBUG "Bad buffer!\n"); break; } - - priv->lastExec = jiffies; } break; -#endif +#endif /* WIRELESS_EXT <= 12 */ +#endif /* WIRELESS_EXT */ default: ret = -EOPNOTSUPP; } - /* ReEnable interrupts & restore flags */ - restore_flags(flags); - return ret; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/orinoco.c linux-2.5/drivers/net/wireless/orinoco.c --- linux-2.5.5/drivers/net/wireless/orinoco.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/net/wireless/orinoco.c Sun Mar 3 20:15:16 2002 @@ -1,4 +1,4 @@ -/* orinoco.c 0.08a - (formerly known as dldwd_cs.c and orinoco_cs.c) +/* orinoco.c 0.09b - (formerly known as dldwd_cs.c and orinoco_cs.c) * * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ @@ -197,18 +197,67 @@ * o Fixed bad bug in WEP key handling on Intersil and Symbol firmware, * which led to an instant crash on big-endian machines. * - * TODO - Jean II - * o inline functions (lots of candidate, need to reorder code) - * o Test PrismII/Symbol cards & firmware versions - * o Mini-PCI support (some people have reported success - JII) + * v0.08a -> v0.08b - 20/11/2001 - David Gibson + * o Lots of cleanup and bugfixes in orinoco_plx.c + * o Cleanup to handling of Tx rate setting. + * o Removed support for old encapsulation method. + * o Removed old "dldwd" names. + * o Split RID constants into a new file hermes_rid.h + * o Renamed RID constants to match linux-wlan-ng and prism2.o + * o Bugfixes in hermes.c + * o Poke the PLX's INTCSR register, so it actually starts + * generating interrupts. These cards might actually work now. + * o Update to wireless extensions v12 (Jean II) + * o Support for tallies and inquire command (Jean II) + * o Airport updates for newer PPC kernels (BenH) + * + * v0.08b -> v0.09 - 21/12/2001 - David Gibson + * o Some new PCI IDs for PLX cards. + * o Removed broken attempt to do ALLMULTI reception. Just use + * promiscuous mode instead + * o Preliminary work for list-AP (Jean II) + * o Airport updates from (BenH) + * o Eliminated racy hw_ready stuff + * o Fixed generation of fake events in irq handler. This should + * finally kill the EIO problems (Jean II & dgibson) + * o Fixed breakage of bitrate set/get on Agere firmware (Jean II) + * + * v0.09 -> v0.09a - 2/1/2002 - David Gibson + * o Fixed stupid mistake in multicast list handling, triggering + * a BUG() + * + * v0.09a -> v0.09b - 16/1/2002 - David Gibson + * o Fixed even stupider mistake in new interrupt handling, which + * seriously broke things on big-endian machines. + * o Removed a bunch of redundand includes and exports. + * o Removed a redundant MOD_{INC,DEC}_USE_COUNT pair in airport.c + * o Don't attempt to do hardware level multicast reception on + * Intersil firmware, just go promisc instead. + * o Typo fixed in hermes_issue_cmd() + * o Eliminated WIRELESS_SPY #ifdefs + * o Status code reported on Tx exceptions + * o Moved netif_wake_queue() from ALLOC interrupts to TX and TXEXC + * interrupts, which should fix the timeouts we're seeing. + * + * TODO * o Find and kill remaining Tx timeout problems + * o Fix WEP / order of iwconfig wierdness on Intersil firmware + * o Convert /proc debugging stuff to seqfile + * o Re-assess our encapsulation detection strategy + * o Handle de-encapsulation within NET framework, provide 802.11 + * headers + * o Fix possible races in SPY handling. + * o Take the xmit lock when calling orinoco_reset from an + * ioctl(), because that protects the multicast list. + * o Fix allocation lengths. */ /* Notes on locking: * * The basic principle of operation is that everything except the * interrupt handler is serialized through a single spinlock in the - * dldwd_priv_t structure, using dldwd_lock() and - * dldwd_unlock() (which in turn use spin_lock_bh() and spin_unlock_bh()). + * struct orinoco_private structure, using dldwd_lock() and + * dldwd_unlock() (which in turn use spin_lock_bh() and + * spin_unlock_bh()). * * The kernel's IRQ handling stuff ensures that the interrupt handler * does not re-enter itself. The interrupt handler is written such @@ -216,10 +265,11 @@ * that the Rx path uses one of the Hermes chipset's BAPs while * everything else uses the other. * - * Actually, the current updating of the statistics from the interrupt - * handler is unsafe. However all it can do is perturb the - * packet/byte counts slightly, so we just put up with it. We could - * fix this to use atomic types, but it's probably not worth it. + * Actually, strictly speaking, the updating of the statistics from + * the interrupt handler isn't safe without a lock. However the worst + * that can happen is that we perturb the packet/byte counts slightly. + * We could fix this to use atomic types, but it's probably not worth + * it. * * The big exception is that that we don't want the irq handler * running when we actually reset or shut down the card, because @@ -251,33 +301,61 @@ #include #include -#include -#include -#include -#include -#include -#include -#include - #include "hermes.h" +#include "hermes_rid.h" #include "orinoco.h" +#include "ieee802_11.h" + +/* Wireless extensions backwares compatibility */ +#ifndef SIOCIWFIRSTPRIV +#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE +#endif /* SIOCIWFIRSTPRIV */ + +/* We do this this way to avoid ifdefs in the actual code */ +#ifdef WIRELESS_SPY +#define SPY_NUMBER(priv) (priv->spy_number) +#else +#define SPY_NUMBER(priv) 0 +#endif /* WIRELESS_SPY */ -static char version[] __initdata = "orinoco.c 0.08a (David Gibson and others)"; +static char version[] __initdata = "orinoco.c 0.09b (David Gibson and others)"; MODULE_AUTHOR("David Gibson "); MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards"); MODULE_LICENSE("Dual MPL/GPL"); /* Level of debugging. Used in the macros in orinoco.h */ #ifdef ORINOCO_DEBUG -int dldwd_debug = ORINOCO_DEBUG; -MODULE_PARM(dldwd_debug, "i"); +int orinoco_debug = ORINOCO_DEBUG; +MODULE_PARM(orinoco_debug, "i"); #endif -int use_old_encaps = 0; -MODULE_PARM(use_old_encaps, "i"); +#define ORINOCO_MIN_MTU 256 +#define ORINOCO_MAX_MTU (HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD) #define SYMBOL_MAX_VER_LEN (14) +#define LTV_BUF_SIZE 128 +#define USER_BAP 0 +#define IRQ_BAP 1 +#define ORINOCO_MACPORT 0 +#define MAX_IRQLOOPS_PER_IRQ 10 +#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of how many events the + device can legitimately generate */ +#define TX_NICBUF_SIZE 2048 +#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ +#define LARGE_KEY_SIZE 13 +#define SMALL_KEY_SIZE 5 +#define MAX_FRAME_SIZE 2304 + +#define DUMMY_FID 0xFFFF +#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \ + HERMES_MAX_MULTICAST : 0) + +/* + * Data tables + */ + +/* The frequency of each channel in MHz */ const long channel_frequency[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 @@ -285,39 +363,24 @@ #define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) ) -/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. - It gives the rate in halfMb/s, negative indicates auto mode */ -const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0}; - -#define NUM_RATES (sizeof(rate_list) / sizeof(rate_list[0])) - -struct p80211_hdr { - u16 frame_ctl; - u16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq_ctl; - u8 addr4[ETH_ALEN]; - u16 data_len; -} __attribute__ ((packed)); +/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. */ +struct { + int bitrate; /* in 100s of kilbits */ + int automatic; + u16 agere_txratectrl; + u16 intersil_txratectrl; +} bitrate_table[] = { + {110, 1, 3, 15}, /* Entry 0 is the default */ + {10, 0, 1, 1}, + {10, 1, 1, 1}, + {20, 0, 2, 2}, + {20, 1, 6, 3}, + {55, 0, 4, 4}, + {55, 1, 7, 7}, + {110, 0, 5, 8}, +}; -/* Frame control field constants */ -#define DLDWD_FCTL_VERS 0x0002 -#define DLDWD_FCTL_FTYPE 0x000c -#define DLDWD_FCTL_STYPE 0x00f0 -#define DLDWD_FCTL_TODS 0x0100 -#define DLDWD_FCTL_FROMDS 0x0200 -#define DLDWD_FCTL_MOREFRAGS 0x0400 -#define DLDWD_FCTL_RETRY 0x0800 -#define DLDWD_FCTL_PM 0x1000 -#define DLDWD_FCTL_MOREDATA 0x2000 -#define DLDWD_FCTL_WEP 0x4000 -#define DLDWD_FCTL_ORDER 0x8000 - -#define DLDWD_FTYPE_MGMT 0x0000 -#define DLDWD_FTYPE_CTL 0x0004 -#define DLDWD_FTYPE_DATA 0x0008 +#define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0])) struct p8022_hdr { u8 dsap; @@ -326,16 +389,24 @@ u8 oui[3]; } __attribute__ ((packed)); -struct dldwd_frame_hdr { - hermes_frame_desc_t desc; - struct p80211_hdr p80211; +struct orinoco_rxframe_hdr { + struct hermes_rx_descriptor desc; + struct ieee802_11_hdr p80211; struct ethhdr p8023; struct p8022_hdr p8022; u16 ethertype; } __attribute__ ((packed)); -#define P8023_OFFSET (sizeof(hermes_frame_desc_t) + \ - sizeof(struct p80211_hdr)) +struct orinoco_txframe_hdr { + struct hermes_tx_descriptor desc; + struct ieee802_11_hdr p80211; + struct ethhdr p8023; + struct p8022_hdr p8022; + u16 ethertype; +} __attribute__ ((packed)); + +#define P8023_OFFSET (sizeof(struct hermes_rx_descriptor) + \ + sizeof(struct ieee802_11_hdr)) #define ENCAPS_OVERHEAD (sizeof(struct p8022_hdr) + 2) /* 802.2 LLL header SNAP used for SNAP encapsulation over 802.11 */ @@ -343,114 +414,109 @@ 0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00} }; -struct p8022_hdr old_encaps_hdr = { - 0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8} -}; - -/* How many times to retry if we get an EIO reading the BAP in the Rx path */ -#define RX_EIO_RETRY 10 - -typedef struct dldwd_commsqual { +typedef struct orinoco_commsqual { u16 qual, signal, noise; -} __attribute__ ((packed)) dldwd_commsqual_t; +} __attribute__ ((packed)) orinoco_commsqual_t; /* * Function prototypes */ -static void dldwd_stat_gather(struct net_device *dev, +static void orinoco_stat_gather(struct net_device *dev, struct sk_buff *skb, - struct dldwd_frame_hdr *hdr); + struct orinoco_rxframe_hdr *hdr); -static struct net_device_stats *dldwd_get_stats(struct net_device *dev); -static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev); +static struct net_device_stats *orinoco_get_stats(struct net_device *dev); +static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev); /* Hardware control routines */ -static int __dldwd_hw_reset(dldwd_priv_t *priv); -static int __dldwd_hw_setup_wep(dldwd_priv_t *priv); -static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]); -static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]); -static long dldwd_hw_get_freq(dldwd_priv_t *priv); -static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, - s32 *rates, int max); +static int __orinoco_hw_reset(struct orinoco_private *priv); +static int __orinoco_hw_set_bitrate(struct orinoco_private *priv); +static int __orinoco_hw_setup_wep(struct orinoco_private *priv); +static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN]); +static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, + char buf[IW_ESSID_MAX_SIZE+1]); +static long orinoco_hw_get_freq(struct orinoco_private *priv); +static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, + int32_t *rates, int max); /* Interrupt handling routines */ -static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw); -static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw); - -static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq); -static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq); -static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq); -static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq); -static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq); -static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq); -static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq); -static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); -static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *frq); -static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq); -static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq); -static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq); -static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq); -static void __dldwd_set_multicast_list(struct net_device *dev); +static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw); + +static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq); +static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq); +static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq); +static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq); +static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq); +static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq); +static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq); +static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq); +static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq); +static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq); +static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); +static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq); +static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq); +static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *frq); +static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *frq); +static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq); +static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq); +static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq); +static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq); +static void __orinoco_set_multicast_list(struct net_device *dev); /* /proc debugging stuff */ -static int dldwd_proc_init(void); -static void dldwd_proc_cleanup(void); +static int orinoco_proc_init(void); +static void orinoco_proc_cleanup(void); /* * Inline functions */ static inline void -dldwd_lock(dldwd_priv_t *priv) +orinoco_lock(struct orinoco_private *priv) { spin_lock_bh(&priv->lock); } static inline void -dldwd_unlock(dldwd_priv_t *priv) +orinoco_unlock(struct orinoco_private *priv) { spin_unlock_bh(&priv->lock); } static inline int -dldwd_irqs_allowed(dldwd_priv_t *priv) +orinoco_irqs_allowed(struct orinoco_private *priv) { - return test_bit(DLDWD_STATE_DOIRQ, &priv->state); + return test_bit(ORINOCO_STATE_DOIRQ, &priv->state); } static inline void -__dldwd_stop_irqs(dldwd_priv_t *priv) +__orinoco_stop_irqs(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; hermes_set_irqmask(hw, 0); - clear_bit(DLDWD_STATE_DOIRQ, &priv->state); - while (test_bit(DLDWD_STATE_INIRQ, &priv->state)) + clear_bit(ORINOCO_STATE_DOIRQ, &priv->state); + while (test_bit(ORINOCO_STATE_INIRQ, &priv->state)) ; } static inline void -__dldwd_start_irqs(dldwd_priv_t *priv, u16 irqmask) +__orinoco_start_irqs(struct orinoco_private *priv, u16 irqmask) { hermes_t *hw = &priv->hw; TRACE_ENTER(priv->ndev.name); __cli(); - set_bit(DLDWD_STATE_DOIRQ, &priv->state); + set_bit(ORINOCO_STATE_DOIRQ, &priv->state); hermes_set_irqmask(hw, irqmask); __sti(); @@ -458,7 +524,7 @@ } static inline void -set_port_type(dldwd_priv_t *priv) +set_port_type(struct orinoco_private *priv) { switch (priv->iw_mode) { case IW_MODE_INFRA: @@ -481,13 +547,13 @@ } extern void -dldwd_set_multicast_list(struct net_device *dev) +orinoco_set_multicast_list(struct net_device *dev) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; - dldwd_lock(priv); - __dldwd_set_multicast_list(dev); - dldwd_unlock(priv); + orinoco_lock(priv); + __orinoco_set_multicast_list(dev); + orinoco_unlock(priv); } /* @@ -495,63 +561,54 @@ */ static int -__dldwd_hw_reset(dldwd_priv_t *priv) +__orinoco_hw_reset(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; - int err; - if (! priv->broken_reset) - return hermes_reset(hw); - else { - hw->inten = 0; - hermes_write_regn(hw, INTEN, 0); - err = hermes_disable_port(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); - return err; - } + return hermes_reset(hw); } void -dldwd_shutdown(dldwd_priv_t *priv) +orinoco_shutdown(struct orinoco_private *priv) { /* hermes_t *hw = &priv->hw; */ int err = 0; TRACE_ENTER(priv->ndev.name); - dldwd_lock(priv); - __dldwd_stop_irqs(priv); + orinoco_lock(priv); + __orinoco_stop_irqs(priv); - err = __dldwd_hw_reset(priv); + err = __orinoco_hw_reset(priv); if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */ printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev.name, err); - dldwd_unlock(priv); + orinoco_unlock(priv); TRACE_EXIT(priv->ndev.name); } int -dldwd_reset(dldwd_priv_t *priv) +orinoco_reset(struct orinoco_private *priv) { struct net_device *dev = &priv->ndev; hermes_t *hw = &priv->hw; int err = 0; - hermes_id_t idbuf; + struct hermes_idstring idbuf; int frame_size; TRACE_ENTER(priv->ndev.name); /* Stop other people bothering us */ - dldwd_lock(priv); - __dldwd_stop_irqs(priv); + orinoco_lock(priv); + __orinoco_stop_irqs(priv); /* Check if we need a card reset */ if((priv->need_card_reset) && (priv->card_reset_handler != NULL)) priv->card_reset_handler(priv); /* Do standard firmware reset if we can */ - err = __dldwd_hw_reset(priv); + err = __orinoco_hw_reset(priv); if (err) goto out; @@ -568,11 +625,11 @@ /* Set up the link mode */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type); + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, priv->port_type); if (err) goto out; if (priv->has_ibss) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS, + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFCREATEIBSS, priv->allow_ibss); if (err) goto out; @@ -588,7 +645,7 @@ /* Set up encryption */ if (priv->has_wep) { - err = __dldwd_hw_setup_wep(priv); + err = __orinoco_hw_setup_wep(priv); if (err) { printk(KERN_ERR "%s: Error %d activating WEP.\n", dev->name, err); @@ -600,7 +657,7 @@ idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); err = hermes_write_ltv(hw, USER_BAP, (priv->port_type == 3) ? - HERMES_RID_CNF_OWN_SSID : HERMES_RID_CNF_DESIRED_SSID, + HERMES_RID_CNFOWNSSID : HERMES_RID_CNFDESIREDSSID, HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), &idbuf); if (err) @@ -609,58 +666,62 @@ /* Set the station name */ idbuf.len = cpu_to_le16(strlen(priv->nick)); memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), &idbuf); if (err) goto out; /* Set the channel/frequency */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CHANNEL, priv->channel); + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, priv->channel); if (err) goto out; /* Set AP density */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, priv->ap_density); + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, priv->ap_density); if (err) goto out; /* Set RTS threshold */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, priv->rts_thresh); + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, priv->rts_thresh); if (err) goto out; /* Set fragmentation threshold or MWO robustness */ if (priv->has_mwo) err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNF_MWO_ROBUST, priv->mwo_robust); + HERMES_RID_CNFMWOROBUST_AGERE, + priv->mwo_robust); else err = hermes_write_wordrec(hw, USER_BAP, - HERMES_RID_CNF_FRAG_THRESH, priv->frag_thresh); + HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, + priv->frag_thresh); if (err) goto out; /* Set bitrate */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, - priv->tx_rate_ctrl); + err = __orinoco_hw_set_bitrate(priv); if (err) goto out; /* Set power management */ if (priv->has_pm) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, priv->pm_on); if (err) goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMULTICASTRECEIVE, priv->pm_mcast); if (err) goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, priv->pm_period); if (err) goto out; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMHOLDOVERDURATION, priv->pm_timeout); if (err) goto out; @@ -668,7 +729,8 @@ /* Set preamble - only for Symbol so far... */ if (priv->has_preamble) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPREAMBLE_SYMBOL, priv->preamble); if (err) { printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name); @@ -678,28 +740,62 @@ /* Set promiscuity / multicast*/ priv->promiscuous = 0; - priv->allmulti = 0; priv->mc_count = 0; - __dldwd_set_multicast_list(dev); - - err = hermes_enable_port(hw, DLDWD_MACPORT); - if (err) - goto out; + __orinoco_set_multicast_list(dev); - __dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | + __orinoco_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | HERMES_EV_TX | HERMES_EV_TXEXC | HERMES_EV_WTERR | HERMES_EV_INFO | HERMES_EV_INFDROP); + err = hermes_enable_port(hw, ORINOCO_MACPORT); + if (err) + goto out; + out: - dldwd_unlock(priv); + orinoco_unlock(priv); TRACE_EXIT(priv->ndev.name); return err; } -static int __dldwd_hw_setup_wep(dldwd_priv_t *priv) +static int __orinoco_hw_set_bitrate(struct orinoco_private *priv) +{ + hermes_t *hw = &priv->hw; + int err = 0; + + TRACE_ENTER(priv->ndev.name); + + if (priv->bitratemode >= BITRATE_TABLE_SIZE) { + printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", + priv->ndev.name, priv->bitratemode); + return -EINVAL; + } + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXRATECONTROL, + bitrate_table[priv->bitratemode].agere_txratectrl); + break; + case FIRMWARE_TYPE_INTERSIL: + case FIRMWARE_TYPE_SYMBOL: + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXRATECONTROL, + bitrate_table[priv->bitratemode].intersil_txratectrl); + break; + default: + BUG(); + } + + TRACE_EXIT(priv->ndev.name); + + return err; +} + + +static int __orinoco_hw_setup_wep(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; int err = 0; @@ -709,17 +805,23 @@ TRACE_ENTER(priv->ndev.name); switch (priv->firmware_type) { - case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */ + case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ if (priv->wep_on) { - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key); + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFTXKEY_AGERE, + priv->tx_key); if (err) return err; - err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys); + err = HERMES_WRITE_RECORD(hw, USER_BAP, + HERMES_RID_CNFWEPKEYS_AGERE, + &priv->keys); if (err) return err; } - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on); + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPENABLED_AGERE, + priv->wep_on); if (err) return err; break; @@ -728,15 +830,15 @@ case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ master_wep_flag = 0; /* Off */ if (priv->wep_on) { -/* int keylen; */ + int keylen; int i; /* Fudge around firmware weirdness */ -/* keylen = priv->keys[priv->tx_key].len; */ + keylen = le16_to_cpu(priv->keys[priv->tx_key].len); /* Write all 4 keys */ - for(i = 0; i < MAX_KEYS; i++) { - int keylen = le16_to_cpu(priv->keys[i].len); + for(i = 0; i < ORINOCO_MAX_KEYS; i++) { +/* int keylen = le16_to_cpu(priv->keys[i].len); */ if (keylen > LARGE_KEY_SIZE) { printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", @@ -747,7 +849,7 @@ printk("About to write key %d, keylen=%d\n", i, keylen); err = hermes_write_ltv(hw, USER_BAP, - HERMES_RID_CNF_INTERSIL_KEY0 + i, + HERMES_RID_CNFDEFAULTKEY0 + i, HERMES_BYTES_TO_RECLEN(keylen), priv->keys[i].data); if (err) @@ -755,7 +857,7 @@ } /* Write the index of the key used in transmission */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_INTERSIL_TX_KEY, + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFWEPDEFAULTKEYID, priv->tx_key); if (err) return err; @@ -771,7 +873,8 @@ auth_flag = 2; else auth_flag = 1; - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, auth_flag); + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFAUTHENTICATION, auth_flag); if (err) return err; /* Master WEP setting is always 3 */ @@ -787,7 +890,9 @@ } /* Master WEP setting : on/off */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_INTERSIL_WEP_ON, master_wep_flag); + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFWEPFLAGS_INTERSIL, + master_wep_flag); if (err) return err; @@ -806,48 +911,48 @@ return 0; } -static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]) +static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN]) { hermes_t *hw = &priv->hw; int err = 0; - dldwd_lock(priv); + orinoco_lock(priv); - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, ETH_ALEN, NULL, buf); - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, +static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]) { hermes_t *hw = &priv->hw; int err = 0; - hermes_id_t essidbuf; + struct hermes_idstring essidbuf; char *p = (char *)(&essidbuf.val); int len; TRACE_ENTER(priv->ndev.name); - dldwd_lock(priv); + orinoco_lock(priv); if (strlen(priv->desired_essid) > 0) { /* We read the desired SSID from the hardware rather than from priv->desired_essid, just in case the firmware is allowed to change it on us. I'm not sure about this */ - /* My guess is that the OWN_SSID should always be whatever + /* My guess is that the OWNSSID should always be whatever * we set to the card, whereas CURRENT_SSID is the one that * may change... - Jean II */ u16 rid; *active = 1; - rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID : - HERMES_RID_CNF_DESIRED_SSID; + rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : + HERMES_RID_CNFDESIREDSSID; err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), NULL, &essidbuf); @@ -856,7 +961,7 @@ } else { *active = 0; - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, sizeof(essidbuf), NULL, &essidbuf); if (err) goto fail_unlock; @@ -869,14 +974,14 @@ buf[len] = '\0'; fail_unlock: - dldwd_unlock(priv); + orinoco_unlock(priv); TRACE_EXIT(priv->ndev.name); return err; } -static long dldwd_hw_get_freq(dldwd_priv_t *priv) +static long orinoco_hw_get_freq(struct orinoco_private *priv) { hermes_t *hw = &priv->hw; @@ -884,9 +989,9 @@ u16 channel; long freq = 0; - dldwd_lock(priv); + orinoco_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel); if (err) goto out; @@ -901,27 +1006,27 @@ freq = channel_frequency[channel-1] * 100000; out: - dldwd_unlock(priv); + orinoco_unlock(priv); if (err > 0) err = -EBUSY; return err ? err : freq; } -static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, - s32 *rates, int max) +static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, + int32_t *rates, int max) { hermes_t *hw = &priv->hw; - hermes_id_t list; + struct hermes_idstring list; unsigned char *p = (unsigned char *)&list.val; int err = 0; int num; int i; - dldwd_lock(priv); - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_DATARATES, sizeof(list), - NULL, &list); - dldwd_unlock(priv); + orinoco_lock(priv); + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, + sizeof(list), NULL, &list); + orinoco_unlock(priv); if (err) return err; @@ -937,19 +1042,20 @@ return 0; } +#if 0 #ifndef ORINOCO_DEBUG -static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {} +static inline void show_rx_frame(struct orinoco_rxframe_hdr *frame) {} #else -static void show_rx_frame(struct dldwd_frame_hdr *frame) +static void show_rx_frame(struct orinoco_rxframe_hdr *frame) { printk(KERN_DEBUG "RX descriptor:\n"); printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); - printk(KERN_DEBUG " res1 = 0x%04x\n", frame->desc.res1); - printk(KERN_DEBUG " res2 = 0x%04x\n", frame->desc.res2); - printk(KERN_DEBUG " q_info = 0x%04x\n", frame->desc.q_info); - printk(KERN_DEBUG " res3 = 0x%04x\n", frame->desc.res3); - printk(KERN_DEBUG " res4 = 0x%04x\n", frame->desc.res4); - printk(KERN_DEBUG " tx_ctl = 0x%04x\n", frame->desc.tx_ctl); + printk(KERN_DEBUG " time = 0x%08x\n", frame->desc.time); + printk(KERN_DEBUG " silence = 0x%02x\n", frame->desc.silence); + printk(KERN_DEBUG " signal = 0x%02x\n", frame->desc.signal); + printk(KERN_DEBUG " rate = 0x%02x\n", frame->desc.rate); + printk(KERN_DEBUG " rxflow = 0x%02x\n", frame->desc.rxflow); + printk(KERN_DEBUG " reserved = 0x%08x\n", frame->desc.reserved); printk(KERN_DEBUG "IEEE 802.11 header:\n"); printk(KERN_DEBUG " frame_ctl = 0x%04x\n", @@ -997,96 +1103,99 @@ printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); } #endif +#endif /* * Interrupt handler */ -void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs) +void orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs) { - dldwd_priv_t *priv = (dldwd_priv_t *) dev_id; + struct orinoco_private *priv = (struct orinoco_private *) dev_id; hermes_t *hw = &priv->hw; struct net_device *dev = &priv->ndev; - int count = IRQ_LOOP_MAX; + int count = MAX_IRQLOOPS_PER_IRQ; u16 evstat, events; - static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */ + /* These are used to detect a runaway interrupt situation */ + /* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy, + * we panic and shut down the hardware */ + static int last_irq_jiffy = 0; /* jiffies value the last time we were called */ + static int loops_this_jiffy = 0; - if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state)) + if (test_and_set_bit(ORINOCO_STATE_INIRQ, &priv->state)) BUG(); - if (! dldwd_irqs_allowed(priv)) { - clear_bit(DLDWD_STATE_INIRQ, &priv->state); + if (! orinoco_irqs_allowed(priv)) { + clear_bit(ORINOCO_STATE_INIRQ, &priv->state); return; } - DEBUG(3, "%s: dldwd_interrupt()\n", priv->ndev.name); + DEBUG(3, "%s: orinoco_interrupt()\n", priv->ndev.name); - while (1) { - if (jiffies != old_time) - timecount = 0; - if ( (++timecount > 50) || (! count--) ) { + evstat = hermes_read_regn(hw, EVSTAT); + events = evstat & hw->inten; + + if (! events) { /* Sometimes the card generates Tx interrupts without setting EVSTAT, + or so I've heard - FIXME does it really happen? */ + printk(KERN_WARNING "%s: Null event in orinoco_interrupt!\n", priv->ndev.name); + __orinoco_ev_alloc(priv, hw); + } + + if (jiffies != last_irq_jiffy) + loops_this_jiffy = 0; + last_irq_jiffy = jiffies; + + while (events && count--) { + DEBUG(4, "__orinoco_interrupt(): count=%d EVSTAT=0x%04x\n", + count, evstat); + + if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { printk(KERN_CRIT "%s: IRQ handler is looping too \ much! Shutting down.\n", dev->name); /* Perform an emergency shutdown */ - clear_bit(DLDWD_STATE_DOIRQ, &priv->state); + clear_bit(ORINOCO_STATE_DOIRQ, &priv->state); hermes_set_irqmask(hw, 0); break; } - evstat = hermes_read_regn(hw, EVSTAT); - DEBUG(3, "__dldwd_interrupt(): count=%d EVSTAT=0x%04x inten=0x%04x\n", - count, evstat, hw->inten); - - events = evstat & hw->inten; - - if (! events) { - if (netif_queue_stopped(dev)) { - /* There seems to be a firmware bug which - sometimes causes the card to give an - interrupt with no event set, when there - sould be a Tx completed event. */ - DEBUG(3, "%s: Interrupt with no event (ALLOCFID=0x%04x)\n", - dev->name, (int)hermes_read_regn(hw, ALLOCFID)); - events = HERMES_EV_TX | HERMES_EV_ALLOC; - } else /* Nothing's happening, we're done */ - break; - } - /* Check the card hasn't been removed */ if (! hermes_present(hw)) { - DEBUG(0, "dldwd_interrupt(): card removed\n"); + DEBUG(0, "orinoco_interrupt(): card removed\n"); break; } if (events & HERMES_EV_TICK) - __dldwd_ev_tick(priv, hw); + __orinoco_ev_tick(priv, hw); if (events & HERMES_EV_WTERR) - __dldwd_ev_wterr(priv, hw); + __orinoco_ev_wterr(priv, hw); if (events & HERMES_EV_INFDROP) - __dldwd_ev_infdrop(priv, hw); + __orinoco_ev_infdrop(priv, hw); if (events & HERMES_EV_INFO) - __dldwd_ev_info(priv, hw); + __orinoco_ev_info(priv, hw); if (events & HERMES_EV_RX) - __dldwd_ev_rx(priv, hw); + __orinoco_ev_rx(priv, hw); if (events & HERMES_EV_TXEXC) - __dldwd_ev_txexc(priv, hw); + __orinoco_ev_txexc(priv, hw); if (events & HERMES_EV_TX) - __dldwd_ev_tx(priv, hw); + __orinoco_ev_tx(priv, hw); if (events & HERMES_EV_ALLOC) - __dldwd_ev_alloc(priv, hw); + __orinoco_ev_alloc(priv, hw); hermes_write_regn(hw, EVACK, events); - } - clear_bit(DLDWD_STATE_INIRQ, &priv->state); + evstat = hermes_read_regn(hw, EVSTAT); + events = evstat & hw->inten; + }; + + clear_bit(ORINOCO_STATE_INIRQ, &priv->state); } -static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw) { printk(KERN_DEBUG "%s: TICK\n", priv->ndev.name); } -static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw) { /* This seems to happen a fair bit under load, but ignoring it seems to work fine...*/ @@ -1094,53 +1203,111 @@ priv->ndev.name); } -static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw) { printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev.name); } -static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw) { - DEBUG(3, "%s: Information frame received.\n", priv->ndev.name); - /* We don't actually do anything about it - we assume the MAC - controller can deal with it */ + struct net_device *dev = &priv->ndev; + u16 infofid; + struct { + u16 len; + u16 type; + } __attribute__ ((packed)) info; + int err; + + /* This is an answer to an INQUIRE command that we did earlier, + * or an information "event" generated by the card + * The controller return to us a pseudo frame containing + * the information in question - Jean II */ + infofid = hermes_read_regn(hw, INFOFID); + DEBUG(3, "%s: __dldwd_ev_info(): INFOFID=0x%04x\n", dev->name, + infofid); + + /* Read the info frame header - don't try too hard */ + err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info), + infofid, 0); + if (err) { + printk(KERN_ERR "%s: error %d reading info frame. " + "Frame dropped.\n", dev->name, err); + return; + } + + switch (le16_to_cpu(info.type)) { + case HERMES_INQ_TALLIES: { + struct hermes_tallies_frame tallies; + struct iw_statistics *wstats = &priv->wstats; + int len = le16_to_cpu(info.len) - 1; + + if (len > (sizeof(tallies) / 2)) { + DEBUG(1, "%s: tallies frame too long.\n", dev->name); + len = sizeof(tallies) / 2; + } + + /* Read directly the data (no seek) */ + hermes_read_words(hw, HERMES_DATA1, (void *) &tallies, len); + + /* Increment our various counters */ + /* wstats->discard.nwid - no wrong BSSID stuff */ + wstats->discard.code += + le16_to_cpu(tallies.RxWEPUndecryptable); + if (len == (sizeof(tallies) / 2)) + wstats->discard.code += + le16_to_cpu(tallies.RxDiscards_WEPICVError) + + le16_to_cpu(tallies.RxDiscards_WEPExcluded); + wstats->discard.misc += + le16_to_cpu(tallies.TxDiscardsWrongSA); +#if WIRELESS_EXT > 11 + wstats->discard.fragment += + le16_to_cpu(tallies.RxMsgInBadMsgFragments); + wstats->discard.retries += + le16_to_cpu(tallies.TxRetryLimitExceeded); + /* wstats->miss.beacon - no match */ +#if ORINOCO_DEBUG > 3 + /* Hack for debugging - should not be taken as an example */ + wstats->discard.nwid += le16_to_cpu(tallies.TxUnicastFrames); + wstats->miss.beacon += le16_to_cpu(tallies.RxUnicastFrames); +#endif +#endif /* WIRELESS_EXT > 11 */ + } + break; + default: + DEBUG(1, "%s: Unknown information frame received (type %04x).\n", + priv->ndev.name, le16_to_cpu(info.type)); + /* We don't actually do anything about it */ + break; + } } -static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw) { struct net_device *dev = &priv->ndev; struct net_device_stats *stats = &priv->stats; struct iw_statistics *wstats = &priv->wstats; struct sk_buff *skb = NULL; - int l = RX_EIO_RETRY; u16 rxfid, status; int length, data_len, data_off; char *p; - struct dldwd_frame_hdr hdr; + struct orinoco_rxframe_hdr hdr; struct ethhdr *eh; int err; rxfid = hermes_read_regn(hw, RXFID); - DEBUG(3, "__dldwd_ev_rx(): RXFID=0x%04x\n", rxfid); + DEBUG(3, "__orinoco_ev_rx(): RXFID=0x%04x\n", rxfid); /* We read in the entire frame header here. This isn't really necessary, since we ignore most of it, but it's conceptually simpler. We can tune this later if necessary. */ - do { - err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), - rxfid, 0); - } while ( (err == -EIO) && (--l) ); + err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0); if (err) { - if (err == -EIO) - DEBUG(1, "%s: EIO reading frame header.\n", dev->name); - else - printk(KERN_ERR "%s: error %d reading frame header. " - "Frame dropped.\n", dev->name, err); + printk(KERN_ERR "%s: error %d reading frame header. " + "Frame dropped.\n", dev->name, err); stats->rx_errors++; goto drop; } - DEBUG(2, "%s: BAP read suceeded: l=%d\n", dev->name, l); status = le16_to_cpu(hdr.desc.status); @@ -1148,7 +1315,6 @@ if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) { stats->rx_crc_errors++; DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); - show_rx_frame(&hdr); } else if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_UNDECRYPTABLE) { wstats->discard.code++; @@ -1228,10 +1394,8 @@ } p = skb_put(skb, data_len); - do { - err = hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), - rxfid, data_off); - } while ( (err == -EIO) && (--l) ); + err = hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), + rxfid, data_off); if (err) { if (err == -EIO) DEBUG(1, "%s: EIO reading frame header.\n", dev->name); @@ -1241,7 +1405,6 @@ stats->rx_errors++; goto drop; } - DEBUG(2, "%s: BAP read suceeded: l=%d\n", dev->name, l); dev->last_rx = jiffies; skb->dev = dev; @@ -1249,10 +1412,11 @@ skb->ip_summed = CHECKSUM_NONE; /* Process the wireless stats if needed */ - dldwd_stat_gather(dev, skb, &hdr); + orinoco_stat_gather(dev, skb, &hdr); /* Pass the packet to the networking stack */ netif_rx(skb); + dev->last_rx = jiffies; stats->rx_packets++; stats->rx_bytes += length; @@ -1264,45 +1428,77 @@ return; } -static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw) { struct net_device *dev = &priv->ndev; struct net_device_stats *stats = &priv->stats; + u16 fid = hermes_read_regn(hw, TXCOMPLFID); + struct hermes_tx_descriptor desc; + int err = 0; - printk(KERN_WARNING "%s: Tx error!\n", dev->name); + if (fid == DUMMY_FID) + return; /* Nothing's really happened */ - netif_wake_queue(dev); + err = hermes_bap_pread(hw, USER_BAP, &desc, sizeof(desc), fid, 0); + if (err) { + printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " + "(FID=%04X error %d)\n", + dev->name, fid, err); + } else { + printk(KERN_INFO "%s: Tx error, status %d (FID=%04X)\n", + dev->name, le16_to_cpu(desc.status), fid); + } + stats->tx_errors++; + netif_wake_queue(dev); + + hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); } -static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw) { struct net_device *dev = &priv->ndev; struct net_device_stats *stats = &priv->stats; +/* u16 fid = hermes_read_regn(hw, TXCOMPLFID); */ + + /* We don't generally use the Tx event (to cut down on + interrupts) - we do the transmit complet processing once + the transmit buffer is reclaimed in __orinoco_ev_alloc() , + hence nothing here */ - DEBUG(3, "%s: Transmit completed\n", dev->name); +/* DEBUG(2, "%s: Transmit completed (FID=%04X)\n", priv->ndev.name, fid); */ stats->tx_packets++; netif_wake_queue(dev); + + hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); } -static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw) +static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw) { - u16 allocfid; + struct net_device *dev = &priv->ndev; + u16 fid = hermes_read_regn(hw, ALLOCFID); - allocfid = hermes_read_regn(hw, ALLOCFID); - DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid); + DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, fid); - /* For some reason we don't seem to get transmit completed events properly */ - if (allocfid == priv->txfid) - __dldwd_ev_tx(priv, hw); + /* We don't generally request Tx complete events to cut down + on the number of interrupts, so we do trasmit complete + processing here, which happens once the firmware is done + with the transmit buffer */ + + if (fid != priv->txfid) { + if (fid != DUMMY_FID) + printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", + dev->name, fid); + return; + } -/* hermes_write_regn(hw, ALLOCFID, 0); */ + hermes_write_regn(hw, ALLOCFID, DUMMY_FID); } static void determine_firmware(struct net_device *dev) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err; struct sta_id { @@ -1311,8 +1507,7 @@ u32 firmver; /* Get the firmware version */ - err = HERMES_READ_RECORD(hw, USER_BAP, - HERMES_RID_STAIDENTITY, &sta_id); + err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); if (err) { printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", dev->name, err); @@ -1338,10 +1533,8 @@ "version %d.%02d\n", dev->name, sta_id.major, sta_id.minor); - priv->firmware_type = FIRMWARE_TYPE_LUCENT; - priv->tx_rate_ctrl = 0x3; /* 11 Mb/s auto */ + priv->firmware_type = FIRMWARE_TYPE_AGERE; priv->need_card_reset = 0; - priv->broken_reset = 0; priv->broken_allocate = 0; priv->has_port3 = 1; /* Still works in 7.28 */ priv->has_ibss = (firmver >= 0x60006); @@ -1353,7 +1546,7 @@ priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ priv->has_preamble = 0; priv->ibss_port = 1; - /* Tested with Lucent firmware : + /* Tested with Agere firmware : * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II * Tested CableTron firmware : 4.32 => Anton */ } else if ((sta_id.vendor == 2) && @@ -1365,7 +1558,8 @@ memset(tmp, 0, sizeof(tmp)); /* Get the Symbol firmware version */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SYMBOL_SECONDARY_VER, + err = hermes_read_ltv(hw, USER_BAP, + HERMES_RID_SECONDARYVERSION_SYMBOL, SYMBOL_MAX_VER_LEN, NULL, &tmp); if (err) { printk(KERN_WARNING @@ -1390,9 +1584,7 @@ tmp, firmver); priv->firmware_type = FIRMWARE_TYPE_SYMBOL; - priv->tx_rate_ctrl = 0xF; /* 11 Mb/s auto */ priv->need_card_reset = 1; - priv->broken_reset = 0; priv->broken_allocate = 1; priv->has_port3 = 1; priv->has_ibss = (firmver >= 0x20000); @@ -1415,9 +1607,7 @@ sta_id.major, sta_id.minor); priv->firmware_type = FIRMWARE_TYPE_INTERSIL; - priv->tx_rate_ctrl = 0xF; /* 11 Mb/s auto */ priv->need_card_reset = 0; - priv->broken_reset = 0; priv->broken_allocate = 0; priv->has_port3 = 1; priv->has_ibss = (firmver >= 0x00007); /* FIXME */ @@ -1431,7 +1621,7 @@ priv->ibss_port = 0; else { printk(KERN_NOTICE "%s: Intersil firmware earlier " - "than v0.08 - several features not supported.", + "than v0.08 - several features not supported\n", dev->name); priv->ibss_port = 1; } @@ -1443,18 +1633,18 @@ */ int -dldwd_init(struct net_device *dev) +orinoco_init(struct net_device *dev) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; - hermes_id_t nickbuf; + struct hermes_idstring nickbuf; u16 reclen; int len; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); - dldwd_lock(priv); + orinoco_lock(priv); /* Do standard firmware reset */ err = hermes_reset(hw); @@ -1467,20 +1657,20 @@ determine_firmware(dev); if (priv->has_port3) - printk(KERN_DEBUG "%s: Ad-hoc demo mode supported.\n", dev->name); + printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name); if (priv->has_ibss) - printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported.\n", + printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n", dev->name); if (priv->has_wep) { printk(KERN_DEBUG "%s: WEP supported, ", dev->name); if (priv->has_big_wep) - printk("\"128\"-bit key.\n"); + printk("104-bit key\n"); else - printk("40-bit key.\n"); + printk("40-bit key\n"); } /* Get the MAC address */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, ETH_ALEN, NULL, dev->dev_addr); if (err) { printk(KERN_WARNING "%s: failed to read MAC address!\n", @@ -1494,15 +1684,15 @@ dev->dev_addr[5]); /* Get the station name */ - err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, sizeof(nickbuf), &reclen, &nickbuf); if (err) { - printk(KERN_ERR "%s: failed to read station name!n", + printk(KERN_ERR "%s: failed to read station name\n", dev->name); goto out; } if (nickbuf.len) - len = min_t(u16, IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len)); + len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); else len = min(IW_ESSID_MAX_SIZE, 2 * reclen); memcpy(priv->nick, &nickbuf.val, len); @@ -1511,7 +1701,8 @@ printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick); /* Get allowed channels */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNEL_LIST, &priv->channel_mask); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST, + &priv->channel_mask); if (err) { printk(KERN_ERR "%s: failed to read channel list!\n", dev->name); @@ -1519,14 +1710,15 @@ } /* Get initial AP density */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &priv->ap_density); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, &priv->ap_density); if (err) { printk(KERN_ERR "%s: failed to read AP density!\n", dev->name); goto out; } /* Get initial RTS threshold */ - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, &priv->rts_thresh); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, + &priv->rts_thresh); if (err) { printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name); goto out; @@ -1534,10 +1726,11 @@ /* Get initial fragmentation settings */ if (priv->has_mwo) - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMWOROBUST_AGERE, &priv->mwo_robust); else - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, &priv->frag_thresh); if (err) { printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name); @@ -1548,14 +1741,16 @@ if (priv->has_pm) { priv->pm_on = 0; priv->pm_mcast = 1; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, &priv->pm_period); if (err) { printk(KERN_ERR "%s: failed to read power management period!\n", dev->name); goto out; } - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFPMHOLDOVERDURATION, &priv->pm_timeout); if (err) { printk(KERN_ERR "%s: failed to read power management timeout!\n", @@ -1566,7 +1761,8 @@ /* Preamble setup */ if (priv->has_preamble) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, &priv->preamble); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPREAMBLE_SYMBOL, + &priv->preamble); if (err) goto out; } @@ -1578,55 +1774,52 @@ set_port_type(priv); priv->promiscuous = 0; - priv->allmulti = 0; priv->wep_on = 0; priv->tx_key = 0; printk(KERN_DEBUG "%s: ready\n", dev->name); out: - dldwd_unlock(priv); + orinoco_unlock(priv); - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); return err; } struct net_device_stats * -dldwd_get_stats(struct net_device *dev) +orinoco_get_stats(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; return &priv->stats; } struct iw_statistics * -dldwd_get_wireless_stats(struct net_device *dev) +orinoco_get_wireless_stats(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; hermes_t *hw = &priv->hw; struct iw_statistics *wstats = &priv->wstats; int err = 0; - if (!priv->hw_ready) - return NULL; + if (! netif_device_present(dev)) + return NULL; /* FIXME: We may be able to do better than this */ - dldwd_lock(priv); + orinoco_lock(priv); if (priv->iw_mode == IW_MODE_ADHOC) { memset(&wstats->qual, 0, sizeof(wstats->qual)); -#ifdef WIRELESS_SPY /* If a spy address is defined, we report stats of the * first spy address - Jean II */ - if (priv->spy_number > 0) { + if (SPY_NUMBER(priv)) { wstats->qual.qual = priv->spy_stat[0].qual; wstats->qual.level = priv->spy_stat[0].level; wstats->qual.noise = priv->spy_stat[0].noise; wstats->qual.updated = priv->spy_stat[0].updated; } -#endif /* WIRELESS_SPY */ } else { - dldwd_commsqual_t cq; + orinoco_commsqual_t cq; err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_COMMSQUALITY, &cq); @@ -1640,7 +1833,14 @@ wstats->qual.updated = 7; } - dldwd_unlock(priv); + /* We can't really wait for the tallies inquiry command to + * complete, so we just use the previous results and trigger + * a new tallies inquiry command for next time - Jean II */ + /* FIXME: Hmm.. seems a bit ugly, I wonder if there's a way to + do better - dgibson */ + err = hermes_inquire(hw, HERMES_INQ_TALLIES); + + orinoco_unlock(priv); if (err) return NULL; @@ -1648,11 +1848,10 @@ return wstats; } -#ifdef WIRELESS_SPY -static inline void dldwd_spy_gather(struct net_device *dev, u_char *mac, +static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, int level, int noise) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; int i; /* Gather wireless spy statistics: for each packet, compare the @@ -1665,14 +1864,13 @@ priv->spy_stat[i].updated = 7; } } -#endif /* WIRELESS_SPY */ void -dldwd_stat_gather( struct net_device *dev, +orinoco_stat_gather( struct net_device *dev, struct sk_buff *skb, - struct dldwd_frame_hdr *hdr) + struct orinoco_rxframe_hdr *hdr) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; /* Using spy support with lots of Rx packets, like in an * infrastructure (AP), will really slow down everything, because @@ -1682,24 +1880,18 @@ * Note that to get here, you need both WIRELESS_SPY * compiled in AND some addresses in the list !!! */ -#ifdef WIRELESS_SPY /* Note : gcc will optimise the whole section away if * WIRELESS_SPY is not defined... - Jean II */ - if (priv->spy_number > 0) { - u8 *stats = (u8 *) &(hdr->desc.q_info); - /* This code may look strange. Everywhere we are using 16 bit - * ints except here. I've verified that these are are the - * correct values. Please check on PPC - Jean II */ - - dldwd_spy_gather(dev, skb->mac.raw + ETH_ALEN, (int)stats[1], (int)stats[0]); + if (SPY_NUMBER(priv)) { + orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN, + hdr->desc.signal, hdr->desc.silence); } -#endif /* WIRELESS_SPY */ } int -dldwd_xmit(struct sk_buff *skb, struct net_device *dev) +orinoco_xmit(struct sk_buff *skb, struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; struct net_device_stats *stats = &priv->stats; hermes_t *hw = &priv->hw; int err = 0; @@ -1707,7 +1899,7 @@ char *p; struct ethhdr *eh; int len, data_len, data_off; - struct dldwd_frame_hdr hdr; + struct orinoco_txframe_hdr hdr; hermes_response_t resp; if (! netif_running(dev)) { @@ -1723,9 +1915,10 @@ return 1; } - dldwd_lock(priv); + orinoco_lock(priv); /* Length of the packet body */ + /* FIXME: what if the skb is smaller than this? */ len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN); eh = (struct ethhdr *)skb->data; @@ -1734,7 +1927,11 @@ memset(&hdr, 0, sizeof(hdr)); memcpy(hdr.p80211.addr1, eh->h_dest, ETH_ALEN); memcpy(hdr.p80211.addr2, eh->h_source, ETH_ALEN); - hdr.p80211.frame_ctl = DLDWD_FTYPE_DATA; + hdr.p80211.frame_ctl = IEEE802_11_FTYPE_DATA; + + /* Request an interrupt on Tx failures, but not sucesses (we + use the buffer reclaim allocation event instead */ + hdr.desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_EX | HERMES_TXCTRL_TX_OK); /* Encapsulate Ethernet-II frames */ if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ @@ -1751,24 +1948,12 @@ hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD); /* 802.2 header */ - if (! use_old_encaps) - memcpy(&hdr.p8022, &encaps_hdr, - sizeof(encaps_hdr)); - else - memcpy(&hdr.p8022, &encaps_hdr, - sizeof(old_encaps_hdr)); + memcpy(&hdr.p8022, &encaps_hdr, sizeof(encaps_hdr)); hdr.ethertype = eh->h_proto; err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), txfid, 0); if (err) { - if (err == -EIO) - /* We get these errors reported by the - firmware every so often apparently at - random. Let the upper layers - handle the retry */ - DEBUG(1, "%s: DEBUG: EIO writing packet header to BAP\n", dev->name); - else printk(KERN_ERR "%s: Error %d writing packet header to BAP\n", dev->name, err); stats->tx_errors++; @@ -1795,11 +1980,8 @@ /* Round up for odd length packets */ err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); if (err) { - if (err == -EIO) - DEBUG(1, "%s: DEBUG: EIO writing packet header to BAP\n", dev->name); - else - printk(KERN_ERR "%s: Error %d writing packet header to BAP", - dev->name, err); + printk(KERN_ERR "%s: Error %d writing packet header to BAP\n", + dev->name, err); stats->tx_errors++; goto fail; } @@ -1812,26 +1994,27 @@ goto fail; } + atomic_inc(&priv->queue_length); dev->trans_start = jiffies; stats->tx_bytes += data_off + data_len; netif_stop_queue(dev); - dldwd_unlock(priv); + orinoco_unlock(priv); dev_kfree_skb(skb); return 0; fail: - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } void -dldwd_tx_timeout(struct net_device *dev) +orinoco_tx_timeout(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; struct net_device_stats *stats = &priv->stats; int err = 0; @@ -1839,7 +2022,7 @@ stats->tx_errors++; - err = dldwd_reset(priv); + err = orinoco_reset(priv); if (err) printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", dev->name, err); @@ -1849,9 +2032,9 @@ } } -static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) +static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int err = 0; int mode; struct iw_range range; @@ -1866,9 +2049,9 @@ rrq->length = sizeof(range); - dldwd_lock(priv); + orinoco_lock(priv); mode = priv->iw_mode; - dldwd_unlock(priv); + orinoco_unlock(priv); memset(&range, 0, sizeof(range)); @@ -1904,13 +2087,25 @@ range.max_qual.qual = 0; range.max_qual.level = 0; range.max_qual.noise = 0; +#if WIRELESS_EXT > 11 + range.avg_qual.qual = 0; + range.avg_qual.level = 0; + range.avg_qual.noise = 0; +#endif /* WIRELESS_EXT > 11 */ + } else { range.max_qual.qual = 0x8b - 0x2f; range.max_qual.level = 0x2f - 0x95 - 1; range.max_qual.noise = 0x2f - 0x95 - 1; +#if WIRELESS_EXT > 11 + /* Need to get better values */ + range.avg_qual.qual = 0x24; + range.avg_qual.level = 0xC2; + range.avg_qual.noise = 0x9E; +#endif /* WIRELESS_EXT > 11 */ } - err = dldwd_hw_get_bitratelist(priv, &numrates, + err = orinoco_hw_get_bitratelist(priv, &numrates, range.bitrate, IW_MAX_BITRATES); if (err) return err; @@ -1929,9 +2124,9 @@ range.min_frag = 256; range.max_frag = 2346; - dldwd_lock(priv); + orinoco_lock(priv); if (priv->has_wep) { - range.max_encoding_tokens = MAX_KEYS; + range.max_encoding_tokens = ORINOCO_MAX_KEYS; range.encoding_size[0] = SMALL_KEY_SIZE; range.num_encoding_sizes = 1; @@ -1944,7 +2139,7 @@ range.num_encoding_sizes = 0; range.max_encoding_tokens = 0; } - dldwd_unlock(priv); + orinoco_unlock(priv); range.min_pmp = 0; range.max_pmp = 65535000; @@ -1976,30 +2171,30 @@ return 0; } -static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) +static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int index = (erq->flags & IW_ENCODE_INDEX) - 1; int setindex = priv->tx_key; int enable = priv->wep_on; int restricted = priv->wep_restrict; u16 xlen = 0; int err = 0; - char keybuf[MAX_KEY_SIZE]; + char keybuf[ORINOCO_MAX_KEY_SIZE]; if (erq->pointer) { /* We actually have a key to set */ - if ( (erq->length < SMALL_KEY_SIZE) || (erq->length > MAX_KEY_SIZE) ) + if ( (erq->length < SMALL_KEY_SIZE) || (erq->length > ORINOCO_MAX_KEY_SIZE) ) return -EINVAL; if (copy_from_user(keybuf, erq->pointer, erq->length)) return -EFAULT; } - dldwd_lock(priv); + orinoco_lock(priv); if (erq->pointer) { - if (erq->length > MAX_KEY_SIZE) { + if (erq->length > ORINOCO_MAX_KEY_SIZE) { err = -E2BIG; goto out; } @@ -2010,7 +2205,7 @@ goto out; } - if ((index < 0) || (index >= MAX_KEYS)) + if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) index = priv->tx_key; if (erq->length > SMALL_KEY_SIZE) { @@ -2029,7 +2224,7 @@ /* Important note : if the user do "iwconfig eth0 enc off", * we will arrive there with an index of -1. This is valid * but need to be taken care off... Jean II */ - if ((index < 0) || (index >= MAX_KEYS)) { + if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) { if((index != -1) || (erq->flags == 0)) { err = -EINVAL; goto out; @@ -2062,22 +2257,22 @@ priv->wep_restrict = restricted; out: - dldwd_unlock(priv); + orinoco_unlock(priv); - return 0; + return err; } -static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) +static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int index = (erq->flags & IW_ENCODE_INDEX) - 1; u16 xlen = 0; - char keybuf[MAX_KEY_SIZE]; + char keybuf[ORINOCO_MAX_KEY_SIZE]; - dldwd_lock(priv); + orinoco_lock(priv); - if ((index < 0) || (index >= MAX_KEYS)) + if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) index = priv->tx_key; erq->flags = 0; @@ -2086,7 +2281,7 @@ erq->flags |= index + 1; /* Only for symbol cards - Jean II */ - if (priv->firmware_type != FIRMWARE_TYPE_LUCENT) { + if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { if(priv->wep_restrict) erq->flags |= IW_ENCODE_RESTRICTED; else @@ -2098,10 +2293,10 @@ erq->length = xlen; if (erq->pointer) { - memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE); + memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); } - dldwd_unlock(priv); + orinoco_unlock(priv); if (erq->pointer) { if (copy_to_user(erq->pointer, keybuf, xlen)) @@ -2111,9 +2306,9 @@ return 0; } -static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq) +static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; char essidbuf[IW_ESSID_MAX_SIZE+1]; /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it @@ -2131,25 +2326,25 @@ essidbuf[erq->length] = '\0'; } - dldwd_lock(priv); + orinoco_lock(priv); memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid)); - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq) +static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; char essidbuf[IW_ESSID_MAX_SIZE+1]; int active; int err = 0; TRACE_ENTER(dev->name); - err = dldwd_hw_get_essid(priv, &active, essidbuf); + err = orinoco_hw_get_essid(priv, &active, essidbuf); if (err) return err; @@ -2164,9 +2359,9 @@ return 0; } -static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) +static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; char nickbuf[IW_ESSID_MAX_SIZE+1]; if (nrq->length > IW_ESSID_MAX_SIZE) @@ -2179,23 +2374,23 @@ nickbuf[nrq->length] = '\0'; - dldwd_lock(priv); + orinoco_lock(priv); memcpy(priv->nick, nickbuf, sizeof(priv->nick)); - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) +static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; char nickbuf[IW_ESSID_MAX_SIZE+1]; - dldwd_lock(priv); + orinoco_lock(priv); memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1); - dldwd_unlock(priv); + orinoco_unlock(priv); nrq->length = strlen(nickbuf)+1; @@ -2205,9 +2400,9 @@ return 0; } -static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) +static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int chan = -1; /* We can only use this in Ad-Hoc demo mode to set the operating @@ -2236,23 +2431,23 @@ ! (priv->channel_mask & (1 << (chan-1)) ) ) return -EINVAL; - dldwd_lock(priv); + orinoco_lock(priv); priv->channel = chan; - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq) +static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; u16 val; int err; - dldwd_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val); - dldwd_unlock(priv); + orinoco_lock(priv); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, &val); + orinoco_unlock(priv); if (err) return err; @@ -2263,24 +2458,24 @@ return 0; } -static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq) +static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int val = srq->value; if ((val < 1) || (val > 3)) return -EINVAL; - dldwd_lock(priv); + orinoco_lock(priv); priv->ap_density = val; - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) +static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int val = rrq->value; if (rrq->disabled) @@ -2289,19 +2484,19 @@ if ( (val < 0) || (val > 2347) ) return -EINVAL; - dldwd_lock(priv); + orinoco_lock(priv); priv->rts_thresh = val; - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) +static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int err = 0; - dldwd_lock(priv); + orinoco_lock(priv); if (priv->has_mwo) { if (frq->disabled) @@ -2323,22 +2518,24 @@ } } - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) +static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; u16 val; - dldwd_lock(priv); + orinoco_lock(priv); if (priv->has_mwo) { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val); + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMWOROBUST_AGERE, + &val); if (err) val = 0; @@ -2346,7 +2543,8 @@ frq->disabled = ! val; frq->fixed = 0; } else { - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, + &val); if (err) val = 0; @@ -2355,158 +2553,122 @@ frq->fixed = 1; } - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) +static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int err = 0; - int rate_ctrl = -1; - int fixed, upto; - int brate; + int ratemode = -1; + int bitrate; /* 100s of kilobits */ int i; + + /* As the user space doesn't know our highest rate, it uses -1 + * to ask us to set the highest rate. Test it using "iwconfig + * ethX rate auto" - Jean II */ + if (rrq->value == -1) + bitrate = 110; + else { + if (rrq->value % 100000) + return -EINVAL; + bitrate = rrq->value / 100000; + } - dldwd_lock(priv); - - /* Normalise value */ - brate = rrq->value / 500000; + if ( (bitrate != 10) && (bitrate != 20) && + (bitrate != 55) && (bitrate != 110) ) + return -EINVAL; - switch (priv->firmware_type) { - case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ - if (! rrq->fixed) { - if (brate > 0) - brate = -brate; - else - brate = -22; - } - - for (i = 0; i < NUM_RATES; i++) - if (rate_list[i] == brate) { - rate_ctrl = i; - break; - } - - if ( (rate_ctrl < 1) || (rate_ctrl >= NUM_RATES) ) - err = -EINVAL; - else - priv->tx_rate_ctrl = rate_ctrl; - break; - case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ - switch(brate) { - case 0: - fixed = 0x0; - upto = 0xF; - break; - case 2: - fixed = 0x1; - upto = 0x1; - break; - case 4: - fixed = 0x2; - upto = 0x3; - break; - case 11: - fixed = 0x4; - upto = 0x7; - break; - case 22: - fixed = 0x8; - upto = 0xF; + for (i = 0; i < BITRATE_TABLE_SIZE; i++) + if ( (bitrate_table[i].bitrate == bitrate) && + (bitrate_table[i].automatic == ! rrq->fixed) ) { + ratemode = i; break; - default: - fixed = 0x0; - upto = 0x0; } - if (rrq->fixed) - rate_ctrl = fixed; - else - rate_ctrl = upto; - if (rate_ctrl == 0) - err = -EINVAL; - else - priv->tx_rate_ctrl = rate_ctrl; - break; - } + + if (ratemode == -1) + return -EINVAL; - dldwd_unlock(priv); + orinoco_lock(priv); + priv->bitratemode = ratemode; + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) +static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; + int ratemode; + int i; u16 val; - int brate = 0; - dldwd_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, &val); - if (err) - goto out; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ - brate = rate_list[val]; - - if (brate < 0) { - rrq->fixed = 0; + orinoco_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); - if (err) - goto out; + ratemode = priv->bitratemode; + + if ( (ratemode < 0) || (ratemode > BITRATE_TABLE_SIZE) ) + BUG(); + + rrq->value = bitrate_table[ratemode].bitrate * 100000; + rrq->fixed = ! bitrate_table[ratemode].automatic; + rrq->disabled = 0; + /* If the interface is running we try to find more about the + current mode */ + if (netif_running(dev)) { + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CURRENTTXRATE, &val); + if (err) + goto out; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: /* Lucent style rate */ + /* Note : in Lucent firmware, the return value of + * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s, + * and therefore is totally different from the + * encoding of HERMES_RID_CNFTXRATECONTROL. + * Don't forget that 6Mb/s is really 5.5Mb/s */ if (val == 6) - brate = 11; + rrq->value = 5500000; else - brate = 2*val; - } else - rrq->fixed = 1; - break; - case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ - case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ - /* Check if auto or fixed (crude approximation) */ - if((val & 0x1) && (val > 1)) { - rrq->fixed = 0; - - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); - if (err) - goto out; - } else - rrq->fixed = 1; + rrq->value = val * 1000000; + break; + case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ + for (i = 0; i < BITRATE_TABLE_SIZE; i++) + if (bitrate_table[i].intersil_txratectrl == val) { + ratemode = i; + break; + } + if (i >= BITRATE_TABLE_SIZE) + printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n", + dev->name, val); - if(val >= 8) - brate = 22; - else if(val >= 4) - brate = 11; - else if(val >= 2) - brate = 4; - else - brate = 2; - break; + rrq->value = bitrate_table[ratemode].bitrate * 100000; + break; + default: + BUG(); + } } - rrq->value = brate * 500000; - rrq->disabled = 0; - out: - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq) +static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int err = 0; - dldwd_lock(priv); + orinoco_lock(priv); if (prq->disabled) { priv->pm_on = 0; @@ -2546,33 +2708,34 @@ } out: - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq) +static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; u16 enable, period, timeout, mcast; - dldwd_lock(priv); + orinoco_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, &enable); if (err) goto out; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period); + err = hermes_read_wordrec(hw, USER_BAP, + HERMES_RID_CNFMAXSLEEPDURATION, &period); if (err) goto out; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, &timeout); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, &timeout); if (err) goto out; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFMULTICASTRECEIVE, &mcast); if (err) goto out; @@ -2591,30 +2754,33 @@ prq->flags |= IW_POWER_UNICAST_R; out: - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } #if WIRELESS_EXT > 10 -static int dldwd_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) +static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; u16 short_limit, long_limit, lifetime; - dldwd_lock(priv); + orinoco_lock(priv); - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &short_limit); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT, + &short_limit); if (err) goto out; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &long_limit); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT, + &long_limit); if (err) goto out; - err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &lifetime); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME, + &lifetime); if (err) goto out; @@ -2638,46 +2804,46 @@ } out: - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } #endif /* WIRELESS_EXT > 10 */ -static int dldwd_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq) +static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int val = *( (int *) wrq->u.name ); - dldwd_lock(priv); + orinoco_lock(priv); priv->ibss_port = val ; /* Actually update the mode we are using */ set_port_type(priv); - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq) +static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int *val = (int *)wrq->u.name; - dldwd_lock(priv); + orinoco_lock(priv); *val = priv->ibss_port; - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } -static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) +static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int val = *( (int *) wrq->u.name ); int err = 0; - dldwd_lock(priv); + orinoco_lock(priv); switch (val) { case 0: /* Try to do IEEE ad-hoc mode */ if (! priv->has_ibss) { @@ -2706,28 +2872,28 @@ /* Actually update the mode we are using */ set_port_type(priv); - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) +static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; int *val = (int *)wrq->u.name; - dldwd_lock(priv); + orinoco_lock(priv); *val = priv->prefer_port3; - dldwd_unlock(priv); + orinoco_unlock(priv); return 0; } /* Spy is used for link quality/strength measurements in Ad-Hoc mode * Jean II */ -static int dldwd_ioctl_setspy(struct net_device *dev, struct iw_point *srq) +static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; struct sockaddr address[IW_MAX_SPY]; int number = srq->length; int i; @@ -2745,9 +2911,9 @@ } /* Make sure nobody mess with the structure while we do */ - dldwd_lock(priv); + orinoco_lock(priv); - /* dldwd_lock() doesn't disable interrupts, so make sure the + /* orinoco_lock() doesn't disable interrupts, so make sure the * interrupt rx path don't get confused while we copy */ priv->spy_number = 0; @@ -2774,20 +2940,20 @@ } /* Now, let the others play */ - dldwd_unlock(priv); + orinoco_unlock(priv); return err; } -static int dldwd_ioctl_getspy(struct net_device *dev, struct iw_point *srq) +static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; struct sockaddr address[IW_MAX_SPY]; struct iw_quality spy_stat[IW_MAX_SPY]; int number; int i; - dldwd_lock(priv); + orinoco_lock(priv); number = priv->spy_number; if ((number > 0) && (srq->pointer)) { @@ -2807,7 +2973,7 @@ priv->spy_stat[i].updated = 0; } - dldwd_unlock(priv); + orinoco_unlock(priv); /* Push stuff to user space */ srq->length = number; @@ -2822,22 +2988,22 @@ } int -dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; struct iwreq *wrq = (struct iwreq *)rq; int err = 0; int changed = 0; TRACE_ENTER(dev->name); - /* In theory, we could allow most of the the SET stuff to be done - * In practice, the laps of time at startup when the card is not - * ready is very short, so why bother... - * Note that hw_ready is different from up/down (ifconfig), when - * the device is not yet up, it is usually already ready... - * Jean II */ - if (!priv->hw_ready) + /* In theory, we could allow most of the the SET stuff to be + * done In practice, the laps of time at startup when the card + * is not ready is very short, so why bother... Note that + * netif_device_present is different from up/down (ifconfig), + * when the device is not yet up, it is usually already + * ready... Jean II */ + if (! netif_device_present(dev)) return -ENODEV; switch (cmd) { @@ -2849,17 +3015,17 @@ case SIOCGIWAP: DEBUG(1, "%s: SIOCGIWAP\n", dev->name); wrq->u.ap_addr.sa_family = ARPHRD_ETHER; - err = dldwd_hw_get_bssid(priv, wrq->u.ap_addr.sa_data); + err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data); break; case SIOCGIWRANGE: DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name); - err = dldwd_ioctl_getiwrange(dev, &wrq->u.data); + err = orinoco_ioctl_getiwrange(dev, &wrq->u.data); break; case SIOCSIWMODE: DEBUG(1, "%s: SIOCSIWMODE\n", dev->name); - dldwd_lock(priv); + orinoco_lock(priv); switch (wrq->u.mode) { case IW_MODE_ADHOC: if (! (priv->has_ibss || priv->has_port3) ) @@ -2880,14 +3046,14 @@ break; } set_port_type(priv); - dldwd_unlock(priv); + orinoco_unlock(priv); break; case SIOCGIWMODE: DEBUG(1, "%s: SIOCGIWMODE\n", dev->name); - dldwd_lock(priv); + orinoco_lock(priv); wrq->u.mode = priv->iw_mode; - dldwd_unlock(priv); + orinoco_unlock(priv); break; case SIOCSIWENCODE: @@ -2897,7 +3063,7 @@ break; } - err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding); + err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding); if (! err) changed = 1; break; @@ -2914,54 +3080,54 @@ break; } - err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding); + err = orinoco_ioctl_getiwencode(dev, &wrq->u.encoding); break; case SIOCSIWESSID: DEBUG(1, "%s: SIOCSIWESSID\n", dev->name); - err = dldwd_ioctl_setessid(dev, &wrq->u.essid); + err = orinoco_ioctl_setessid(dev, &wrq->u.essid); if (! err) changed = 1; break; case SIOCGIWESSID: DEBUG(1, "%s: SIOCGIWESSID\n", dev->name); - err = dldwd_ioctl_getessid(dev, &wrq->u.essid); + err = orinoco_ioctl_getessid(dev, &wrq->u.essid); break; case SIOCSIWNICKN: DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name); - err = dldwd_ioctl_setnick(dev, &wrq->u.data); + err = orinoco_ioctl_setnick(dev, &wrq->u.data); if (! err) changed = 1; break; case SIOCGIWNICKN: DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name); - err = dldwd_ioctl_getnick(dev, &wrq->u.data); + err = orinoco_ioctl_getnick(dev, &wrq->u.data); break; case SIOCGIWFREQ: DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name); - wrq->u.freq.m = dldwd_hw_get_freq(priv); + wrq->u.freq.m = orinoco_hw_get_freq(priv); wrq->u.freq.e = 1; break; case SIOCSIWFREQ: DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name); - err = dldwd_ioctl_setfreq(dev, &wrq->u.freq); + err = orinoco_ioctl_setfreq(dev, &wrq->u.freq); if (! err) changed = 1; break; case SIOCGIWSENS: DEBUG(1, "%s: SIOCGIWSENS\n", dev->name); - err = dldwd_ioctl_getsens(dev, &wrq->u.sens); + err = orinoco_ioctl_getsens(dev, &wrq->u.sens); break; case SIOCSIWSENS: DEBUG(1, "%s: SIOCSIWSENS\n", dev->name); - err = dldwd_ioctl_setsens(dev, &wrq->u.sens); + err = orinoco_ioctl_setsens(dev, &wrq->u.sens); if (! err) changed = 1; break; @@ -2975,45 +3141,45 @@ case SIOCSIWRTS: DEBUG(1, "%s: SIOCSIWRTS\n", dev->name); - err = dldwd_ioctl_setrts(dev, &wrq->u.rts); + err = orinoco_ioctl_setrts(dev, &wrq->u.rts); if (! err) changed = 1; break; case SIOCSIWFRAG: DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name); - err = dldwd_ioctl_setfrag(dev, &wrq->u.frag); + err = orinoco_ioctl_setfrag(dev, &wrq->u.frag); if (! err) changed = 1; break; case SIOCGIWFRAG: DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name); - err = dldwd_ioctl_getfrag(dev, &wrq->u.frag); + err = orinoco_ioctl_getfrag(dev, &wrq->u.frag); break; case SIOCSIWRATE: DEBUG(1, "%s: SIOCSIWRATE\n", dev->name); - err = dldwd_ioctl_setrate(dev, &wrq->u.bitrate); + err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate); if (! err) changed = 1; break; case SIOCGIWRATE: DEBUG(1, "%s: SIOCGIWRATE\n", dev->name); - err = dldwd_ioctl_getrate(dev, &wrq->u.bitrate); + err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate); break; case SIOCSIWPOWER: DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name); - err = dldwd_ioctl_setpower(dev, &wrq->u.power); + err = orinoco_ioctl_setpower(dev, &wrq->u.power); if (! err) changed = 1; break; case SIOCGIWPOWER: DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name); - err = dldwd_ioctl_getpower(dev, &wrq->u.power); + err = orinoco_ioctl_getpower(dev, &wrq->u.power); break; case SIOCGIWTXPOW: @@ -3033,44 +3199,44 @@ case SIOCGIWRETRY: DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name); - err = dldwd_ioctl_getretry(dev, &wrq->u.retry); + err = orinoco_ioctl_getretry(dev, &wrq->u.retry); break; #endif /* WIRELESS_EXT > 10 */ case SIOCSIWSPY: DEBUG(1, "%s: SIOCSIWSPY\n", dev->name); - err = dldwd_ioctl_setspy(dev, &wrq->u.data); + err = orinoco_ioctl_setspy(dev, &wrq->u.data); break; case SIOCGIWSPY: DEBUG(1, "%s: SIOCGIWSPY\n", dev->name); - err = dldwd_ioctl_getspy(dev, &wrq->u.data); + err = orinoco_ioctl_getspy(dev, &wrq->u.data); break; case SIOCGIWPRIV: DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name); if (wrq->u.data.pointer) { struct iw_priv_args privtab[] = { - { SIOCDEVPRIVATE + 0x0, 0, 0, "force_reset" }, - { SIOCDEVPRIVATE + 0x1, 0, 0, "card_reset" }, - { SIOCDEVPRIVATE + 0x2, + { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, + { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, + { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_port3" }, - { SIOCDEVPRIVATE + 0x3, 0, + { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_port3" }, - { SIOCDEVPRIVATE + 0x4, + { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble" }, - { SIOCDEVPRIVATE + 0x5, 0, + { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_preamble" }, - { SIOCDEVPRIVATE + 0x6, + { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_ibssport" }, - { SIOCDEVPRIVATE + 0x7, 0, + { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_ibssport" } }; @@ -3085,8 +3251,8 @@ } break; - case SIOCDEVPRIVATE + 0x0: /* force_reset */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n", + case SIOCIWFIRSTPRIV + 0x0: /* force_reset */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x0 (force_reset)\n", dev->name); if (! capable(CAP_NET_ADMIN)) { err = -EPERM; @@ -3094,11 +3260,11 @@ } printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); - dldwd_reset(priv); + orinoco_reset(priv); break; - case SIOCDEVPRIVATE + 0x1: /* card_reset */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x1 (card_reset)\n", + case SIOCIWFIRSTPRIV + 0x1: /* card_reset */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x1 (card_reset)\n", dev->name); if (! capable(CAP_NET_ADMIN)) { err = -EPERM; @@ -3108,30 +3274,30 @@ printk(KERN_DEBUG "%s: Forcing card reset!\n", dev->name); if(priv->card_reset_handler != NULL) priv->card_reset_handler(priv); - dldwd_reset(priv); + orinoco_reset(priv); break; - case SIOCDEVPRIVATE + 0x2: /* set_port3 */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n", + case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x2 (set_port3)\n", dev->name); if (! capable(CAP_NET_ADMIN)) { err = -EPERM; break; } - err = dldwd_ioctl_setport3(dev, wrq); + err = orinoco_ioctl_setport3(dev, wrq); if (! err) changed = 1; break; - case SIOCDEVPRIVATE + 0x3: /* get_port3 */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n", + case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x3 (get_port3)\n", dev->name); - err = dldwd_ioctl_getport3(dev, wrq); + err = orinoco_ioctl_getport3(dev, wrq); break; - case SIOCDEVPRIVATE + 0x4: /* set_preamble */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x4 (set_preamble)\n", + case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x4 (set_preamble)\n", dev->name); if (! capable(CAP_NET_ADMIN)) { err = -EPERM; @@ -3146,46 +3312,46 @@ if(priv->has_preamble) { int val = *( (int *) wrq->u.name ); - dldwd_lock(priv); + orinoco_lock(priv); if(val) priv->preamble = 1; else priv->preamble = 0; - dldwd_unlock(priv); + orinoco_unlock(priv); changed = 1; } else err = -EOPNOTSUPP; break; - case SIOCDEVPRIVATE + 0x5: /* get_preamble */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x5 (get_preamble)\n", + case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x5 (get_preamble)\n", dev->name); if(priv->has_preamble) { int *val = (int *)wrq->u.name; - dldwd_lock(priv); + orinoco_lock(priv); *val = priv->preamble; - dldwd_unlock(priv); + orinoco_unlock(priv); } else err = -EOPNOTSUPP; break; - case SIOCDEVPRIVATE + 0x6: /* set_ibssport */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x6 (set_ibssport)\n", + case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x6 (set_ibssport)\n", dev->name); if (! capable(CAP_NET_ADMIN)) { err = -EPERM; break; } - err = dldwd_ioctl_setibssport(dev, wrq); + err = orinoco_ioctl_setibssport(dev, wrq); if (! err) changed = 1; break; - case SIOCDEVPRIVATE + 0x7: /* get_ibssport */ - DEBUG(1, "%s: SIOCDEVPRIVATE + 0x7 (get_ibssport)\n", + case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */ + DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x7 (get_ibssport)\n", dev->name); - err = dldwd_ioctl_getibssport(dev, wrq); + err = orinoco_ioctl_getibssport(dev, wrq); break; @@ -3194,14 +3360,13 @@ } if (! err && changed && netif_running(dev)) { - err = dldwd_reset(priv); + err = orinoco_reset(priv); if (err) { /* Ouch ! What are we supposed to do ? */ printk(KERN_ERR "orinoco_cs: Failed to set parameters on %s\n", dev->name); - netif_stop_queue(dev); - dldwd_shutdown(priv); - priv->hw_ready = 0; + netif_device_detach(dev); + orinoco_shutdown(priv); } } @@ -3211,11 +3376,11 @@ } int -dldwd_change_mtu(struct net_device *dev, int new_mtu) +orinoco_change_mtu(struct net_device *dev, int new_mtu) { TRACE_ENTER(dev->name); - if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) ) + if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) return -EINVAL; dev->mtu = new_mtu; @@ -3226,108 +3391,72 @@ } static void -__dldwd_set_multicast_list(struct net_device *dev) +__orinoco_set_multicast_list(struct net_device *dev) { - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; - int promisc, allmulti, mc_count; + int promisc, mc_count; /* We'll wait until it's ready. Anyway, the network doesn't call us * here until we are open - Jean II */ - if (!priv->hw_ready) + /* FIXME: do we need this test at all? */ + if (! netif_device_present(dev)) return; - TRACE_ENTER(dev->name); - DEBUG(3, "dev->flags=0x%x, priv->promiscuous=%d, dev->mc_count=%d priv->mc_count=%d\n", - dev->flags, priv->promiscuous, dev->mc_count, priv->mc_count); - /* The Hermes doesn't seem to have an allmulti mode, so we go * into promiscuous mode and let the upper levels deal. */ - if ( (dev->flags & IFF_PROMISC) ) { + if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || + (dev->mc_count > MAX_MULTICAST(priv)) ) { promisc = 1; - allmulti = 0; mc_count = 0; - } else if ( (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > HERMES_MAX_MULTICAST) ) { - promisc = 0; - allmulti = 1; - mc_count = HERMES_MAX_MULTICAST; } else { promisc = 0; - allmulti = 0; mc_count = dev->mc_count; } - DEBUG(3, "promisc=%d mc_count=%d\n", - promisc, mc_count); - - if (promisc != priv->promiscuous) { /* Don't touch the hardware if we don't have to */ - err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PROMISCUOUS, + if (promisc != priv->promiscuous) { + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNFPROMISCUOUSMODE, promisc); if (err) { - printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n", - dev->name, err, promisc); + printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", + dev->name, err); } else priv->promiscuous = promisc; - } - if (allmulti) { - /* FIXME: This method of doing allmulticast reception - comes from the NetBSD driver. Haven't actually - tested whether it works or not. */ - hermes_multicast_t mclist; + mc_count = 0; + } - memset(&mclist, 0, sizeof(mclist)); - err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, &mclist); - if (err) - printk(KERN_ERR "%s: Error %d setting multicast list.\n", - dev->name, err); - else - priv->allmulti = 1; - - } else if (mc_count || (! mc_count && priv->mc_count) ) { + if (mc_count || priv->mc_count) { struct dev_mc_list *p = dev->mc_list; hermes_multicast_t mclist; int i; for (i = 0; i < mc_count; i++) { - /* First some paranoid checks */ - if (! p) { - printk(KERN_ERR "%s: Multicast list shorter than mc_count.\n", - dev->name); - break; - } - if (p->dmi_addrlen != ETH_ALEN) { - - printk(KERN_ERR "%s: Bad address size (%d) in multicast list.\n", - dev->name, p->dmi_addrlen); - break; - } - + /* Paranoia: */ + if (! p) + BUG(); /* Multicast list shorter than mc_count */ + if (p->dmi_addrlen != ETH_ALEN) + BUG(); /* Bad address size in multicast list */ + memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); p = p->next; } - - /* More paranoia */ + if (p) - printk(KERN_ERR "%s: Multicast list longer than mc_count.\n", - dev->name); + printk(KERN_WARNING "Multicast list is longer than mc_count\n"); - priv->mc_count = i; - - DEBUG(3, "priv->mc_count = %d\n", priv->mc_count); - - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES, HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), &mclist); if (err) printk(KERN_ERR "%s: Error %d setting multicast list.\n", dev->name, err); else - priv->allmulti = 0; + priv->mc_count = mc_count; } /* Since we can set the promiscuous flag when it wasn't asked @@ -3337,11 +3466,6 @@ else dev->flags &= ~IFF_PROMISC; - if (priv->allmulti) - dev->flags |= IFF_ALLMULTI; - else - dev->flags &= ~IFF_ALLMULTI; - TRACE_EXIT(dev->name); } @@ -3420,16 +3544,17 @@ } static int -dldwd_proc_get_hermes_regs(char *page, char **start, off_t requested_offset, +orinoco_proc_get_hermes_regs(char *page, char **start, off_t requested_offset, int requested_len, int *eof, void *data) { - dldwd_priv_t *dev = (dldwd_priv_t *)data; - hermes_t *hw = &dev->hw; + struct orinoco_private *priv = (struct orinoco_private *)data; + struct net_device *dev = &priv->ndev; + hermes_t *hw = &priv->hw; char *buf; int total = 0, slop = 0; /* Hum, in this case hardware register are probably not readable... */ - if (!dev->hw_ready) + if (! netif_device_present(dev)) return -ENODEV; buf = page; @@ -3478,57 +3603,130 @@ #define DISPLAY_WORDS 0 #define DISPLAY_BYTES 1 #define DISPLAY_STRING 2 +#define DISPLAY_XSTRING 3 } record_table[] = { -#define RTCNFENTRY(name, type) { HERMES_RID_CNF_##name, #name, 0, LTV_BUF_SIZE, type } - RTCNFENTRY(PORTTYPE, DISPLAY_WORDS), - RTCNFENTRY(MACADDR, DISPLAY_BYTES), - RTCNFENTRY(DESIRED_SSID, DISPLAY_STRING), - RTCNFENTRY(CHANNEL, DISPLAY_WORDS), - RTCNFENTRY(OWN_SSID, DISPLAY_STRING), - RTCNFENTRY(SYSTEM_SCALE, DISPLAY_WORDS), - RTCNFENTRY(MAX_DATA_LEN, DISPLAY_WORDS), - RTCNFENTRY(PM_ENABLE, DISPLAY_WORDS), - RTCNFENTRY(PM_MCAST_RX, DISPLAY_WORDS), - RTCNFENTRY(PM_PERIOD, DISPLAY_WORDS), - RTCNFENTRY(NICKNAME, DISPLAY_STRING), - RTCNFENTRY(WEP_ON, DISPLAY_WORDS), - RTCNFENTRY(MWO_ROBUST, DISPLAY_WORDS), - RTCNFENTRY(MULTICAST_LIST, DISPLAY_BYTES), - RTCNFENTRY(CREATEIBSS, DISPLAY_WORDS), - RTCNFENTRY(FRAG_THRESH, DISPLAY_WORDS), - RTCNFENTRY(RTS_THRESH, DISPLAY_WORDS), - RTCNFENTRY(TX_RATE_CTRL, DISPLAY_WORDS), - RTCNFENTRY(PROMISCUOUS, DISPLAY_WORDS), - RTCNFENTRY(KEYS, DISPLAY_BYTES), - RTCNFENTRY(TX_KEY, DISPLAY_WORDS), - RTCNFENTRY(TICKTIME, DISPLAY_WORDS), - RTCNFENTRY(INTERSIL_TX_KEY, DISPLAY_WORDS), - RTCNFENTRY(INTERSIL_KEY0, DISPLAY_BYTES), - RTCNFENTRY(INTERSIL_KEY1, DISPLAY_BYTES), - RTCNFENTRY(INTERSIL_KEY2, DISPLAY_BYTES), - RTCNFENTRY(INTERSIL_KEY3, DISPLAY_BYTES), - RTCNFENTRY(INTERSIL_WEP_ON, DISPLAY_WORDS), -#undef RTCNFENTRY -#define RTINFENTRY(name,type) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, type } - RTINFENTRY(CHANNEL_LIST, DISPLAY_WORDS), - RTINFENTRY(STAIDENTITY, DISPLAY_WORDS), - RTINFENTRY(CURRENT_SSID, DISPLAY_STRING), - RTINFENTRY(CURRENT_BSSID, DISPLAY_BYTES), - RTINFENTRY(COMMSQUALITY, DISPLAY_WORDS), - RTINFENTRY(CURRENT_TX_RATE, DISPLAY_WORDS), - RTINFENTRY(WEP_AVAIL, DISPLAY_WORDS), - RTINFENTRY(CURRENT_CHANNEL, DISPLAY_WORDS), - RTINFENTRY(DATARATES, DISPLAY_BYTES), -#undef RTINFENTRY +#define CNF_WORDS(name) { HERMES_RID_CNF##name, #name, 0, LTV_BUF_SIZE, DISPLAY_WORDS } +#define CNF_BYTES(name) { HERMES_RID_CNF##name, #name, 0, LTV_BUF_SIZE, DISPLAY_BYTES } +#define CNF_STRING(name) { HERMES_RID_CNF##name, #name, 0, LTV_BUF_SIZE, DISPLAY_STRING } + CNF_WORDS(PORTTYPE), + CNF_BYTES(OWNMACADDR), + CNF_STRING(DESIREDSSID), + CNF_WORDS(OWNCHANNEL), + CNF_STRING(OWNSSID), + CNF_WORDS(OWNATIMWINDOW), + CNF_WORDS(SYSTEMSCALE), + CNF_WORDS(MAXDATALEN), + CNF_WORDS(PMENABLED), + CNF_WORDS(PMEPS), + CNF_WORDS(MULTICASTRECEIVE), + CNF_WORDS(MAXSLEEPDURATION), + CNF_WORDS(PMHOLDOVERDURATION), + CNF_STRING(OWNNAME), + CNF_WORDS(OWNDTIMPERIOD), + CNF_WORDS(MULTICASTPMBUFFERING), + CNF_WORDS(WEPENABLED_AGERE), + CNF_WORDS(MANDATORYBSSID_SYMBOL), + CNF_WORDS(WEPDEFAULTKEYID), + CNF_BYTES(DEFAULTKEY0), + CNF_BYTES(DEFAULTKEY1), + CNF_WORDS(MWOROBUST_AGERE), + CNF_BYTES(DEFAULTKEY2), + CNF_BYTES(DEFAULTKEY3), + CNF_WORDS(WEPFLAGS_INTERSIL), + CNF_WORDS(WEPKEYMAPPINGTABLE), + CNF_WORDS(AUTHENTICATION), + CNF_WORDS(MAXASSOCSTA), + CNF_WORDS(KEYLENGTH_SYMBOL), + CNF_WORDS(TXCONTROL), + CNF_WORDS(ROAMINGMODE), + CNF_WORDS(HOSTAUTHENTICATION), + CNF_WORDS(RCVCRCERROR), + CNF_WORDS(MMLIFE), + CNF_WORDS(ALTRETRYCOUNT), + CNF_WORDS(BEACONINT), + CNF_WORDS(APPCFINFO), + CNF_WORDS(STAPCFINFO), + CNF_WORDS(PRIORITYQUSAGE), + CNF_WORDS(TIMCTRL), + CNF_WORDS(THIRTY2TALLY), + CNF_WORDS(ENHSECURITY), + CNF_BYTES(GROUPADDRESSES), + CNF_WORDS(CREATEIBSS), + CNF_WORDS(FRAGMENTATIONTHRESHOLD), + CNF_WORDS(RTSTHRESHOLD), + CNF_WORDS(TXRATECONTROL), + CNF_WORDS(PROMISCUOUSMODE), + CNF_WORDS(BASICRATES_SYMBOL), + CNF_WORDS(PREAMBLE_SYMBOL), + CNF_WORDS(SHORTPREAMBLE), + CNF_BYTES(WEPKEYS_AGERE), + CNF_WORDS(EXCLUDELONGPREAMBLE), + CNF_WORDS(TXKEY_AGERE), + CNF_WORDS(AUTHENTICATIONRSPTO), + CNF_WORDS(BASICRATES), + CNF_WORDS(SUPPORTEDRATES), + CNF_WORDS(TICKTIME), + CNF_WORDS(SCANREQUEST), + CNF_WORDS(JOINREQUEST), + CNF_WORDS(AUTHENTICATESTATION), + CNF_WORDS(CHANNELINFOREQUEST), +#undef CNF_WORDS +#undef CNF_BYTES +#undef CNF_STRING +#define INF_WORDS(name) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, DISPLAY_WORDS } +#define INF_BYTES(name) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, DISPLAY_BYTES } +#define INF_STRING(name) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, DISPLAY_STRING } +#define INF_XSTRING(name) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, DISPLAY_XSTRING } + INF_WORDS(MAXLOADTIME), + INF_WORDS(DOWNLOADBUFFER), + INF_WORDS(PRIID), + INF_WORDS(PRISUPRANGE), + INF_WORDS(CFIACTRANGES), + INF_WORDS(NICSERNUM), + INF_WORDS(NICID), + INF_WORDS(MFISUPRANGE), + INF_WORDS(CFISUPRANGE), + INF_WORDS(CHANNELLIST), + INF_WORDS(REGULATORYDOMAINS), + INF_WORDS(TEMPTYPE), +/* INF_BYTES(CIS), */ + INF_WORDS(STAID), + INF_STRING(CURRENTSSID), + INF_BYTES(CURRENTBSSID), + INF_WORDS(COMMSQUALITY), + INF_WORDS(CURRENTTXRATE), + INF_WORDS(CURRENTBEACONINTERVAL), + INF_WORDS(CURRENTSCALETHRESHOLDS), + INF_WORDS(PROTOCOLRSPTIME), + INF_WORDS(SHORTRETRYLIMIT), + INF_WORDS(LONGRETRYLIMIT), + INF_WORDS(MAXTRANSMITLIFETIME), + INF_WORDS(MAXRECEIVELIFETIME), + INF_WORDS(CFPOLLABLE), + INF_WORDS(AUTHENTICATIONALGORITHMS), + INF_WORDS(PRIVACYOPTIONIMPLEMENTED), + INF_BYTES(OWNMACADDR), + INF_WORDS(SCANRESULTSTABLE), + INF_WORDS(PHYTYPE), + INF_WORDS(CURRENTCHANNEL), + INF_WORDS(CURRENTPOWERSTATE), + INF_WORDS(CCAMODE), + INF_WORDS(SUPPORTEDDATARATES), + INF_BYTES(BUILDSEQ), + INF_XSTRING(FWID) +#undef INF_WORDS +#undef INF_BYTES +#undef INF_STRING }; #define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) ) static int -dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset, +orinoco_proc_get_hermes_recs(char *page, char **start, off_t requested_offset, int requested_len, int *eof, void *data) { - dldwd_priv_t *dev = (dldwd_priv_t *)data; - hermes_t *hw = &dev->hw; + struct orinoco_private *priv = (struct orinoco_private *)data; + struct net_device *dev = &priv->ndev; + hermes_t *hw = &priv->hw; char *buf; int total = 0, slop = 0; int i; @@ -3536,7 +3734,7 @@ int err; /* Hum, in this case hardware register are probably not readable... */ - if (!dev->hw_ready) + if (! netif_device_present(dev)) return -ENODEV; buf = page; @@ -3554,6 +3752,7 @@ val8 = kmalloc(maxlen + 2, GFP_KERNEL); if (! val8) return -ENOMEM; + memset(val8, 0, maxlen + 2); err = hermes_read_ltv(hw, USER_BAP, rid, maxlen, &length, val8); @@ -3562,6 +3761,8 @@ continue; } val16 = (u16 *)val8; + if (length == 0) + continue; buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name, rid, length, (length-1)*2); @@ -3588,6 +3789,9 @@ val8[len] = '\0'; buf += sprintf(buf, "\"%s\"", (char *)&val16[1]); break; + case DISPLAY_XSTRING: + + buf += sprintf(buf, "'%s'", (char *)val8); } buf += sprintf(buf, "\n"); @@ -3609,65 +3813,67 @@ /* initialise the /proc subsystem for the hermes driver, creating the * separate entries */ static int -dldwd_proc_init(void) +orinoco_proc_init(void) { int err = 0; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); /* create the directory for it to sit in */ dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root); if (dir_base == NULL) { printk(KERN_ERR "Unable to initialise /proc/hermes.\n"); - dldwd_proc_cleanup(); + orinoco_proc_cleanup(); err = -ENOMEM; } - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); return err; } int -dldwd_proc_dev_init(dldwd_priv_t *dev) +orinoco_proc_dev_init(struct orinoco_private *priv) { - struct net_device *ndev = &dev->ndev; + struct net_device *dev = &priv->ndev; - dev->dir_dev = NULL; + priv->dir_dev = NULL; /* create the directory for it to sit in */ - dev->dir_dev = create_proc_entry(ndev->name, S_IFDIR | S_IRUGO | S_IXUGO, - dir_base); - if (dev->dir_dev == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n", ndev->name); + priv->dir_dev = create_proc_entry(dev->name, S_IFDIR | S_IRUGO | S_IXUGO, + dir_base); + if (priv->dir_dev == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n", dev->name); goto fail; } - dev->dir_regs = NULL; - dev->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO, - dev->dir_dev, dldwd_proc_get_hermes_regs, dev); - if (dev->dir_regs == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes/%s/regs.\n", ndev->name); + priv->dir_regs = NULL; + priv->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO, + priv->dir_dev, orinoco_proc_get_hermes_regs, priv); + if (priv->dir_regs == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s/regs.\n", dev->name); goto fail; } - dev->dir_recs = NULL; - dev->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO, - dev->dir_dev, dldwd_proc_get_hermes_recs, dev); - if (dev->dir_recs == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n", ndev->name); + priv->dir_recs = NULL; + priv->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO, + priv->dir_dev, orinoco_proc_get_hermes_recs, priv); + if (priv->dir_recs == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n", dev->name); goto fail; } return 0; fail: - dldwd_proc_dev_cleanup(dev); + orinoco_proc_dev_cleanup(priv); return -ENOMEM; } void -dldwd_proc_dev_cleanup(dldwd_priv_t *priv) +orinoco_proc_dev_cleanup(struct orinoco_private *priv) { - struct net_device *ndev = &priv->ndev; + struct net_device *dev = &priv->ndev; + + TRACE_ENTER(priv->ndev.name); if (priv->dir_regs) { remove_proc_entry("regs", priv->dir_dev); @@ -3678,26 +3884,28 @@ priv->dir_recs = NULL; } if (priv->dir_dev) { - remove_proc_entry(ndev->name, dir_base); + remove_proc_entry(dev->name, dir_base); priv->dir_dev = NULL; } + + TRACE_EXIT(priv->ndev.name); } static void -dldwd_proc_cleanup(void) +orinoco_proc_cleanup(void) { - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); if (dir_base) { remove_proc_entry("hermes", &proc_root); dir_base = NULL; } - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); } int -dldwd_setup(dldwd_priv_t* priv) +orinoco_setup(struct orinoco_private* priv) { struct net_device *dev = &priv->ndev;; @@ -3709,20 +3917,20 @@ /* Setup up default routines */ priv->card_reset_handler = NULL; /* Caller may override */ - dev->init = dldwd_init; + dev->init = orinoco_init; dev->open = NULL; /* Caller *must* override */ dev->stop = NULL; - dev->hard_start_xmit = dldwd_xmit; - dev->tx_timeout = dldwd_tx_timeout; - dev->watchdog_timeo = HZ; /* 4 second timeout */ + dev->hard_start_xmit = orinoco_xmit; + dev->tx_timeout = orinoco_tx_timeout; + dev->watchdog_timeo = HZ; /* 1 second timeout */ - dev->get_stats = dldwd_get_stats; - dev->get_wireless_stats = dldwd_get_wireless_stats; + dev->get_stats = orinoco_get_stats; + dev->get_wireless_stats = orinoco_get_wireless_stats; - dev->do_ioctl = dldwd_ioctl; + dev->do_ioctl = orinoco_ioctl; - dev->change_mtu = dldwd_change_mtu; - dev->set_multicast_list = dldwd_set_multicast_list; + dev->change_mtu = orinoco_change_mtu; + dev->set_multicast_list = orinoco_set_multicast_list; netif_stop_queue(dev); @@ -3730,36 +3938,25 @@ } #ifdef ORINOCO_DEBUG -EXPORT_SYMBOL(dldwd_debug); +EXPORT_SYMBOL(orinoco_debug); #endif -EXPORT_SYMBOL(dldwd_init); -EXPORT_SYMBOL(dldwd_xmit); -EXPORT_SYMBOL(dldwd_tx_timeout); -EXPORT_SYMBOL(dldwd_ioctl); -EXPORT_SYMBOL(dldwd_change_mtu); -EXPORT_SYMBOL(dldwd_set_multicast_list); -EXPORT_SYMBOL(dldwd_shutdown); -EXPORT_SYMBOL(dldwd_reset); -EXPORT_SYMBOL(dldwd_setup); -EXPORT_SYMBOL(dldwd_proc_dev_init); -EXPORT_SYMBOL(dldwd_proc_dev_cleanup); -EXPORT_SYMBOL(dldwd_interrupt); +EXPORT_SYMBOL(orinoco_shutdown); +EXPORT_SYMBOL(orinoco_reset); +EXPORT_SYMBOL(orinoco_setup); +EXPORT_SYMBOL(orinoco_proc_dev_init); +EXPORT_SYMBOL(orinoco_proc_dev_cleanup); +EXPORT_SYMBOL(orinoco_interrupt); -static int __init init_dldwd(void) +static int __init init_orinoco(void) { - int err; - - err = dldwd_proc_init(); - printk(KERN_DEBUG "%s\n", version); - - return 0; + return orinoco_proc_init(); } -static void __exit exit_dldwd(void) +static void __exit exit_orinoco(void) { - dldwd_proc_cleanup(); + orinoco_proc_cleanup(); } -module_init(init_dldwd); -module_exit(exit_dldwd); +module_init(init_orinoco); +module_exit(exit_orinoco); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/orinoco.h linux-2.5/drivers/net/wireless/orinoco.h --- linux-2.5.5/drivers/net/wireless/orinoco.h Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/net/wireless/orinoco.h Wed Jan 23 01:11:51 2002 @@ -8,64 +8,48 @@ #define _ORINOCO_H /* To enable debug messages */ -/* #define ORINOCO_DEBUG 3 */ +//#define ORINOCO_DEBUG 3 #if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) -#error "orinoco_cs requires Wireless extensions v10 or later." +#error "orinoco driver requires Wireless extensions v10 or later." #endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ #define WIRELESS_SPY // enable iwspy support +#define ORINOCO_MAX_KEY_SIZE 14 +#define ORINOCO_MAX_KEYS 4 -#define DLDWD_MIN_MTU 256 -#define DLDWD_MAX_MTU (HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD) +typedef struct orinoco_key { + u16 len; /* always store little-endian */ + char data[ORINOCO_MAX_KEY_SIZE]; +} __attribute__ ((packed)) orinoco_key_t; -#define LTV_BUF_SIZE 128 -#define USER_BAP 0 -#define IRQ_BAP 1 -#define DLDWD_MACPORT 0 -#define IRQ_LOOP_MAX 10 -#define TX_NICBUF_SIZE 2048 -#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ -#define MAX_KEYS 4 -#define MAX_KEY_SIZE 14 -#define LARGE_KEY_SIZE 13 -#define SMALL_KEY_SIZE 5 -#define MAX_FRAME_SIZE 2304 - -typedef struct dldwd_key { - uint16_t len; /* always store little-endian */ - char data[MAX_KEY_SIZE]; -} __attribute__ ((packed)) dldwd_key_t; - -typedef dldwd_key_t dldwd_keys_t[MAX_KEYS]; +typedef orinoco_key_t orinoco_keys_t[ORINOCO_MAX_KEYS]; /*====================================================================*/ - -typedef struct dldwd_priv { +struct orinoco_private { void* card; /* Pointer to card dependant structure */ /* card dependant extra reset code (i.e. bus/interface specific */ - int (*card_reset_handler)(struct dldwd_priv *); + int (*card_reset_handler)(struct orinoco_private *); spinlock_t lock; long state; -#define DLDWD_STATE_INIRQ 0 -#define DLDWD_STATE_DOIRQ 1 - int hw_ready; /* HW may be suspended by platform */ +#define ORINOCO_STATE_INIRQ 0 +#define ORINOCO_STATE_DOIRQ 1 + atomic_t queue_length; /* Net device stuff */ struct net_device ndev; struct net_device_stats stats; struct iw_statistics wstats; - /* Hardware control variables */ hermes_t hw; - uint16_t txfid; + u16 txfid; /* Capabilities of the hardware/firmware */ int firmware_type; -#define FIRMWARE_TYPE_LUCENT 1 +#define FIRMWARE_TYPE_AGERE 1 #define FIRMWARE_TYPE_INTERSIL 2 #define FIRMWARE_TYPE_SYMBOL 3 int has_ibss, has_port3, prefer_port3, has_ibss_any, ibss_port; @@ -74,23 +58,26 @@ int has_pm; int has_preamble; int need_card_reset, broken_reset, broken_allocate; - uint16_t channel_mask; + u16 channel_mask; /* Current configuration */ - uint32_t iw_mode; + u32 iw_mode; int port_type, allow_ibss; - uint16_t wep_on, wep_restrict, tx_key; - dldwd_keys_t keys; + + u16 wep_on, wep_restrict, tx_key; + orinoco_keys_t keys; + + int bitratemode; + char nick[IW_ESSID_MAX_SIZE+1]; char desired_essid[IW_ESSID_MAX_SIZE+1]; - uint16_t frag_thresh, mwo_robust; - uint16_t channel; - uint16_t ap_density, rts_thresh; - uint16_t tx_rate_ctrl; - uint16_t pm_on, pm_mcast, pm_period, pm_timeout; - uint16_t preamble; + u16 frag_thresh, mwo_robust; + u16 channel; + u16 ap_density, rts_thresh; + u16 pm_on, pm_mcast, pm_period, pm_timeout; + u16 preamble; - int promiscuous, allmulti, mc_count; + int promiscuous, mc_count; #ifdef WIRELESS_SPY int spy_number; @@ -102,16 +89,16 @@ struct proc_dir_entry *dir_dev; struct proc_dir_entry *dir_regs; struct proc_dir_entry *dir_recs; -} dldwd_priv_t; +}; /*====================================================================*/ -extern struct list_head dldwd_instances; +extern struct list_head orinoco_instances; #ifdef ORINOCO_DEBUG -extern int dldwd_debug; -#define DEBUG(n, args...) do { if (dldwd_debug>(n)) printk(KERN_DEBUG args); } while(0) -#define DEBUGMORE(n, args...) do { if (dldwd_debug>(n)) printk(args); } while (0) +extern int orinoco_debug; +#define DEBUG(n, args...) do { if (orinoco_debug>(n)) printk(KERN_DEBUG args); } while(0) +#define DEBUGMORE(n, args...) do { if (orinoco_debug>(n)) printk(args); } while (0) #else #define DEBUG(n, args...) do { } while (0) #define DEBUGMORE(n, args...) do { } while (0) @@ -123,20 +110,20 @@ #define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) ) /* struct net_device methods */ -extern int dldwd_init(struct net_device *dev); -extern int dldwd_xmit(struct sk_buff *skb, struct net_device *dev); -extern void dldwd_tx_timeout(struct net_device *dev); - -extern int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -extern int dldwd_change_mtu(struct net_device *dev, int new_mtu); -extern void dldwd_set_multicast_list(struct net_device *dev); +extern int orinoco_init(struct net_device *dev); +extern int orinoco_xmit(struct sk_buff *skb, struct net_device *dev); +extern void orinoco_tx_timeout(struct net_device *dev); + +extern int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +extern int orinoco_change_mtu(struct net_device *dev, int new_mtu); +extern void orinoco_set_multicast_list(struct net_device *dev); /* utility routines */ -extern void dldwd_shutdown(dldwd_priv_t *dev); -extern int dldwd_reset(dldwd_priv_t *dev); -extern int dldwd_setup(dldwd_priv_t* priv); -extern int dldwd_proc_dev_init(dldwd_priv_t *dev); -extern void dldwd_proc_dev_cleanup(dldwd_priv_t *priv); -extern void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs); +extern void orinoco_shutdown(struct orinoco_private *dev); +extern int orinoco_reset(struct orinoco_private *dev); +extern int orinoco_setup(struct orinoco_private* priv); +extern int orinoco_proc_dev_init(struct orinoco_private *dev); +extern void orinoco_proc_dev_cleanup(struct orinoco_private *priv); +extern void orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs); -#endif +#endif /* _ORINOCO_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/orinoco_cs.c linux-2.5/drivers/net/wireless/orinoco_cs.c --- linux-2.5.5/drivers/net/wireless/orinoco_cs.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/net/wireless/orinoco_cs.c Fri Feb 8 16:06:15 2002 @@ -1,4 +1,4 @@ -/* orinoco_cs.c 0.08a - (formerly known as dldwd_cs.c) +/* orinoco_cs.c 0.09b - (formerly known as dldwd_cs.c) * * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ @@ -44,7 +44,7 @@ /*====================================================================*/ -static char version[] __initdata = "orinoco_cs.c 0.08a (David Gibson and others)"; +static char version[] __initdata = "orinoco_cs.c 0.09b (David Gibson and others)"; MODULE_AUTHOR("David Gibson "); MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards"); @@ -68,33 +68,31 @@ MODULE_PARM(reset_cor, "i"); MODULE_PARM(ignore_cis_vcc, "i"); - /* Pcmcia specific structure */ -typedef struct dldwd_card { +struct orinoco_pccard { dev_link_t link; dev_node_t node; - int instance; /* Common structure (fully included), see orinoco.h */ - struct dldwd_priv priv; -} dldwd_card_t; + struct orinoco_private priv; +}; /* * Function prototypes */ /* struct net_device methods */ -static int dldwd_cs_open(struct net_device *dev); -static int dldwd_cs_stop(struct net_device *dev); +static int orinoco_cs_open(struct net_device *dev); +static int orinoco_cs_stop(struct net_device *dev); /* PCMCIA gumpf */ -static void dldwd_cs_config(dev_link_t * link); -static void dldwd_cs_release(u_long arg); -static int dldwd_cs_event(event_t event, int priority, +static void orinoco_cs_config(dev_link_t * link); +static void orinoco_cs_release(u_long arg); +static int orinoco_cs_event(event_t event, int priority, event_callback_args_t * args); -static dev_link_t *dldwd_cs_attach(void); -static void dldwd_cs_detach(dev_link_t *); +static dev_link_t *orinoco_cs_attach(void); +static void orinoco_cs_detach(dev_link_t *); /* The dev_info variable is the "key" that is used to match up this @@ -115,7 +113,6 @@ */ static dev_link_t *dev_list; /* = NULL */ -static int num_instances; /* = 0 */ /*====================================================================*/ @@ -127,10 +124,10 @@ } static int -dldwd_cs_open(struct net_device *dev) +orinoco_cs_open(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - dldwd_card_t* card = (dldwd_card_t *)priv->card; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; + struct orinoco_pccard* card = (struct orinoco_pccard *)priv->card; dev_link_t *link = &card->link; int err; @@ -139,9 +136,9 @@ link->open++; netif_device_attach(dev); - err = dldwd_reset(priv); + err = orinoco_reset(priv); if (err) - dldwd_cs_stop(dev); + orinoco_cs_stop(dev); else netif_start_queue(dev); @@ -151,17 +148,17 @@ } static int -dldwd_cs_stop(struct net_device *dev) +orinoco_cs_stop(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; - dldwd_card_t* card = (dldwd_card_t *)priv->card; + struct orinoco_private *priv = (struct orinoco_private *)dev->priv; + struct orinoco_pccard* card = (struct orinoco_pccard *)priv->card; dev_link_t *link = &card->link; TRACE_ENTER(priv->ndev.name); netif_stop_queue(dev); - dldwd_shutdown(priv); + orinoco_shutdown(priv); link->open--; @@ -179,9 +176,9 @@ * In fact, this seem necessary for Spectrum cards... */ static int -dldwd_cs_cor_reset(dldwd_priv_t *priv) +orinoco_cs_cor_reset(struct orinoco_private *priv) { - dldwd_card_t* card = (dldwd_card_t *)priv->card; + struct orinoco_pccard* card = (struct orinoco_pccard *)priv->card; dev_link_t *link = &card->link; conf_reg_t reg; u_int default_cor; @@ -189,8 +186,8 @@ TRACE_ENTER(priv->ndev.name); /* Doing it if hardware is gone is guaranteed crash */ - if(!priv->hw_ready) - return(0); + if(! (link->state & DEV_CONFIG) ) + return -ENODEV; /* Save original COR value */ reg.Function = 0; @@ -200,7 +197,7 @@ CardServices(AccessConfigurationRegister, link->handle, ®); default_cor = reg.Value; - DEBUG(2, "dldwd : dldwd_cs_cor_reset() : cor=0x%X\n", default_cor); + DEBUG(2, "orinoco : orinoco_cs_cor_reset() : cor=0x%X\n", default_cor); /* Soft-Reset card */ reg.Action = CS_WRITE; @@ -209,6 +206,7 @@ CardServices(AccessConfigurationRegister, link->handle, ®); /* Wait until the card has acknowledged our reset */ + /* FIXME: mdelay() is deprecated -dgibson */ mdelay(1); /* Restore original COR configuration index */ @@ -216,11 +214,12 @@ CardServices(AccessConfigurationRegister, link->handle, ®); /* Wait until the card has finished restarting */ + /* FIXME: mdelay() is deprecated -dgibson */ mdelay(1); TRACE_EXIT(priv->ndev.name); - return(0); + return 0; } /* Remove zombie instances (card removed, detach pending) */ @@ -228,17 +227,17 @@ flush_stale_links(void) { dev_link_t *link, *next; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); for (link = dev_list; link; link = next) { next = link->next; if (link->state & DEV_STALE_LINK) - dldwd_cs_detach(link); + orinoco_cs_detach(link); } - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); } /*====================================================================== - dldwd_cs_attach() creates an "instance" of the driver, allocating + orinoco_cs_attach() creates an "instance" of the driver, allocating local data structures for one device. The device is registered with Card Services. @@ -248,16 +247,16 @@ ======================================================================*/ static dev_link_t * -dldwd_cs_attach(void) +orinoco_cs_attach(void) { - dldwd_card_t *card; - dldwd_priv_t *priv; + struct orinoco_pccard *card; + struct orinoco_private *priv; dev_link_t *link; struct net_device *ndev; client_reg_t client_reg; int ret, i; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); /* A bit of cleanup */ flush_stale_links(); @@ -272,13 +271,12 @@ /* Link both structure together */ priv = &(card->priv); priv->card = card; - card->instance = num_instances++; /* FIXME: Racy? */ link = &card->link; ndev = &priv->ndev; link->priv = priv; /* Initialize the dev_link_t structure */ - link->release.function = &dldwd_cs_release; + link->release.function = &orinoco_cs_release; link->release.data = (u_long) link; /* Interrupt setup */ @@ -302,15 +300,15 @@ link->conf.IntType = INT_MEMORY_AND_IO; /* Setup the common part */ - if(dldwd_setup(priv) < 0) { + if(orinoco_setup(priv) < 0) { kfree(card); return NULL; } /* Overrides */ - ndev->open = dldwd_cs_open; - ndev->stop = dldwd_cs_stop; - priv->card_reset_handler = dldwd_cs_cor_reset; + ndev->open = orinoco_cs_open; + ndev->stop = orinoco_cs_stop; + priv->card_reset_handler = orinoco_cs_cor_reset; /* Register with Card Services */ link->next = dev_list; @@ -321,21 +319,21 @@ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &dldwd_cs_event; + client_reg.event_handler = &orinoco_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); - dldwd_cs_detach(link); + orinoco_cs_detach(link); link = NULL; goto out; } out: - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); return link; -} /* dldwd_cs_attach */ +} /* orinoco_cs_attach */ /*====================================================================== This deletes a driver "instance". The device is de-registered @@ -345,12 +343,12 @@ ======================================================================*/ static void -dldwd_cs_detach(dev_link_t * link) +orinoco_cs_detach(dev_link_t * link) { dev_link_t **linkp; - dldwd_priv_t *priv = link->priv; + struct orinoco_private *priv = link->priv; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) @@ -388,14 +386,12 @@ } kfree(priv->card); - num_instances--; /* FIXME: Racy? */ - out: - TRACE_EXIT("dldwd"); -} /* dldwd_cs_detach */ + TRACE_EXIT("orinoco"); +} /* orinoco_cs_detach */ /*====================================================================== - dldwd_cs_config() is scheduled to run after a CARD_INSERTION event + orinoco_cs_config() is scheduled to run after a CARD_INSERTION event is received, to configure the PCMCIA socket, and to make the device available to the system. ======================================================================*/ @@ -407,11 +403,11 @@ if (CardServices(fn, args) != 0) goto next_entry static void -dldwd_cs_config(dev_link_t * link) +orinoco_cs_config(dev_link_t * link) { client_handle_t handle = link->handle; - dldwd_priv_t *priv = link->priv; - dldwd_card_t *card = (dldwd_card_t *)priv->card; + struct orinoco_private *priv = link->priv; + struct orinoco_pccard *card = (struct orinoco_pccard *)priv->card; hermes_t *hw = &priv->hw; struct net_device *ndev = &priv->ndev; tuple_t tuple; @@ -422,7 +418,7 @@ cistpl_cftable_entry_t dflt = { 0 }; cisinfo_t info; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); CS_CHECK(ValidateCIS, handle, &info); @@ -448,7 +444,7 @@ CS_CHECK(GetConfigurationInfo, handle, &conf); link->conf.Vcc = conf.Vcc; - DEBUG(0, "dldwd_cs_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", + DEBUG(0, "orinoco_cs_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", link->conf.ConfigBase, link->conf.Vcc); /* @@ -470,7 +466,7 @@ CFG_CHECK(GetTupleData, handle, &tuple); CFG_CHECK(ParseTuple, handle, &tuple, &parse); - DEBUG(0, "dldwd_cs_config: index = 0x%x, flags = 0x%x\n", + DEBUG(0, "orinoco_cs_config: index = 0x%x, flags = 0x%x\n", cfg->index, cfg->flags); if (cfg->flags & CISTPL_CFTABLE_DEFAULT) @@ -490,14 +486,14 @@ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "dldwd_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); if(!ignore_cis_vcc) goto next_entry; } } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "dldwd_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n", conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000); if(!ignore_cis_vcc) goto next_entry; } @@ -510,7 +506,7 @@ link->conf.Vpp1 = link->conf.Vpp2 = dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; - DEBUG(0, "dldwd_cs_config: We seem to have configured Vcc and Vpp\n"); + DEBUG(0, "orinoco_cs_config: We seem to have configured Vcc and Vpp\n"); /* Do we need to allocate an interrupt? */ if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) @@ -570,7 +566,7 @@ for (i=0; i<4; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; - link->irq.Handler = dldwd_interrupt; + link->irq.Handler = orinoco_interrupt; link->irq.Instance = priv; CS_CHECK(RequestIRQ, link->handle, &link->irq); @@ -591,6 +587,12 @@ ndev->base_addr = link->io.BasePort1; ndev->irq = link->irq.AssignedIRQ; + /* Now do a PCMCIA soft reset on the card, to make sure its in + a sane state */ + /* Optional because it really mess up old Lucent firmwares - Jean II */ + if (reset_cor) + orinoco_cs_cor_reset(priv); + /* register_netdev will give us an ethX name */ ndev->name[0] = '\0'; /* Tell the stack we exist */ @@ -618,7 +620,7 @@ printk("\n"); /* And give us the proc nodes for debugging */ - if (dldwd_proc_dev_init(priv) != 0) { + if (orinoco_proc_dev_init(priv) != 0) { printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n", ndev->name); goto failed; @@ -627,12 +629,9 @@ /* Note to myself : this replace MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT */ SET_MODULE_OWNER(ndev); - /* Allow cor_reset, /proc & ioctls to act */ - priv->hw_ready = 1; - /* Do a Pcmcia soft reset of the card (optional) */ - if(reset_cor) - dldwd_cs_cor_reset(priv); + if (reset_cor) + orinoco_cs_cor_reset(priv); /* At this point, the dev_node_t structure(s) need to be @@ -642,29 +641,29 @@ link->dev = &card->node; link->state &= ~DEV_CONFIG_PENDING; - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); return; cs_failed: cs_error(link->handle, last_fn, last_ret); failed: - dldwd_cs_release((u_long) link); + orinoco_cs_release((u_long) link); - TRACE_EXIT("dldwd"); -} /* dldwd_cs_config */ + TRACE_EXIT("orinoco"); +} /* orinoco_cs_config */ /*====================================================================== - After a card is removed, dldwd_cs_release() will unregister the + After a card is removed, orinoco_cs_release() will unregister the device, and release the PCMCIA configuration. If the device is still open, this will be postponed until it is closed. ======================================================================*/ static void -dldwd_cs_release(u_long arg) +orinoco_cs_release(u_long arg) { dev_link_t *link = (dev_link_t *) arg; - dldwd_priv_t *priv = link->priv; + struct orinoco_private *priv = link->priv; TRACE_ENTER(link->dev->dev_name); @@ -681,7 +680,7 @@ } /* Unregister proc entry */ - dldwd_proc_dev_cleanup(priv); + orinoco_proc_dev_cleanup(priv); /* Don't bother checking to see if these succeed or not */ CardServices(ReleaseConfiguration, link->handle); @@ -692,7 +691,7 @@ link->state &= ~DEV_CONFIG; TRACE_EXIT(link->dev->dev_name); -} /* dldwd_cs_release */ +} /* orinoco_cs_release */ /*====================================================================== The card status event handler. Mostly, this schedules other @@ -705,39 +704,37 @@ ======================================================================*/ static int -dldwd_cs_event(event_t event, int priority, +orinoco_cs_event(event_t event, int priority, event_callback_args_t * args) { dev_link_t *link = args->client_data; - dldwd_priv_t *priv = (dldwd_priv_t *)link->priv; + struct orinoco_private *priv = (struct orinoco_private *)link->priv; struct net_device *dev = &priv->ndev; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); switch (event) { case CS_EVENT_CARD_REMOVAL: - /* FIXME: Erg.. this whole hw_ready thing looks racy - to me. this may not be fixable without changin the - PCMCIA subsystem, though */ - priv->hw_ready = 0; - dldwd_shutdown(priv); link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { netif_stop_queue(dev); + } + orinoco_shutdown(priv); + if (link->state & DEV_CONFIG) { netif_device_detach(dev); mod_timer(&link->release, jiffies + HZ / 20); } break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - dldwd_cs_config(link); + orinoco_cs_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: - dldwd_shutdown(priv); + orinoco_shutdown(priv); /* Mark the device as stopped, to block IO until later */ if (link->state & DEV_CONFIG) { @@ -757,13 +754,13 @@ &link->conf); if (link->open) { - if (dldwd_reset(priv) == 0) { + if (orinoco_reset(priv) == 0) { netif_device_attach(dev); netif_start_queue(dev); } else { printk(KERN_ERR "%s: Error resetting device on PCMCIA event\n", dev->name); - dldwd_cs_stop(dev); + orinoco_cs_stop(dev); } } } @@ -774,17 +771,17 @@ break; } - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); return 0; -} /* dldwd_cs_event */ +} /* orinoco_cs_event */ static int __init -init_dldwd_cs(void) +init_orinoco_cs(void) { servinfo_t serv; - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); printk(KERN_DEBUG "%s\n", version); @@ -795,17 +792,17 @@ return -1; } - register_pccard_driver(&dev_info, &dldwd_cs_attach, &dldwd_cs_detach); + register_pccard_driver(&dev_info, &orinoco_cs_attach, &orinoco_cs_detach); - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); return 0; } static void __exit -exit_dldwd_cs(void) +exit_orinoco_cs(void) { - TRACE_ENTER("dldwd"); + TRACE_ENTER("orinoco"); unregister_pccard_driver(&dev_info); @@ -814,12 +811,12 @@ while (dev_list != NULL) { del_timer(&dev_list->release); if (dev_list->state & DEV_CONFIG) - dldwd_cs_release((u_long) dev_list); - dldwd_cs_detach(dev_list); + orinoco_cs_release((u_long) dev_list); + orinoco_cs_detach(dev_list); } - TRACE_EXIT("dldwd"); + TRACE_EXIT("orinoco"); } -module_init(init_dldwd_cs); -module_exit(exit_dldwd_cs); +module_init(init_orinoco_cs); +module_exit(exit_orinoco_cs); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/orinoco_plx.c linux-2.5/drivers/net/wireless/orinoco_plx.c --- linux-2.5.5/drivers/net/wireless/orinoco_plx.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/net/wireless/orinoco_plx.c Sun Feb 17 23:08:54 2002 @@ -1,16 +1,8 @@ -/* orinoco_plx.c 0.01 +/* orinoco_plx.c 0.09b * * Driver for Prism II devices which would usually be driven by orinoco_cs, * but are connected to the PCI bus by a PLX9052. * - * Specifically here we're talking about the SMC2602W (EZConnect - * Wireless PCI Adaptor) - * - * The actual driving is done by orinoco.c, this is just resource - * allocation stuff. The explanation below is courtesy of Ryan Niemi - * on the linux-wlan-ng list at - * http://archives.neohapsis.com/archives/dev/linux-wlan/2001-q1/0026.html - * * Copyright (C) 2001 Daniel Barlow * * The contents of this file are subject to the Mozilla Public License @@ -34,6 +26,22 @@ * provisions above, a recipient may use your version of this file * under either the MPL or the GPL. + * Caution: this is experimental and probably buggy. For success and + * failure reports for different cards and adaptors, see + * orinoco_plx_pci_id_table near the end of the file. If you have a + * card we don't have the PCI id for, and looks like it should work, + * drop me mail with the id and "it works"/"it doesn't work". + * + * Note: if everything gets detected fine but it doesn't actually send + * or receive packets, your first port of call should probably be to + * try newer firmware in the card. Especially if you're doing Ad-Hoc + * modes + * + * The actual driving is done by orinoco.c, this is just resource + * allocation stuff. The explanation below is courtesy of Ryan Niemi + * on the linux-wlan-ng list at + * http://archives.neohapsis.com/archives/dev/linux-wlan/2001-q1/0026.html + The PLX9052-based cards (WL11000 and several others) are a different beast than the usual PCMCIA-based PRISM2 configuration expected by wlan-ng. Here's the general details on how the WL11000 PCI adapter @@ -95,14 +103,6 @@ not have time for a while.. ---end of mail--- - - Bus 0, device 4, function 0: - Network controller: Unknown vendor Unknown device (rev 2). - Vendor id=1638. Device id=1100. - Medium devsel. Fast back-to-back capable. IRQ 10. - I/O at 0x1000 [0x1001]. - Non-prefetchable 32 bit memory at 0x40000000 [0x40000000]. - I/O at 0x10c0 [0x10c1]. */ #include @@ -140,25 +140,29 @@ #include "hermes.h" #include "orinoco.h" +static char version[] __initdata = "orinoco_plx.c 0.09b (Daniel Barlow )"; MODULE_AUTHOR("Daniel Barlow "); MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); MODULE_LICENSE("Dual MPL/GPL"); static dev_info_t dev_info = "orinoco_plx"; -#define COR_OFFSET 0x3e0 /* COR attribute offset of Prism2 PC card */ -#define COR_VALUE 0x41 /* Enable PC card with interrupt in level trigger */ +#define COR_OFFSET (0x3e0 / 2) /* COR attribute offset of Prism2 PC card */ +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ + +#define PLX_INTCSR 0x4c /* Interrupt Control and Status Register */ +#define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ static int orinoco_plx_open(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *) dev->priv; + struct orinoco_private *priv = (struct orinoco_private *) dev->priv; int err; netif_device_attach(dev); - err = dldwd_reset(priv); + err = orinoco_reset(priv); if (err) - printk(KERN_ERR "%s: dldwd_reset failed in orinoco_plx_open()", + printk(KERN_ERR "%s: orinoco_reset failed in orinoco_plx_open()", dev->name); else netif_start_queue(dev); @@ -168,108 +172,217 @@ static int orinoco_plx_stop(struct net_device *dev) { - dldwd_priv_t *priv = (dldwd_priv_t *) dev->priv; + struct orinoco_private *priv = (struct orinoco_private *) dev->priv; netif_stop_queue(dev); - dldwd_shutdown(priv); + orinoco_shutdown(priv); return 0; } static void orinoco_plx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - dldwd_interrupt(irq, ((struct net_device *) dev_id)->priv, regs); + orinoco_interrupt(irq, (struct orinoco_private *)dev_id, regs); } +static const u16 cis_magic[] = { + 0x0001, 0x0003, 0x0000, 0x0000, 0x00ff, 0x0017, 0x0004, 0x0067 +}; + static int orinoco_plx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct net_device *dev; - unsigned long pccard_ioaddr; + int err = 0; + u16 *attr_mem = NULL; + u32 reg, addr; + struct orinoco_private *priv = NULL; + unsigned long pccard_ioaddr = 0; + unsigned long pccard_iolen = 0; + struct net_device *dev = NULL; + int netdev_registered = 0; int i; - int reg; - unsigned char *attr_mem; - dldwd_priv_t *priv; - if ((i = pci_enable_device(pdev))) + TRACE_ENTER("orinoco_plx"); + + err = pci_enable_device(pdev); + if (err) return -EIO; /* Resource 2 is mapped to the PCMCIA space */ - attr_mem = ioremap(pci_resource_start(pdev, 2), 0x1000); - /* and 3 to the PCMCIA slot I/O address space */ - pccard_ioaddr = pci_resource_start(pdev, 3); + attr_mem = ioremap(pci_resource_start(pdev, 2), PAGE_SIZE); + if (! attr_mem) + goto fail; + + printk(KERN_DEBUG "orinoco_plx: CIS: "); + for (i = 0; i < 16; i++) { + printk("%02X:", (int)attr_mem[i]); + } + printk("\n"); /* Verify whether PC card is present */ - if (attr_mem[0] != 0x01 || attr_mem[2] != 0x03 || - attr_mem[4] != 0x00 || attr_mem[6] != 0x00 || - attr_mem[8] != 0xFF || attr_mem[10] != 0x17 || - attr_mem[12] != 0x04 || attr_mem[14] != 0x67) { + /* FIXME: we probably need to be smarted about this */ + if (memcmp(attr_mem, cis_magic, sizeof(cis_magic)) != 0) { printk(KERN_ERR "orinoco_plx: The CIS value of Prism2 PC card is invalid.\n"); - return -EIO; + err = -EIO; + goto fail; } + /* PCMCIA COR is the first byte following CIS: this write should * enable I/O mode and select level-triggered interrupts */ attr_mem[COR_OFFSET] = COR_VALUE; + mdelay(1); reg = attr_mem[COR_OFFSET]; - /* assert(reg==COR_VALUE); doesn't work */ - iounmap(attr_mem); /* done with this now, it seems */ - if (!request_region(pccard_ioaddr, - pci_resource_len(pdev, 3), dev_info)) { + if (reg != COR_VALUE) { + printk(KERN_ERR "orinoco_plx: Error setting COR value (reg=%x)\n", reg); + goto fail; + } + + iounmap(attr_mem); + attr_mem = NULL; /* done with this now, it seems */ + + /* bjoern: We need to tell the card to enable interrupts, in + case the serial eprom didn't do this already. See the + PLX9052 data book, p8-1 and 8-24 for reference. */ + addr = pci_resource_start(pdev, 1); + reg = 0; + reg = inl(addr+PLX_INTCSR); + if(reg & PLX_INTCSR_INTEN) + printk(KERN_DEBUG "orinoco_plx: " + "Local Interrupt already enabled\n"); + else { + reg |= PLX_INTCSR_INTEN; + outl(reg, addr+PLX_INTCSR); + reg = inl(addr+PLX_INTCSR); + if(!(reg & PLX_INTCSR_INTEN)) { + printk(KERN_ERR "orinoco_plx: " + "Couldn't enable Local Interrupts\n"); + goto fail; + } + } + + /* and 3 to the PCMCIA slot I/O address space */ + pccard_ioaddr = pci_resource_start(pdev, 3); + pccard_iolen = pci_resource_len(pdev, 3); + if (! request_region(pccard_ioaddr, pccard_iolen, dev_info)) { printk(KERN_ERR "orinoco_plx: I/O resource 0x%lx @ 0x%lx busy\n", - pci_resource_len(pdev, 3), pccard_ioaddr); - return -EBUSY; + pccard_iolen, pccard_ioaddr); + pccard_ioaddr = 0; + err = -EBUSY; + goto fail; + } + + priv = kmalloc(sizeof(*priv), GFP_KERNEL); + if (! priv) { + err = -ENOMEM; + goto fail; } - if (!(priv = kmalloc(sizeof(*priv), GFP_KERNEL))) - return -ENOMEM; memset(priv, 0, sizeof(*priv)); + dev = &priv->ndev; - dldwd_setup(priv); /* XXX clean up if <0 */ - dev->irq = pdev->irq; + err = orinoco_setup(priv); + if (err) + goto fail; dev->base_addr = pccard_ioaddr; dev->open = orinoco_plx_open; dev->stop = orinoco_plx_stop; priv->card_reset_handler = NULL; /* We have no reset handler */ + SET_MODULE_OWNER(dev); printk(KERN_DEBUG - "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lx, irq:%d, io addr:0x%lx\n", - pdev->slot_name, (long) attr_mem, pdev->irq, pccard_ioaddr); + "Detected Orinoco/Prism2 PLX device at %s irq:%d, io addr:0x%lx\n", + pdev->slot_name, pdev->irq, pccard_ioaddr); - hermes_struct_init(&(priv->hw), dev->base_addr); /* XXX */ - dev->name[0] = '\0'; /* name defaults to ethX */ - register_netdev(dev); - request_irq(pdev->irq, orinoco_plx_interrupt, SA_SHIRQ, dev->name, - dev); - if (dldwd_proc_dev_init(priv) != 0) { - printk(KERN_ERR "%s: Failed to create /proc node\n", dev->name); - return -EIO; + hermes_struct_init(&(priv->hw), dev->base_addr); + pci_set_drvdata(pdev, priv); + + err = request_irq(pdev->irq, orinoco_plx_interrupt, SA_SHIRQ, dev->name, priv); + if (err) { + printk(KERN_ERR "orinoco_plx: Error allocating IRQ %d.\n", pdev->irq); + err = -EBUSY; + goto fail; } + dev->irq = pdev->irq; - SET_MODULE_OWNER(dev); - priv->hw_ready = 1; + err = register_netdev(dev); + if (err) + goto fail; + netdev_registered = 1; + + err = orinoco_proc_dev_init(priv); + if (err) + goto fail; + + TRACE_EXIT("orinoco_plx"); - /* if(reset_cor) dldwd_cs_cor_reset(priv); */ return 0; /* succeeded */ + + fail: + printk(KERN_DEBUG "orinoco_plx: init_one(), FAIL!\n"); + + if (priv) { + orinoco_proc_dev_cleanup(priv); + + if (netdev_registered) + unregister_netdev(dev); + + if (dev->irq) + free_irq(dev->irq, priv); + + kfree(priv); + } + + if (pccard_ioaddr) + release_region(pccard_ioaddr, pccard_iolen); + + if (attr_mem) + iounmap(attr_mem); + + pci_disable_device(pdev); + + TRACE_EXIT("orinoco_plx"); + + return err; } static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - dldwd_priv_t *priv = dev->priv; + struct orinoco_private *priv = pci_get_drvdata(pdev); + struct net_device *dev = &priv->ndev; - if (!dev) + TRACE_ENTER("orinoco_plx"); + + if (!priv) BUG(); - dldwd_proc_dev_cleanup(priv); - free_irq(dev->irq, dev); + orinoco_proc_dev_cleanup(priv); + unregister_netdev(dev); - release_region(dev->base_addr, 0x40); - kfree(dev->priv); - pci_set_drvdata(pdev, NULL); + + if (dev->irq) + free_irq(dev->irq, priv); + + kfree(priv); + + release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3)); + + pci_disable_device(pdev); + + TRACE_EXIT("orinoco_plx"); } static struct pci_device_id orinoco_plx_pci_id_table[] __devinitdata = { - {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, + {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ +#if 0 + {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga */ +#endif + {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W, + Eumitcom PCI WL11000, + Addtron AWA-100*/ + {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */ + {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */ + {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */ + {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */ {0,}, }; @@ -279,19 +392,22 @@ name:"orinoco_plx", id_table:orinoco_plx_pci_id_table, probe:orinoco_plx_init_one, - remove:orinoco_plx_remove_one, + remove:__devexit_p(orinoco_plx_remove_one), suspend:0, resume:0 }; static int __init orinoco_plx_init(void) { + printk(KERN_DEBUG "%s\n", version); return pci_module_init(&orinoco_plx_driver); } extern void __exit orinoco_plx_exit(void) { pci_unregister_driver(&orinoco_plx_driver); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); } module_init(orinoco_plx_init); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/wavelan.c linux-2.5/drivers/net/wireless/wavelan.c --- linux-2.5.5/drivers/net/wireless/wavelan.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/net/wireless/wavelan.c Tue Feb 26 21:24:49 2002 @@ -24,28 +24,6 @@ /*------------------------------------------------------------------*/ /* - * Wrapper for disabling interrupts and locking the driver. - * (note : inline, so optimised away) - */ -static inline void wv_splhi(net_local * lp, - unsigned long * pflags) -{ - spin_lock_irqsave(&lp->spinlock, *pflags); - /* Note : above does the cli(); itself */ -} - -/*------------------------------------------------------------------*/ -/* - * Wrapper for re-enabling interrupts and un-locking the driver. - */ -static inline void wv_splx(net_local * lp, - unsigned long * pflags) -{ - spin_unlock_irqrestore(&lp->spinlock, *pflags); -} - -/*------------------------------------------------------------------*/ -/* * Translate irq number to PSA irq parameter */ static u8 wv_irq_to_psa(int irq) @@ -870,10 +848,10 @@ /* Check if we can do it now ! */ if((netif_running(dev)) && !(netif_queue_stopped(dev))) { - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* May fail */ wv_82586_config(dev); - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); } else { #ifdef DEBUG_CONFIG_INFO @@ -1786,170 +1764,287 @@ /*------------------------------------------------------------------*/ /* - * Perform ioctl for configuration and information. - * It is here that the wireless extensions are treated (iwconfig). + * Wireless Handler : get protocol name */ -static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is applied */ - struct ifreq *rq, /* data passed */ - int cmd) -{ /* ioctl number */ +static int wavelan_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + strcpy(wrqu->name, "WaveLAN"); + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set NWID + */ +static int wavelan_set_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ unsigned long ioaddr = dev->base_addr; net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - struct iwreq *wrq = (struct iwreq *) rq; psa_t psa; mm_t m; unsigned long flags; int ret = 0; - int err = 0; -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, - cmd); -#endif + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Set NWID in WaveLAN. */ + if (!wrqu->nwid.disabled) { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; + psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; + psa.psa_nwid_select = 0x01; + psa_write(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + + /* Set NWID in mmc. */ + m.w.mmw_netw_id_l = psa.psa_nwid[1]; + m.w.mmw_netw_id_h = psa.psa_nwid[0]; + mmc_write(ioaddr, + (char *) &m.w.mmw_netw_id_l - + (char *) &m, + (unsigned char *) &m.w.mmw_netw_id_l, 2); + mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); + } else { + /* Disable NWID in the psa. */ + psa.psa_nwid_select = 0x00; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_nwid_select - + (char *) &psa, + (unsigned char *) &psa.psa_nwid_select, + 1); + + /* Disable NWID in the mmc (no filtering). */ + mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), + MMW_LOOPT_SEL_DIS_NWID); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get NWID + */ +static int wavelan_get_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; /* Disable interrupts and save flags. */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); - /* Look what is the request */ - switch (cmd) { - /* --------------- WIRELESS EXTENSIONS --------------- */ - - case SIOCGIWNAME: - strcpy(wrq->u.name, "WaveLAN"); - break; - - case SIOCSIWNWID: - /* Set NWID in WaveLAN. */ - if (!wrq->u.nwid.disabled) { - /* Set NWID in psa */ - psa.psa_nwid[0] = - (wrq->u.nwid.value & 0xFF00) >> 8; - psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF; - psa.psa_nwid_select = 0x01; - psa_write(ioaddr, lp->hacr, - (char *) psa.psa_nwid - (char *) &psa, - (unsigned char *) psa.psa_nwid, 3); + /* Read the NWID. */ + psa_read(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrqu->nwid.disabled = !(psa.psa_nwid_select); + wrqu->nwid.fixed = 1; /* Superfluous */ - /* Set NWID in mmc. */ - m.w.mmw_netw_id_l = psa.psa_nwid[1]; - m.w.mmw_netw_id_h = psa.psa_nwid[0]; - mmc_write(ioaddr, - (char *) &m.w.mmw_netw_id_l - - (char *) &m, - (unsigned char *) &m.w.mmw_netw_id_l, 2); - mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); - } else { - /* Disable NWID in the psa. */ - psa.psa_nwid_select = 0x00; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_nwid_select - - (char *) &psa, - (unsigned char *) &psa.psa_nwid_select, - 1); + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - /* Disable NWID in the mmc (no filtering). */ - mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), - MMW_LOOPT_SEL_DIS_NWID); - } - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - break; + return ret; +} - case SIOCGIWNWID: - /* Read the NWID. */ - psa_read(ioaddr, lp->hacr, - (char *) psa.psa_nwid - (char *) &psa, - (unsigned char *) psa.psa_nwid, 3); - wrq->u.nwid.value = - (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; - wrq->u.nwid.disabled = !(psa.psa_nwid_select); - wrq->u.nwid.fixed = 1; /* Superfluous */ - break; - - case SIOCSIWFREQ: - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - ret = wv_set_frequency(ioaddr, &(wrq->u.freq)); - else - ret = -EOPNOTSUPP; - break; +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set frequency + */ +static int wavelan_set_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + int ret; - case SIOCGIWFREQ: - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). - * Does it work for everybody, especially old cards? */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { - unsigned short freq; - - /* Ask the EEPROM to read the frequency from the first area. */ - fee_read(ioaddr, 0x00, &freq, 1); - wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; - wrq->u.freq.e = 1; - } else { - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_subband - (char *) &psa, - (unsigned char *) &psa.psa_subband, 1); - - if (psa.psa_subband <= 4) { - wrq->u.freq.m = - fixed_bands[psa.psa_subband]; - wrq->u.freq.e = (psa.psa_subband != 0); - } else - ret = -EOPNOTSUPP; - } - break; + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + ret = wv_set_frequency(ioaddr, &(wrqu->freq)); + else + ret = -EOPNOTSUPP; - case SIOCSIWSENS: - /* Set the level threshold. */ - /* We should complain loudly if wrq->u.sens.fixed = 0, because we - * can't set auto mode... */ - psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_thr_pre_set - (char *) &psa, - (unsigned char *) &psa.psa_thr_pre_set, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), - psa.psa_thr_pre_set); - break; + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} - case SIOCGIWSENS: - /* Read the level threshold. */ +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get frequency + */ +static int wavelan_get_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). + * Does it work for everybody, especially old cards? */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + unsigned short freq; + + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(ioaddr, 0x00, &freq, 1); + wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000; + wrqu->freq.e = 1; + } else { psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_thr_pre_set - (char *) &psa, - (unsigned char *) &psa.psa_thr_pre_set, 1); - wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; - wrq->u.sens.fixed = 1; - break; - - case SIOCSIWENCODE: - /* Set encryption key */ - if (!mmc_encr(ioaddr)) { + (char *) &psa.psa_subband - (char *) &psa, + (unsigned char *) &psa.psa_subband, 1); + + if (psa.psa_subband <= 4) { + wrqu->freq.m = fixed_bands[psa.psa_subband]; + wrqu->freq.e = (psa.psa_subband != 0); + } else ret = -EOPNOTSUPP; - break; - } + } - /* Basic checking... */ - if (wrq->u.encoding.pointer != (caddr_t) 0) { - /* Check the size of the key */ - if (wrq->u.encoding.length != 8) { - ret = -EINVAL; - break; - } + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - /* Copy the key in the driver */ - wv_splx(lp, &flags); - err = copy_from_user(psa.psa_encryption_key, - wrq->u.encoding.pointer, - wrq->u.encoding.length); - wv_splhi(lp, &flags); - if (err) { - ret = -EFAULT; - break; - } + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set level threshold + */ +static int wavelan_set_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Set the level threshold. */ + /* We should complain loudly if wrqu->sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), + psa.psa_thr_pre_set); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get level threshold + */ +static int wavelan_get_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Read the level threshold. */ + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; + wrqu->sens.fixed = 1; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set encryption key + */ +static int wavelan_set_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + psa_t psa; + int ret = 0; + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check if capable of encryption */ + if (!mmc_encr(ioaddr)) { + ret = -EOPNOTSUPP; + } + + /* Check the size of the key */ + if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) { + ret = -EINVAL; + } + + if(!ret) { + /* Basic checking... */ + if (wrqu->encoding.length == 8) { + /* Copy the key in the driver */ + memcpy(psa.psa_encryption_key, extra, + wrqu->encoding.length); psa.psa_encryption_select = 1; + psa_write(ioaddr, lp->hacr, (char *) &psa.psa_encryption_select - (char *) &psa, @@ -1963,7 +2058,8 @@ psa_encryption_key, 8); } - if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) { /* disable encryption */ + /* disable encryption */ + if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { psa.psa_encryption_select = 0; psa_write(ioaddr, lp->hacr, (char *) &psa.psa_encryption_select - @@ -1975,350 +2071,430 @@ } /* update the Wavelan checksum */ update_psa_checksum(dev, ioaddr, lp->hacr); - break; + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} - case SIOCGIWENCODE: +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get encryption key + */ +static int wavelan_get_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check if encryption is available */ + if (!mmc_encr(ioaddr)) { + ret = -EOPNOTSUPP; + } else { /* Read the encryption key */ - if (!mmc_encr(ioaddr)) { - ret = -EOPNOTSUPP; - break; - } + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1 + 8); + + /* encryption is enabled ? */ + if (psa.psa_encryption_select) + wrqu->encoding.flags = IW_ENCODE_ENABLED; + else + wrqu->encoding.flags = IW_ENCODE_DISABLED; + wrqu->encoding.flags |= mmc_encr(ioaddr); - /* only super-user can see encryption key */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } + /* Copy the key to the user buffer */ + wrqu->encoding.length = 8; + memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length); + } - /* Basic checking... */ - if (wrq->u.encoding.pointer != (caddr_t) 0) { - /* Verify the user buffer */ - ret = - verify_area(VERIFY_WRITE, - wrq->u.encoding.pointer, 8); - if (ret) - break; - - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_encryption_select - - (char *) &psa, - (unsigned char *) &psa. - psa_encryption_select, 1 + 8); - - /* encryption is enabled ? */ - if (psa.psa_encryption_select) - wrq->u.encoding.flags = IW_ENCODE_ENABLED; - else - wrq->u.encoding.flags = IW_ENCODE_DISABLED; - wrq->u.encoding.flags |= mmc_encr(ioaddr); + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - /* Copy the key to the user buffer */ - wrq->u.encoding.length = 8; - wv_splx(lp, &flags); - if (copy_to_user(wrq->u.encoding.pointer, - psa.psa_encryption_key, 8)) - ret = -EFAULT; - wv_splhi(lp, &flags); - } - break; + return ret; +} - case SIOCGIWRANGE: - /* basic checking */ - if (wrq->u.data.pointer != (caddr_t) 0) { - struct iw_range range; - - /* Set the length (very important for backward - * compatibility) */ - wrq->u.data.length = sizeof(struct iw_range); - - /* Set all the info we don't care or don't know - * about to zero */ - memset(&range, 0, sizeof(range)); - - /* Set the Wireless Extension versions */ - range.we_version_compiled = WIRELESS_EXT; - range.we_version_source = 9; - - /* Set information in the range struct. */ - range.throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ - range.min_nwid = 0x0000; - range.max_nwid = 0xFFFF; - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { - range.num_channels = 10; - range.num_frequency = - wv_frequency_list(ioaddr, range.freq, - IW_MAX_FREQUENCIES); - } else - range.num_channels = range.num_frequency = - 0; - - range.sensitivity = 0x3F; - range.max_qual.qual = MMR_SGNL_QUAL; - range.max_qual.level = MMR_SIGNAL_LVL; - range.max_qual.noise = MMR_SILENCE_LVL; - range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ - /* Need to get better values for those two */ - range.avg_qual.level = 30; - range.avg_qual.noise = 8; - - range.num_bitrates = 1; - range.bitrate[0] = 2000000; /* 2 Mb/s */ - - /* Encryption supported ? */ - if (mmc_encr(ioaddr)) { - range.encoding_size[0] = 8; /* DES = 64 bits key */ - range.num_encoding_sizes = 1; - range.max_encoding_tokens = 1; /* Only one key possible */ - } else { - range.num_encoding_sizes = 0; - range.max_encoding_tokens = 0; - } +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get range info + */ +static int wavelan_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct iw_range *range = (struct iw_range *) extra; + unsigned long flags; + int ret = 0; - /* Copy structure to the user buffer. */ - wv_splx(lp, &flags); - if (copy_to_user(wrq->u.data.pointer, - &range, - sizeof(struct iw_range))) - ret = -EFAULT; - wv_splhi(lp, &flags); - } - break; + /* Set the length (very important for backward compatibility) */ + wrqu->data.length = sizeof(struct iw_range); - case SIOCGIWPRIV: - /* Basic checking */ - if (wrq->u.data.pointer != (caddr_t) 0) { - struct iw_priv_args priv[] = { - /* { cmd, - set_args, - get_args, - name } */ - { SIOCSIPQTHR, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - 0, - "setqualthr" }, - { SIOCGIPQTHR, - 0, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - "getqualthr" }, - { SIOCSIPHISTO, - IW_PRIV_TYPE_BYTE | 16, - 0, - "sethisto" }, - { SIOCGIPHISTO, - 0, - IW_PRIV_TYPE_INT | 16, - "gethisto" }, - }; - - /* Set the number of available ioctls. */ - wrq->u.data.length = 4; - - /* Copy structure to the user buffer. */ - wv_splx(lp, &flags); - if (copy_to_user(wrq->u.data.pointer, - (u8 *) priv, - sizeof(priv))) - ret = -EFAULT; - wv_splhi(lp, &flags); - } - break; + /* Set all the info we don't care or don't know about to zero */ + memset(range, 0, sizeof(struct iw_range)); -#ifdef WIRELESS_SPY - case SIOCSIWSPY: - /* Set the spy list */ + /* Set the Wireless Extension versions */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 9; + + /* Set information in the range struct. */ + range->throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ + range->min_nwid = 0x0000; + range->max_nwid = 0xFFFF; + + range->sensitivity = 0x3F; + range->max_qual.qual = MMR_SGNL_QUAL; + range->max_qual.level = MMR_SIGNAL_LVL; + range->max_qual.noise = MMR_SILENCE_LVL; + range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ + /* Need to get better values for those two */ + range->avg_qual.level = 30; + range->avg_qual.noise = 8; - /* Check the number of addresses. */ - if (wrq->u.data.length > IW_MAX_SPY) { - ret = -E2BIG; - break; - } - lp->spy_number = wrq->u.data.length; + range->num_bitrates = 1; + range->bitrate[0] = 2000000; /* 2 Mb/s */ - /* Are there are addresses to copy? */ - if (lp->spy_number > 0) { - struct sockaddr address[IW_MAX_SPY]; - int i; - - /* Copy addresses to the driver. */ - wv_splx(lp, &flags); - err = copy_from_user(address, - wrq->u.data.pointer, - sizeof(struct sockaddr) - * lp->spy_number); - wv_splhi(lp, &flags); - if (err) { - ret = -EFAULT; - break; - } + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + range->num_channels = 10; + range->num_frequency = wv_frequency_list(ioaddr, range->freq, + IW_MAX_FREQUENCIES); + } else + range->num_channels = range->num_frequency = 0; - /* Copy addresses to the lp structure. */ - for (i = 0; i < lp->spy_number; i++) { - memcpy(lp->spy_address[i], - address[i].sa_data, - WAVELAN_ADDR_SIZE); - } + /* Encryption supported ? */ + if (mmc_encr(ioaddr)) { + range->encoding_size[0] = 8; /* DES = 64 bits key */ + range->num_encoding_sizes = 1; + range->max_encoding_tokens = 1; /* Only one key possible */ + } else { + range->num_encoding_sizes = 0; + range->max_encoding_tokens = 0; + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +#ifdef WIRELESS_SPY +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set spy list + */ +static int wavelan_set_spy(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct sockaddr *address = (struct sockaddr *) extra; + int i; + int ret = 0; - /* Reset structure. */ - memset(lp->spy_stat, 0x00, - sizeof(iw_qual) * IW_MAX_SPY); + /* Disable spy while we copy the addresses. + * As we don't disable interrupts, we need to do this */ + lp->spy_number = 0; + + /* Are there are addresses to copy? */ + if (wrqu->data.length > 0) { + /* Copy addresses to the lp structure. */ + for (i = 0; i < wrqu->data.length; i++) { + memcpy(lp->spy_address[i], address[i].sa_data, + WAVELAN_ADDR_SIZE); + } + + /* Reset structure. */ + memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); #ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG + "SetSpy: set of new addresses is: \n"); + for (i = 0; i < wrqu->data.length; i++) printk(KERN_DEBUG - "SetSpy: set of new addresses is: \n"); - for (i = 0; i < wrq->u.data.length; i++) - printk(KERN_DEBUG - "%02X:%02X:%02X:%02X:%02X:%02X \n", - lp->spy_address[i][0], - lp->spy_address[i][1], - lp->spy_address[i][2], - lp->spy_address[i][3], - lp->spy_address[i][4], - lp->spy_address[i][5]); -#endif /* DEBUG_IOCTL_INFO */ - } + "%02X:%02X:%02X:%02X:%02X:%02X \n", + lp->spy_address[i][0], + lp->spy_address[i][1], + lp->spy_address[i][2], + lp->spy_address[i][3], + lp->spy_address[i][4], + lp->spy_address[i][5]); +#endif /* DEBUG_IOCTL_INFO */ + } + + /* Now we can set the number of addresses */ + lp->spy_number = wrqu->data.length; + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get spy list + */ +static int wavelan_get_spy(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct sockaddr *address = (struct sockaddr *) extra; + int i; - break; + /* Set the number of addresses */ + wrqu->data.length = lp->spy_number; - case SIOCGIWSPY: - /* Get the spy list and spy stats. */ + /* Copy addresses from the lp structure. */ + for (i = 0; i < lp->spy_number; i++) { + memcpy(address[i].sa_data, + lp->spy_address[i], + WAVELAN_ADDR_SIZE); + address[i].sa_family = AF_UNIX; + } + /* Copy stats to the user buffer (just after). */ + if(lp->spy_number > 0) + memcpy(extra + (sizeof(struct sockaddr) * lp->spy_number), + lp->spy_stat, sizeof(iw_qual) * lp->spy_number); - /* Set the number of addresses */ - wrq->u.data.length = lp->spy_number; + /* Reset updated flags. */ + for (i = 0; i < lp->spy_number; i++) + lp->spy_stat[i].updated = 0x0; - /* Does the user want to have the addresses back? */ - if ((lp->spy_number > 0) - && (wrq->u.data.pointer != (caddr_t) 0)) { - struct sockaddr address[IW_MAX_SPY]; - int i; - - /* Copy addresses from the lp structure. */ - for (i = 0; i < lp->spy_number; i++) { - memcpy(address[i].sa_data, - lp->spy_address[i], - WAVELAN_ADDR_SIZE); - address[i].sa_family = AF_UNIX; - } + return(0); +} +#endif /* WIRELESS_SPY */ - /* Copy addresses to the user buffer. */ - wv_splx(lp, &flags); - err = copy_to_user(wrq->u.data.pointer, - address, - sizeof(struct sockaddr) - * lp->spy_number); - - /* Copy stats to the user buffer (just after). */ - err |= copy_to_user(wrq->u.data.pointer - + (sizeof(struct sockaddr) - * lp->spy_number), - lp->spy_stat, - sizeof(iw_qual) * lp->spy_number); - wv_splhi(lp, &flags); - if (err) { - ret = -EFAULT; - break; - } +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set quality threshold + */ +static int wavelan_set_qthr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; - /* Reset updated flags. */ - for (i = 0; i < lp->spy_number; i++) - lp->spy_stat[i].updated = 0x0; - } - /* if(pointer != NULL) */ - break; -#endif /* WIRELESS_SPY */ + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + psa.psa_quality_thr = *(extra) & 0x0F; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), + psa.psa_quality_thr); - /* ------------------ PRIVATE IOCTL ------------------ */ + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - case SIOCSIPQTHR: - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - psa.psa_quality_thr = *(wrq->u.name) & 0x0F; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_quality_thr - (char *) &psa, - (unsigned char *) &psa.psa_quality_thr, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), - psa.psa_quality_thr); - break; + return 0; +} - case SIOCGIPQTHR: - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_quality_thr - (char *) &psa, - (unsigned char *) &psa.psa_quality_thr, 1); - *(wrq->u.name) = psa.psa_quality_thr & 0x0F; - break; +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get quality threshold + */ +static int wavelan_get_qthr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + *(extra) = psa.psa_quality_thr & 0x0F; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return 0; +} #ifdef HISTOGRAM - case SIOCSIPHISTO: - /* Verify that the user is root. */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set histogram + */ +static int wavelan_set_histo(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - /* Check the number of intervals. */ - if (wrq->u.data.length > 16) { - ret = -E2BIG; - break; - } - lp->his_number = wrq->u.data.length; + /* Check the number of intervals. */ + if (wrqu->data.length > 16) { + return(-E2BIG); + } - /* Are there addresses to copy? */ - if (lp->his_number > 0) { - /* Copy interval ranges to the driver */ - wv_splx(lp, &flags); - err = copy_from_user(lp->his_range, - wrq->u.data.pointer, - sizeof(char) * lp->his_number); - wv_splhi(lp, &flags); - if (err) { - ret = -EFAULT; - break; - } + /* Disable histo while we copy the addresses. + * As we don't disable interrupts, we need to do this */ + lp->his_number = 0; + + /* Are there ranges to copy? */ + if (wrqu->data.length > 0) { + /* Copy interval ranges to the driver */ + memcpy(lp->his_range, extra, wrqu->data.length); - /* Reset structure. */ - memset(lp->his_sum, 0x00, sizeof(long) * 16); + { + int i; + printk(KERN_DEBUG "Histo :"); + for(i = 0; i < wrqu->data.length; i++) + printk(" %d", lp->his_range[i]); + printk("\n"); } - break; - case SIOCGIPHISTO: - /* Set the number of intervals. */ - wrq->u.data.length = lp->his_number; - - /* Give back the distribution statistics */ - if ((lp->his_number > 0) - && (wrq->u.data.pointer != (caddr_t) 0)) { - /* Copy data to the user buffer. */ - wv_splx(lp, &flags); - if (copy_to_user(wrq->u.data.pointer, - lp->his_sum, - sizeof(long) * lp->his_number); - ret = -EFAULT; - wv_splhi(lp, &flags); + /* Reset result structure. */ + memset(lp->his_sum, 0x00, sizeof(long) * 16); + } - } /* if(pointer != NULL) */ - break; -#endif /* HISTOGRAM */ + /* Now we can set the number of ranges */ + lp->his_number = wrqu->data.length; + + return(0); +} - /* ------------------- OTHER IOCTL ------------------- */ +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get histogram + */ +static int wavelan_get_histo(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - default: - ret = -EOPNOTSUPP; - } /* switch (cmd) */ + /* Set the number of intervals. */ + wrqu->data.length = lp->his_number; - /* Enable interrupts and restore flags. */ - wv_splx(lp, &flags); + /* Give back the distribution statistics */ + if(lp->his_number > 0) + memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number); -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); -#endif - return ret; + return(0); } +#endif /* HISTOGRAM */ + +/*------------------------------------------------------------------*/ +/* + * Structures to export the Wireless Handlers + */ + +static const iw_handler wavelan_handler[] = +{ + NULL, /* SIOCSIWNAME */ + wavelan_get_name, /* SIOCGIWNAME */ + wavelan_set_nwid, /* SIOCSIWNWID */ + wavelan_get_nwid, /* SIOCGIWNWID */ + wavelan_set_freq, /* SIOCSIWFREQ */ + wavelan_get_freq, /* SIOCGIWFREQ */ + NULL, /* SIOCSIWMODE */ + NULL, /* SIOCGIWMODE */ + wavelan_set_sens, /* SIOCSIWSENS */ + wavelan_get_sens, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + wavelan_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ +#ifdef WIRELESS_SPY + wavelan_set_spy, /* SIOCSIWSPY */ + wavelan_get_spy, /* SIOCGIWSPY */ +#else /* WIRELESS_SPY */ + NULL, /* SIOCSIWSPY */ + NULL, /* SIOCGIWSPY */ +#endif /* WIRELESS_SPY */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWAP */ + NULL, /* SIOCGIWAP */ + NULL, /* -- hole -- */ + NULL, /* SIOCGIWAPLIST */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWESSID */ + NULL, /* SIOCGIWESSID */ + NULL, /* SIOCSIWNICKN */ + NULL, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWRATE */ + NULL, /* SIOCGIWRATE */ + NULL, /* SIOCSIWRTS */ + NULL, /* SIOCGIWRTS */ + NULL, /* SIOCSIWFRAG */ + NULL, /* SIOCGIWFRAG */ + NULL, /* SIOCSIWTXPOW */ + NULL, /* SIOCGIWTXPOW */ + NULL, /* SIOCSIWRETRY */ + NULL, /* SIOCGIWRETRY */ + /* Bummer ! Why those are only at the end ??? */ + wavelan_set_encode, /* SIOCSIWENCODE */ + wavelan_get_encode, /* SIOCGIWENCODE */ +}; + +static const iw_handler wavelan_private_handler[] = +{ + wavelan_set_qthr, /* SIOCIWFIRSTPRIV */ + wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */ +#ifdef HISTOGRAM + wavelan_set_histo, /* SIOCIWFIRSTPRIV + 2 */ + wavelan_get_histo, /* SIOCIWFIRSTPRIV + 3 */ +#endif /* HISTOGRAM */ +}; + +static const struct iw_priv_args wavelan_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, + { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, + { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, + { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, +}; + +static const struct iw_handler_def wavelan_handler_def = +{ + num_standard: sizeof(wavelan_handler)/sizeof(iw_handler), + num_private: sizeof(wavelan_private_handler)/sizeof(iw_handler), + num_private_args: sizeof(wavelan_private_args)/sizeof(struct iw_priv_args), + standard: (iw_handler *) wavelan_handler, + private: (iw_handler *) wavelan_private_handler, + private_args: (struct iw_priv_args *) wavelan_private_args, +}; /*------------------------------------------------------------------*/ /* @@ -2343,7 +2519,7 @@ return (iw_stats *) NULL; /* Disable interrupts and save flags. */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); wstats = &lp->wstats; @@ -2371,7 +2547,7 @@ wstats->discard.misc = 0L; /* Enable interrupts and restore flags. */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", @@ -2705,7 +2881,7 @@ if (clen < ETH_ZLEN) clen = ETH_ZLEN; - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Check nothing bad has happened */ if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { @@ -2713,7 +2889,7 @@ printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n", dev->name); #endif - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); return 1; } @@ -2791,7 +2967,7 @@ if (lp->tx_n_in_use < NTXBLOCKS - 1) netif_wake_queue(dev); - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_TX_INFO wv_packet_info((u8 *) buf, length, dev->name, @@ -2832,9 +3008,9 @@ * we can do it now. */ if (lp->reconfig_82586) { - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); wv_82586_config(dev); - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); /* Check that we can continue */ if (lp->tx_n_in_use == (NTXBLOCKS - 1)) return 1; @@ -3694,7 +3870,7 @@ /* Prevent reentrancy. We need to do that because we may have * multiple interrupt handler running concurrently. - * It is safe because wv_splhi() disables interrupts before acquiring + * It is safe because interrupts are disabled before acquiring * the spinlock. */ spin_lock(&lp->spinlock); @@ -3822,7 +3998,7 @@ return; } - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Try to see if some buffers are not free (in case we missed * an interrupt */ @@ -3862,7 +4038,7 @@ if (lp->tx_n_in_use < NTXBLOCKS - 1) netif_wake_queue(dev); - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); @@ -3909,7 +4085,7 @@ return -EAGAIN; } - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); if (wv_hw_reset(dev) != -1) { netif_start_queue(dev); @@ -3920,10 +4096,10 @@ "%s: wavelan_open(): impossible to start the card\n", dev->name); #endif - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); return -EAGAIN; } - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); @@ -3951,9 +4127,9 @@ /* * Flush the Tx and disable Rx. */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); wv_82586_stop(dev); - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); free_irq(dev->irq, dev); @@ -4069,8 +4245,8 @@ #endif /* SET_MAC_ADDRESS */ #ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ - dev->do_ioctl = wavelan_ioctl; dev->get_wireless_stats = wavelan_get_wireless_stats; + dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def; #endif dev->mtu = WAVELAN_MTU; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/wavelan.p.h linux-2.5/drivers/net/wireless/wavelan.p.h --- linux-2.5.5/drivers/net/wireless/wavelan.p.h Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/net/wireless/wavelan.p.h Tue Feb 26 21:24:49 2002 @@ -345,6 +345,12 @@ * - Fix spinlock stupid bugs that I left in. The driver is now SMP * compliant and doesn't lockup at startup. * + * Changes made for release in 2.5.2 : + * --------------------------------- + * - Use new driver API for Wireless Extensions : + * o got rid of wavelan_ioctl() + * o use a bunch of iw_handler instead + * * Wishes & dreams: * ---------------- * - roaming (see Pcmcia driver) @@ -379,6 +385,7 @@ #include #include /* Wireless extensions */ +#include /* Wireless handlers */ /* WaveLAN declarations */ #include "i82586.h" @@ -436,7 +443,7 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan.c : v23 (SMP + wireless extensions) 05/10/00\n"; +static const char *version = "wavelan.c : v24 (SMP + wireless extensions) 11/12/01\n"; #endif /* Watchdog temporisation */ @@ -449,11 +456,9 @@ #define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ #define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ -#define SIOCSIPLTHR SIOCIWFIRSTPRIV + 2 /* Set level threshold */ -#define SIOCGIPLTHR SIOCIWFIRSTPRIV + 3 /* Get level threshold */ -#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */ -#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */ +#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 2 /* Set histogram ranges */ +#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 3 /* Get histogram values */ /****************************** TYPES ******************************/ @@ -516,12 +521,6 @@ /**************************** PROTOTYPES ****************************/ /* ----------------------- MISC. SUBROUTINES ------------------------ */ -static inline void - wv_splhi(net_local *, /* Disable interrupts, lock driver */ - unsigned long *); /* flags */ -static inline void - wv_splx(net_local *, /* Enable interrupts, unlock driver */ - unsigned long *); /* flags */ static u_char wv_irq_to_psa(int); static int diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/wavelan_cs.c linux-2.5/drivers/net/wireless/wavelan_cs.c --- linux-2.5.5/drivers/net/wireless/wavelan_cs.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/net/wireless/wavelan_cs.c Tue Feb 26 21:24:49 2002 @@ -66,34 +66,6 @@ /*------------------------------------------------------------------*/ /* - * Wrapper for disabling interrupts. - * (note : inline, so optimised away) - */ -static inline void -wv_splhi(net_local * lp, - unsigned long * pflags) -{ - spin_lock_irqsave(&lp->spinlock, *pflags); - /* Note : above does the cli(); itself */ -} - -/*------------------------------------------------------------------*/ -/* - * Wrapper for re-enabling interrupts. - */ -static inline void -wv_splx(net_local * lp, - unsigned long * pflags) -{ - spin_unlock_irqrestore(&lp->spinlock, *pflags); - - /* Note : enabling interrupts on the hardware is done in wv_ru_start() - * via : outb(OP1_INT_ENABLE, LCCR(base)); - */ -} - -/*------------------------------------------------------------------*/ -/* * Wrapper for reporting error to cardservices */ static void cs_error(client_handle_t handle, int func, int ret) @@ -591,7 +563,7 @@ #endif /* Disable interrupts & save flags */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00; mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1); @@ -602,7 +574,7 @@ lp->cell_search=0; /* ReEnable interrupts & restore flags */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); } /* Find a record in the WavePoint table matching a given NWID */ @@ -771,7 +743,7 @@ #endif /* Disable interrupts & save flags */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF; m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8; @@ -779,7 +751,7 @@ mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); /* ReEnable interrupts & restore flags */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); wv_nwid_filter(!NWID_PROMISC,lp); lp->curr_point=wavepoint; @@ -1049,9 +1021,9 @@ /* Check if we can do it now ! */ if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev))) { - wv_splhi(lp, &flags); /* Disable interrupts */ + spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */ wv_82593_config(dev); - wv_splx(lp, &flags); /* Re-enable interrupts */ + spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */ } else { @@ -1179,7 +1151,7 @@ return; } - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Read the mmc */ mmc_out(base, mmwoff(0, mmw_freeze), 1); @@ -1191,7 +1163,7 @@ lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; #endif /* WIRELESS_EXT */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); printk(KERN_DEBUG "##### wavelan modem status registers: #####\n"); #ifdef DEBUG_SHOW_UNUSED @@ -1884,557 +1856,1234 @@ /*------------------------------------------------------------------*/ /* - * Perform ioctl : config & info stuff - * This is here that are treated the wireless extensions (iwconfig) + * Wireless Handler : get protocol name */ -static int -wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ - struct ifreq * rq, /* Data passed */ - int cmd) /* Ioctl number */ +static int wavelan_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) { - ioaddr_t base = dev->base_addr; - net_local * lp = (net_local *)dev->priv; /* lp is not unused */ - struct iwreq * wrq = (struct iwreq *) rq; - psa_t psa; - mm_t m; - unsigned long flags; - int ret = 0; - -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd); -#endif - - /* Disable interrupts & save flags */ - wv_splhi(lp, &flags); - - /* Look what is the request */ - switch(cmd) - { - /* --------------- WIRELESS EXTENSIONS --------------- */ + strcpy(wrqu->name, "WaveLAN"); + return 0; +} - case SIOCGIWNAME: - strcpy(wrq->u.name, "Wavelan"); - break; +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set NWID + */ +static int wavelan_set_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + mm_t m; + unsigned long flags; + int ret = 0; - case SIOCSIWNWID: - /* Set NWID in wavelan */ + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Set NWID in WaveLAN. */ #if WIRELESS_EXT > 8 - if(!wrq->u.nwid.disabled) - { - /* Set NWID in psa */ - psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8; - psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF; + if (!wrqu->nwid.disabled) { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; + psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; #else /* WIRELESS_EXT > 8 */ - if(wrq->u.nwid.on) - { - /* Set NWID in psa */ - psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; - psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF; + if(wrq->u.nwid.on) { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; + psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF; #endif /* WIRELESS_EXT > 8 */ - psa.psa_nwid_select = 0x01; - psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, - (unsigned char *)psa.psa_nwid, 3); - - /* Set NWID in mmc */ - m.w.mmw_netw_id_l = psa.psa_nwid[1]; - m.w.mmw_netw_id_h = psa.psa_nwid[0]; - mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, - (unsigned char *)&m.w.mmw_netw_id_l, 2); - mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00); - } - else - { - /* Disable nwid in the psa */ - psa.psa_nwid_select = 0x00; - psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa, - (unsigned char *)&psa.psa_nwid_select, 1); - - /* Disable nwid in the mmc (no filtering) */ - mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID); - } - /* update the Wavelan checksum */ - update_psa_checksum(dev); - break; + psa.psa_nwid_select = 0x01; + psa_write(dev, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + + /* Set NWID in mmc. */ + m.w.mmw_netw_id_l = psa.psa_nwid[1]; + m.w.mmw_netw_id_h = psa.psa_nwid[0]; + mmc_write(base, + (char *) &m.w.mmw_netw_id_l - + (char *) &m, + (unsigned char *) &m.w.mmw_netw_id_l, 2); + mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00); + } else { + /* Disable NWID in the psa. */ + psa.psa_nwid_select = 0x00; + psa_write(dev, + (char *) &psa.psa_nwid_select - + (char *) &psa, + (unsigned char *) &psa.psa_nwid_select, + 1); + + /* Disable NWID in the mmc (no filtering). */ + mmc_out(base, mmwoff(0, mmw_loopt_sel), + MMW_LOOPT_SEL_DIS_NWID); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} - case SIOCGIWNWID: - /* Read the NWID */ - psa_read(dev, (char *)psa.psa_nwid - (char *)&psa, - (unsigned char *)psa.psa_nwid, 3); +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get NWID + */ +static int wavelan_get_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Read the NWID. */ + psa_read(dev, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); #if WIRELESS_EXT > 8 - wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; - wrq->u.nwid.disabled = !(psa.psa_nwid_select); - wrq->u.nwid.fixed = 1; /* Superfluous */ + wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrqu->nwid.disabled = !(psa.psa_nwid_select); + wrqu->nwid.fixed = 1; /* Superfluous */ #else /* WIRELESS_EXT > 8 */ - wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; - wrq->u.nwid.on = psa.psa_nwid_select; + wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrq->u.nwid.on = psa.psa_nwid_select; #endif /* WIRELESS_EXT > 8 */ - break; - case SIOCSIWFREQ: - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ - if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - ret = wv_set_frequency(base, &(wrq->u.freq)); - else - ret = -EOPNOTSUPP; - break; + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - case SIOCGIWFREQ: - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) - * (does it work for everybody ? - especially old cards...) */ - if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - { - unsigned short freq; + return ret; +} - /* Ask the EEprom to read the frequency from the first area */ - fee_read(base, 0x00 /* 1st area - frequency... */, - &freq, 1); - wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; - wrq->u.freq.e = 1; - } - else - { - psa_read(dev, (char *)&psa.psa_subband - (char *)&psa, - (unsigned char *)&psa.psa_subband, 1); +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set frequency + */ +static int wavelan_set_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + int ret; - if(psa.psa_subband <= 4) - { - wrq->u.freq.m = fixed_bands[psa.psa_subband]; - wrq->u.freq.e = (psa.psa_subband != 0); - } - else - ret = -EOPNOTSUPP; + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + ret = wv_set_frequency(base, &(wrqu->freq)); + else + ret = -EOPNOTSUPP; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get frequency + */ +static int wavelan_get_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). + * Does it work for everybody, especially old cards? */ + if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + unsigned short freq; + + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(base, 0x00, &freq, 1); + wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000; + wrqu->freq.e = 1; + } else { + psa_read(dev, + (char *) &psa.psa_subband - (char *) &psa, + (unsigned char *) &psa.psa_subband, 1); + + if (psa.psa_subband <= 4) { + wrqu->freq.m = fixed_bands[psa.psa_subband]; + wrqu->freq.e = (psa.psa_subband != 0); + } else + ret = -EOPNOTSUPP; } - break; - case SIOCSIWSENS: - /* Set the level threshold */ + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set level threshold + */ +static int wavelan_set_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Set the level threshold. */ #if WIRELESS_EXT > 7 - /* We should complain loudly if wrq->u.sens.fixed = 0, because we - * can't set auto mode... */ - psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; + /* We should complain loudly if wrqu->sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; #else /* WIRELESS_EXT > 7 */ - psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; + psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; #endif /* WIRELESS_EXT > 7 */ - psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, - (unsigned char *)&psa.psa_thr_pre_set, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev); - mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); - break; + psa_write(dev, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); + mmc_out(base, mmwoff(0, mmw_thr_pre_set), + psa.psa_thr_pre_set); - case SIOCGIWSENS: - /* Read the level threshold */ - psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, - (unsigned char *)&psa.psa_thr_pre_set, 1); + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get level threshold + */ +static int wavelan_get_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Read the level threshold. */ + psa_read(dev, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); #if WIRELESS_EXT > 7 - wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; - wrq->u.sens.fixed = 1; + wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; + wrqu->sens.fixed = 1; #else /* WIRELESS_EXT > 7 */ - wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F; + wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F; #endif /* WIRELESS_EXT > 7 */ - break; -#if WIRELESS_EXT > 8 - case SIOCSIWENCODE: - /* Set encryption key */ - if(!mmc_encr(base)) - { - ret = -EOPNOTSUPP; - break; - } + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - /* Basic checking... */ - if(wrq->u.encoding.pointer != (caddr_t) 0) - { - /* Check the size of the key */ - if(wrq->u.encoding.length != 8) - { - ret = -EINVAL; - break; - } + return ret; +} - /* Copy the key in the driver */ - if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer, - wrq->u.encoding.length)) - { - ret = -EFAULT; - break; - } +#if WIRELESS_EXT > 8 +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set encryption key + */ +static int wavelan_set_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + psa_t psa; + int ret = 0; - psa.psa_encryption_select = 1; - psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa, - (unsigned char *) &psa.psa_encryption_select, 8+1); - - mmc_out(base, mmwoff(0, mmw_encr_enable), - MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); - mmc_write(base, mmwoff(0, mmw_encr_key), - (unsigned char *) &psa.psa_encryption_key, 8); - } - - if(wrq->u.encoding.flags & IW_ENCODE_DISABLED) - { /* disable encryption */ - psa.psa_encryption_select = 0; - psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa, - (unsigned char *) &psa.psa_encryption_select, 1); + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); - mmc_out(base, mmwoff(0, mmw_encr_enable), 0); + /* Check if capable of encryption */ + if (!mmc_encr(base)) { + ret = -EOPNOTSUPP; } - /* update the Wavelan checksum */ - update_psa_checksum(dev); - break; - case SIOCGIWENCODE: - /* Read the encryption key */ - if(!mmc_encr(base)) - { - ret = -EOPNOTSUPP; - break; + /* Check the size of the key */ + if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) { + ret = -EINVAL; } - /* only super-user can see encryption key */ - if(!capable(CAP_NET_ADMIN)) - { - ret = -EPERM; - break; + if(!ret) { + /* Basic checking... */ + if (wrqu->encoding.length == 8) { + /* Copy the key in the driver */ + memcpy(psa.psa_encryption_key, extra, + wrqu->encoding.length); + psa.psa_encryption_select = 1; + + psa_write(dev, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 8 + 1); + + mmc_out(base, mmwoff(0, mmw_encr_enable), + MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); + mmc_write(base, mmwoff(0, mmw_encr_key), + (unsigned char *) &psa. + psa_encryption_key, 8); + } + + /* disable encryption */ + if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { + psa.psa_encryption_select = 0; + psa_write(dev, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1); + + mmc_out(base, mmwoff(0, mmw_encr_enable), 0); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev); } - /* Basic checking... */ - if(wrq->u.encoding.pointer != (caddr_t) 0) - { - psa_read(dev, (char *) &psa.psa_encryption_select - (char *) &psa, - (unsigned char *) &psa.psa_encryption_select, 1+8); + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - /* encryption is enabled ? */ - if(psa.psa_encryption_select) - wrq->u.encoding.flags = IW_ENCODE_ENABLED; - else - wrq->u.encoding.flags = IW_ENCODE_DISABLED; - wrq->u.encoding.flags |= mmc_encr(base); + return ret; +} - /* Copy the key to the user buffer */ - wrq->u.encoding.length = 8; - if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8)) - ret = -EFAULT; +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get encryption key + */ +static int wavelan_get_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check if encryption is available */ + if (!mmc_encr(base)) { + ret = -EOPNOTSUPP; + } else { + /* Read the encryption key */ + psa_read(dev, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1 + 8); + + /* encryption is enabled ? */ + if (psa.psa_encryption_select) + wrqu->encoding.flags = IW_ENCODE_ENABLED; + else + wrqu->encoding.flags = IW_ENCODE_DISABLED; + wrqu->encoding.flags |= mmc_encr(base); + + /* Copy the key to the user buffer */ + wrqu->encoding.length = 8; + memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length); } - break; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} #endif /* WIRELESS_EXT > 8 */ #ifdef WAVELAN_ROAMING_EXT #if WIRELESS_EXT > 5 - case SIOCSIWESSID: - /* Check if disable */ - if(wrq->u.data.flags == 0) - lp->filter_domains = 0; - else - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) - { - char essid[IW_ESSID_MAX_SIZE + 1]; - char * endp; - - /* Check the size of the string */ - if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1) - { - ret = -E2BIG; - break; - } - - /* Copy the string in the driver */ - if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.length)) - { - ret = -EFAULT; - break; - } - essid[IW_ESSID_MAX_SIZE] = '\0'; +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set ESSID (domain) + */ +static int wavelan_set_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check if disable */ + if(wrqu->data.flags == 0) + lp->filter_domains = 0; + else { + char essid[IW_ESSID_MAX_SIZE + 1]; + char * endp; + + /* Terminate the string */ + memcpy(essid, extra, wrqu->data.length); + essid[IW_ESSID_MAX_SIZE] = '\0'; #ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "SetEssid : ``%s''\n", essid); + printk(KERN_DEBUG "SetEssid : ``%s''\n", essid); #endif /* DEBUG_IOCTL_INFO */ - /* Convert to a number (note : Wavelan specific) */ - lp->domain_id = simple_strtoul(essid, &endp, 16); - /* Has it worked ? */ - if(endp > essid) - lp->filter_domains = 1; - else - { - lp->filter_domains = 0; - ret = -EINVAL; - } - } - break; + /* Convert to a number (note : Wavelan specific) */ + lp->domain_id = simple_strtoul(essid, &endp, 16); + /* Has it worked ? */ + if(endp > essid) + lp->filter_domains = 1; + else { + lp->filter_domains = 0; + ret = -EINVAL; + } + } - case SIOCGIWESSID: - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) - { - char essid[IW_ESSID_MAX_SIZE + 1]; + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); - /* Is the domain ID active ? */ - wrq->u.data.flags = lp->filter_domains; + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get ESSID (domain) + */ +static int wavelan_get_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - /* Copy Domain ID into a string (Wavelan specific) */ - /* Sound crazy, be we can't have a snprintf in the kernel !!! */ - sprintf(essid, "%lX", lp->domain_id); - essid[IW_ESSID_MAX_SIZE] = '\0'; + /* Is the domain ID active ? */ + wrqu->data.flags = lp->filter_domains; - /* Set the length */ - wrq->u.data.length = strlen(essid) + 1; + /* Copy Domain ID into a string (Wavelan specific) */ + /* Sound crazy, be we can't have a snprintf in the kernel !!! */ + sprintf(extra, "%lX", lp->domain_id); + extra[IW_ESSID_MAX_SIZE] = '\0'; - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length)) - ret = -EFAULT; - } - break; + /* Set the length */ + wrqu->data.length = strlen(extra) + 1; - case SIOCSIWAP: + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set AP address + */ +static int wavelan_set_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ #ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n", - wrq->u.ap_addr.sa_data[0], - wrq->u.ap_addr.sa_data[1], - wrq->u.ap_addr.sa_data[2], - wrq->u.ap_addr.sa_data[3], - wrq->u.ap_addr.sa_data[4], - wrq->u.ap_addr.sa_data[5]); + printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n", + wrqu->ap_addr.sa_data[0], + wrqu->ap_addr.sa_data[1], + wrqu->ap_addr.sa_data[2], + wrqu->ap_addr.sa_data[3], + wrqu->ap_addr.sa_data[4], + wrqu->ap_addr.sa_data[5]); #endif /* DEBUG_IOCTL_INFO */ - ret = -EOPNOTSUPP; /* Not supported yet */ - break; + return -EOPNOTSUPP; +} - case SIOCGIWAP: - /* Should get the real McCoy instead of own Ethernet address */ - memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE); - wrq->u.ap_addr.sa_family = ARPHRD_ETHER; +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get AP address + */ +static int wavelan_get_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + /* Should get the real McCoy instead of own Ethernet address */ + memcpy(wrqu->ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE); + wrqu->ap_addr.sa_family = ARPHRD_ETHER; - ret = -EOPNOTSUPP; /* Not supported yet */ - break; + return -EOPNOTSUPP; +} #endif /* WIRELESS_EXT > 5 */ #endif /* WAVELAN_ROAMING_EXT */ #if WIRELESS_EXT > 8 #ifdef WAVELAN_ROAMING - case SIOCSIWMODE: - switch(wrq->u.mode) - { +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set mode + */ +static int wavelan_set_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check mode */ + switch(wrqu->mode) { case IW_MODE_ADHOC: - if(do_roaming) - { - wv_roam_cleanup(dev); - do_roaming = 0; - } - break; + if(do_roaming) { + wv_roam_cleanup(dev); + do_roaming = 0; + } + break; case IW_MODE_INFRA: - if(!do_roaming) - { - wv_roam_init(dev); - do_roaming = 1; - } - break; + if(!do_roaming) { + wv_roam_init(dev); + do_roaming = 1; + } + break; default: - ret = -EINVAL; + ret = -EINVAL; } - break; - case SIOCGIWMODE: - if(do_roaming) - wrq->u.mode = IW_MODE_INFRA; - else - wrq->u.mode = IW_MODE_ADHOC; - break; + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get mode + */ +static int wavelan_get_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + if(do_roaming) + wrqu->mode = IW_MODE_INFRA; + else + wrqu->mode = IW_MODE_ADHOC; + + return 0; +} #endif /* WAVELAN_ROAMING */ #endif /* WIRELESS_EXT > 8 */ - case SIOCGIWRANGE: - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) - { - struct iw_range range; +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get range info + */ +static int wavelan_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct iw_range *range = (struct iw_range *) extra; + unsigned long flags; + int ret = 0; - /* Set the length (very important for backward compatibility) */ - wrq->u.data.length = sizeof(struct iw_range); + /* Set the length (very important for backward compatibility) */ + wrqu->data.length = sizeof(struct iw_range); - /* Set all the info we don't care or don't know about to zero */ - memset(&range, 0, sizeof(range)); + /* Set all the info we don't care or don't know about to zero */ + memset(range, 0, sizeof(struct iw_range)); #if WIRELESS_EXT > 10 - /* Set the Wireless Extension versions */ - range.we_version_compiled = WIRELESS_EXT; - range.we_version_source = 9; /* Nothing for us in v10 and v11 */ + /* Set the Wireless Extension versions */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 9; #endif /* WIRELESS_EXT > 10 */ - /* Set information in the range struct */ - range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ - range.min_nwid = 0x0000; - range.max_nwid = 0xFFFF; - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ - if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - { - range.num_channels = 10; - range.num_frequency = wv_frequency_list(base, range.freq, - IW_MAX_FREQUENCIES); - } - else - range.num_channels = range.num_frequency = 0; - - range.sensitivity = 0x3F; - range.max_qual.qual = MMR_SGNL_QUAL; - range.max_qual.level = MMR_SIGNAL_LVL; - range.max_qual.noise = MMR_SILENCE_LVL; + /* Set information in the range struct. */ + range->throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ + range->min_nwid = 0x0000; + range->max_nwid = 0xFFFF; + + range->sensitivity = 0x3F; + range->max_qual.qual = MMR_SGNL_QUAL; + range->max_qual.level = MMR_SIGNAL_LVL; + range->max_qual.noise = MMR_SILENCE_LVL; #if WIRELESS_EXT > 11 - range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ - /* Need to get better values for those two */ - range.avg_qual.level = 30; - range.avg_qual.noise = 8; + range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ + /* Need to get better values for those two */ + range->avg_qual.level = 30; + range->avg_qual.noise = 8; #endif /* WIRELESS_EXT > 11 */ #if WIRELESS_EXT > 7 - range.num_bitrates = 1; - range.bitrate[0] = 2000000; /* 2 Mb/s */ + range->num_bitrates = 1; + range->bitrate[0] = 2000000; /* 2 Mb/s */ #endif /* WIRELESS_EXT > 7 */ + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + range->num_channels = 10; + range->num_frequency = wv_frequency_list(base, range->freq, + IW_MAX_FREQUENCIES); + } else + range->num_channels = range->num_frequency = 0; + #if WIRELESS_EXT > 8 - /* Encryption supported ? */ - if(mmc_encr(base)) - { - range.encoding_size[0] = 8; /* DES = 64 bits key */ - range.num_encoding_sizes = 1; - range.max_encoding_tokens = 1; /* Only one key possible */ - } - else - { - range.num_encoding_sizes = 0; - range.max_encoding_tokens = 0; - } + /* Encryption supported ? */ + if (mmc_encr(base)) { + range->encoding_size[0] = 8; /* DES = 64 bits key */ + range->num_encoding_sizes = 1; + range->max_encoding_tokens = 1; /* Only one key possible */ + } else { + range->num_encoding_sizes = 0; + range->max_encoding_tokens = 0; + } #endif /* WIRELESS_EXT > 8 */ - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, &range, - sizeof(struct iw_range))) - ret = -EFAULT; + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +#ifdef WIRELESS_SPY +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set spy list + */ +static int wavelan_set_spy(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct sockaddr *address = (struct sockaddr *) extra; + int i; + int ret = 0; + + /* Disable spy while we copy the addresses. + * As we don't disable interrupts, we need to do this */ + lp->spy_number = 0; + + /* Are there are addresses to copy? */ + if (wrqu->data.length > 0) { + /* Copy addresses to the lp structure. */ + for (i = 0; i < wrqu->data.length; i++) { + memcpy(lp->spy_address[i], address[i].sa_data, + WAVELAN_ADDR_SIZE); + } + + /* Reset structure. */ + memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG + "SetSpy: set of new addresses is: \n"); + for (i = 0; i < wrqu->data.length; i++) + printk(KERN_DEBUG + "%02X:%02X:%02X:%02X:%02X:%02X \n", + lp->spy_address[i][0], + lp->spy_address[i][1], + lp->spy_address[i][2], + lp->spy_address[i][3], + lp->spy_address[i][4], + lp->spy_address[i][5]); +#endif /* DEBUG_IOCTL_INFO */ + } + + /* Now we can set the number of addresses */ + lp->spy_number = wrqu->data.length; + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get spy list + */ +static int wavelan_get_spy(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct sockaddr *address = (struct sockaddr *) extra; + int i; + + /* Set the number of addresses */ + wrqu->data.length = lp->spy_number; + + /* Copy addresses from the lp structure. */ + for (i = 0; i < lp->spy_number; i++) { + memcpy(address[i].sa_data, + lp->spy_address[i], + WAVELAN_ADDR_SIZE); + address[i].sa_family = AF_UNIX; } + /* Copy stats to the user buffer (just after). */ + if(lp->spy_number > 0) + memcpy(extra + (sizeof(struct sockaddr) * lp->spy_number), + lp->spy_stat, sizeof(iw_qual) * lp->spy_number); + + /* Reset updated flags. */ + for (i = 0; i < lp->spy_number; i++) + lp->spy_stat[i].updated = 0x0; + + return(0); +} +#endif /* WIRELESS_SPY */ + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set quality threshold + */ +static int wavelan_set_qthr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + ioaddr_t base = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + psa.psa_quality_thr = *(extra) & 0x0F; + psa_write(dev, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); + mmc_out(base, mmwoff(0, mmw_quality_thr), + psa.psa_quality_thr); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get quality threshold + */ +static int wavelan_get_qthr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + psa_t psa; + unsigned long flags; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + psa_read(dev, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + *(extra) = psa.psa_quality_thr & 0x0F; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return 0; +} + +#ifdef WAVELAN_ROAMING +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set roaming + */ +static int wavelan_set_roam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + unsigned long flags; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Note : should check if user == root */ + if(do_roaming && (*extra)==0) + wv_roam_cleanup(dev); + else if(do_roaming==0 && (*extra)!=0) + wv_roam_init(dev); + + do_roaming = (*extra); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get quality threshold + */ +static int wavelan_get_roam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + *(extra) = do_roaming; + + return 0; +} +#endif /* WAVELAN_ROAMING */ + +#ifdef HISTOGRAM +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set histogram + */ +static int wavelan_set_histo(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + + /* Check the number of intervals. */ + if (wrqu->data.length > 16) { + return(-E2BIG); + } + + /* Disable histo while we copy the addresses. + * As we don't disable interrupts, we need to do this */ + lp->his_number = 0; + + /* Are there ranges to copy? */ + if (wrqu->data.length > 0) { + /* Copy interval ranges to the driver */ + memcpy(lp->his_range, extra, wrqu->data.length); + + { + int i; + printk(KERN_DEBUG "Histo :"); + for(i = 0; i < wrqu->data.length; i++) + printk(" %d", lp->his_range[i]); + printk("\n"); + } + + /* Reset result structure. */ + memset(lp->his_sum, 0x00, sizeof(long) * 16); + } + + /* Now we can set the number of ranges */ + lp->his_number = wrqu->data.length; + + return(0); +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get histogram + */ +static int wavelan_get_histo(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + + /* Set the number of intervals. */ + wrqu->data.length = lp->his_number; + + /* Give back the distribution statistics */ + if(lp->his_number > 0) + memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number); + + return(0); +} +#endif /* HISTOGRAM */ + +/*------------------------------------------------------------------*/ +/* + * Structures to export the Wireless Handlers + */ + +static const struct iw_priv_args wavelan_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, + { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, + { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setroam" }, + { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" }, + { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, + { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, +}; + +#if WIRELESS_EXT > 12 + +static const iw_handler wavelan_handler[] = +{ + NULL, /* SIOCSIWNAME */ + wavelan_get_name, /* SIOCGIWNAME */ + wavelan_set_nwid, /* SIOCSIWNWID */ + wavelan_get_nwid, /* SIOCGIWNWID */ + wavelan_set_freq, /* SIOCSIWFREQ */ + wavelan_get_freq, /* SIOCGIWFREQ */ +#ifdef WAVELAN_ROAMING + wavelan_set_mode, /* SIOCSIWMODE */ + wavelan_get_mode, /* SIOCGIWMODE */ +#else /* WAVELAN_ROAMING */ + NULL, /* SIOCSIWMODE */ + NULL, /* SIOCGIWMODE */ +#endif /* WAVELAN_ROAMING */ + wavelan_set_sens, /* SIOCSIWSENS */ + wavelan_get_sens, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + wavelan_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ +#ifdef WIRELESS_SPY + wavelan_set_spy, /* SIOCSIWSPY */ + wavelan_get_spy, /* SIOCGIWSPY */ +#else /* WIRELESS_SPY */ + NULL, /* SIOCSIWSPY */ + NULL, /* SIOCGIWSPY */ +#endif /* WIRELESS_SPY */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ +#ifdef WAVELAN_ROAMING_EXT + wavelan_set_wap, /* SIOCSIWAP */ + wavelan_get_wap, /* SIOCGIWAP */ + NULL, /* -- hole -- */ + NULL, /* SIOCGIWAPLIST */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + wavelan_set_essid, /* SIOCSIWESSID */ + wavelan_get_essid, /* SIOCGIWESSID */ +#else /* WAVELAN_ROAMING_EXT */ + NULL, /* SIOCSIWAP */ + NULL, /* SIOCGIWAP */ + NULL, /* -- hole -- */ + NULL, /* SIOCGIWAPLIST */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWESSID */ + NULL, /* SIOCGIWESSID */ +#endif /* WAVELAN_ROAMING_EXT */ +#if WIRELESS_EXT > 8 + NULL, /* SIOCSIWNICKN */ + NULL, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWRATE */ + NULL, /* SIOCGIWRATE */ + NULL, /* SIOCSIWRTS */ + NULL, /* SIOCGIWRTS */ + NULL, /* SIOCSIWFRAG */ + NULL, /* SIOCGIWFRAG */ + NULL, /* SIOCSIWTXPOW */ + NULL, /* SIOCGIWTXPOW */ + NULL, /* SIOCSIWRETRY */ + NULL, /* SIOCGIWRETRY */ + wavelan_set_encode, /* SIOCSIWENCODE */ + wavelan_get_encode, /* SIOCGIWENCODE */ +#endif /* WIRELESS_EXT > 8 */ +}; + +static const iw_handler wavelan_private_handler[] = +{ + wavelan_set_qthr, /* SIOCIWFIRSTPRIV */ + wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */ +#ifdef WAVELAN_ROAMING + wavelan_set_roam, /* SIOCIWFIRSTPRIV + 2 */ + wavelan_get_roam, /* SIOCIWFIRSTPRIV + 3 */ +#else /* WAVELAN_ROAMING */ + NULL, /* SIOCIWFIRSTPRIV + 2 */ + NULL, /* SIOCIWFIRSTPRIV + 3 */ +#endif /* WAVELAN_ROAMING */ +#ifdef HISTOGRAM + wavelan_set_histo, /* SIOCIWFIRSTPRIV + 4 */ + wavelan_get_histo, /* SIOCIWFIRSTPRIV + 5 */ +#endif /* HISTOGRAM */ +}; + +static const struct iw_handler_def wavelan_handler_def = +{ + num_standard: sizeof(wavelan_handler)/sizeof(iw_handler), + num_private: sizeof(wavelan_private_handler)/sizeof(iw_handler), + num_private_args: sizeof(wavelan_private_args)/sizeof(struct iw_priv_args), + standard: (iw_handler *) wavelan_handler, + private: (iw_handler *) wavelan_private_handler, + private_args: (struct iw_priv_args *) wavelan_private_args, +}; + +#else /* WIRELESS_EXT > 12 */ +/*------------------------------------------------------------------*/ +/* + * Perform ioctl : config & info stuff + * This is here that are treated the wireless extensions (iwconfig) + */ +static int +wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ + struct ifreq * rq, /* Data passed */ + int cmd) /* Ioctl number */ +{ + struct iwreq * wrq = (struct iwreq *) rq; + int ret = 0; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd); +#endif + + /* Look what is the request */ + switch(cmd) + { + /* --------------- WIRELESS EXTENSIONS --------------- */ + + case SIOCGIWNAME: + wavelan_get_name(dev, NULL, &(wrq->u), NULL); break; - case SIOCGIWPRIV: - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) - { - struct iw_priv_args priv[] = - { /* cmd, set_args, get_args, name */ - { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, - { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, - { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, - { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, - { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1 , 0, "setroam" }, - { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" }, - }; + case SIOCSIWNWID: + ret = wavelan_set_nwid(dev, NULL, &(wrq->u), NULL); + break; - /* Set the number of ioctl available */ - wrq->u.data.length = 6; + case SIOCGIWNWID: + ret = wavelan_get_nwid(dev, NULL, &(wrq->u), NULL); + break; - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, - sizeof(priv))) + case SIOCSIWFREQ: + ret = wavelan_set_freq(dev, NULL, &(wrq->u), NULL); + break; + + case SIOCGIWFREQ: + ret = wavelan_get_freq(dev, NULL, &(wrq->u), NULL); + break; + + case SIOCSIWSENS: + ret = wavelan_set_sens(dev, NULL, &(wrq->u), NULL); + break; + + case SIOCGIWSENS: + ret = wavelan_get_sens(dev, NULL, &(wrq->u), NULL); + break; + +#if WIRELESS_EXT > 8 + case SIOCSIWENCODE: + { + char keybuf[8]; + if (wrq->u.encoding.pointer) { + /* We actually have a key to set */ + if (wrq->u.encoding.length != 8) { + ret = -EINVAL; + break; + } + if (copy_from_user(keybuf, + wrq->u.encoding.pointer, + wrq->u.encoding.length)) { ret = -EFAULT; + break; + } + } else if (wrq->u.encoding.length != 0) { + ret = -EINVAL; + break; } + ret = wavelan_set_encode(dev, NULL, &(wrq->u), keybuf); + } break; -#ifdef WIRELESS_SPY - case SIOCSIWSPY: - /* Set the spy list */ + case SIOCGIWENCODE: + if (! capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + { + char keybuf[8]; + ret = wavelan_get_encode(dev, NULL, + &(wrq->u), + keybuf); + if (wrq->u.encoding.pointer) { + if (copy_to_user(wrq->u.encoding.pointer, + keybuf, + wrq->u.encoding.length)) + ret = -EFAULT; + } + } + break; +#endif /* WIRELESS_EXT > 8 */ - /* Check the number of addresses */ - if(wrq->u.data.length > IW_MAX_SPY) - { +#ifdef WAVELAN_ROAMING_EXT +#if WIRELESS_EXT > 5 + case SIOCSIWESSID: + { + char essidbuf[IW_ESSID_MAX_SIZE+1]; + if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) { ret = -E2BIG; break; } - lp->spy_number = wrq->u.data.length; - - /* If there is some addresses to copy */ - if(lp->spy_number > 0) - { - struct sockaddr address[IW_MAX_SPY]; - int i; - - /* Copy addresses to the driver */ - if(copy_from_user(address, wrq->u.data.pointer, - sizeof(struct sockaddr) * lp->spy_number)) - { - ret = -EFAULT; - break; - } + if (copy_from_user(essidbuf, wrq->u.essid.pointer, + wrq->u.essid.length)) { + ret = -EFAULT; + break; + } + ret = wavelan_set_essid(dev, NULL, + &(wrq->u), + essidbuf); + } + break; - /* Copy addresses to the lp structure */ - for(i = 0; i < lp->spy_number; i++) - { - memcpy(lp->spy_address[i], address[i].sa_data, - WAVELAN_ADDR_SIZE); - } + case SIOCGIWESSID: + { + char essidbuf[IW_ESSID_MAX_SIZE+1]; + ret = wavelan_get_essid(dev, NULL, + &(wrq->u), + essidbuf); + if (wrq->u.essid.pointer) + if ( copy_to_user(wrq->u.essid.pointer, + essidbuf, + wrq->u.essid.length) ) + ret = -EFAULT; + } + break; - /* Reset structure... */ - memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); + case SIOCSIWAP: + ret = wavelan_set_wap(dev, NULL, &(wrq->u), NULL); + break; -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n"); - for(i = 0; i < wrq->u.data.length; i++) - printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n", - lp->spy_address[i][0], - lp->spy_address[i][1], - lp->spy_address[i][2], - lp->spy_address[i][3], - lp->spy_address[i][4], - lp->spy_address[i][5]); -#endif /* DEBUG_IOCTL_INFO */ - } + case SIOCGIWAP: + ret = wavelan_get_wap(dev, NULL, &(wrq->u), NULL); + break; +#endif /* WIRELESS_EXT > 5 */ +#endif /* WAVELAN_ROAMING_EXT */ +#if WIRELESS_EXT > 8 +#ifdef WAVELAN_ROAMING + case SIOCSIWMODE: + ret = wavelan_set_mode(dev, NULL, &(wrq->u), NULL); break; - case SIOCGIWSPY: - /* Get the spy list and spy stats */ + case SIOCGIWMODE: + ret = wavelan_get_mode(dev, NULL, &(wrq->u), NULL); + break; +#endif /* WAVELAN_ROAMING */ +#endif /* WIRELESS_EXT > 8 */ - /* Set the number of addresses */ - wrq->u.data.length = lp->spy_number; + case SIOCGIWRANGE: + { + struct iw_range range; + ret = wavelan_get_range(dev, NULL, + &(wrq->u), + (char *) &range); + if (copy_to_user(wrq->u.data.pointer, &range, + sizeof(struct iw_range))) + ret = -EFAULT; + } + break; - /* If the user want to have the addresses back... */ - if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) + case SIOCGIWPRIV: + /* Basic checking... */ + if(wrq->u.data.pointer != (caddr_t) 0) { - struct sockaddr address[IW_MAX_SPY]; - int i; - - /* Copy addresses from the lp structure */ - for(i = 0; i < lp->spy_number; i++) - { - memcpy(address[i].sa_data, lp->spy_address[i], - WAVELAN_ADDR_SIZE); - address[i].sa_family = ARPHRD_ETHER; - } - - /* Copy addresses to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, address, - sizeof(struct sockaddr) * lp->spy_number)) - { - ret = -EFAULT; - break; - } + /* Set the number of ioctl available */ + wrq->u.data.length = sizeof(wavelan_private_args) / sizeof(wavelan_private_args[0]); - /* Copy stats to the user buffer (just after) */ - if(copy_to_user(wrq->u.data.pointer + - (sizeof(struct sockaddr) * lp->spy_number), - lp->spy_stat, sizeof(iw_qual) * lp->spy_number)) - { - ret = -EFAULT; - break; - } + /* Copy structure to the user buffer */ + if(copy_to_user(wrq->u.data.pointer, (u_char *) wavelan_private_args, + sizeof(wavelan_private_args))) + ret = -EFAULT; + } + break; - /* Reset updated flags */ - for(i = 0; i < lp->spy_number; i++) - lp->spy_stat[i].updated = 0x0; - } /* if(pointer != NULL) */ +#ifdef WIRELESS_SPY + case SIOCSIWSPY: + { + struct sockaddr address[IW_MAX_SPY]; + /* Check the number of addresses */ + if (wrq->u.data.length > IW_MAX_SPY) { + ret = -E2BIG; + break; + } + /* Get the data in the driver */ + if (wrq->u.data.pointer) { + if (copy_from_user((char *) address, + wrq->u.data.pointer, + sizeof(struct sockaddr) * + wrq->u.data.length)) { + ret = -EFAULT; + break; + } + } else if (wrq->u.data.length != 0) { + ret = -EINVAL; + break; + } + ret = wavelan_set_spy(dev, NULL, &(wrq->u), + (char *) address); + } + break; + case SIOCGIWSPY: + { + char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) + + sizeof(struct iw_quality))]; + ret = wavelan_get_spy(dev, NULL, &(wrq->u), + buffer); + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, + buffer, + (wrq->u.data.length * + (sizeof(struct sockaddr) + + sizeof(struct iw_quality))) + )) + ret = -EFAULT; + } + } break; #endif /* WIRELESS_SPY */ @@ -2446,34 +3095,21 @@ ret = -EPERM; break; } - psa.psa_quality_thr = *(wrq->u.name) & 0x0F; - psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa, - (unsigned char *)&psa.psa_quality_thr, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev); - mmc_out(base, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr); + ret = wavelan_set_qthr(dev, NULL, &(wrq->u), NULL); break; case SIOCGIPQTHR: - psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa, - (unsigned char *)&psa.psa_quality_thr, 1); - *(wrq->u.name) = psa.psa_quality_thr & 0x0F; + ret = wavelan_get_qthr(dev, NULL, &(wrq->u), NULL); break; #ifdef WAVELAN_ROAMING case SIOCSIPROAM: /* Note : should check if user == root */ - if(do_roaming && (*wrq->u.name)==0) - wv_roam_cleanup(dev); - else if(do_roaming==0 && (*wrq->u.name)!=0) - wv_roam_init(dev); - - do_roaming = (*wrq->u.name); - + ret = wavelan_set_roam(dev, NULL, &(wrq->u), NULL); break; case SIOCGIPROAM: - *(wrq->u.name) = do_roaming; + ret = wavelan_get_roam(dev, NULL, &(wrq->u), NULL); break; #endif /* WAVELAN_ROAMING */ @@ -2484,44 +3120,44 @@ { ret = -EPERM; } - - /* Check the number of intervals */ - if(wrq->u.data.length > 16) - { - ret = -E2BIG; - break; + { + char buffer[16]; + /* Check the number of intervals */ + if(wrq->u.data.length > 16) + { + ret = -E2BIG; + break; } - lp->his_number = wrq->u.data.length; - - /* If there is some addresses to copy */ - if(lp->his_number > 0) - { - /* Copy interval ranges to the driver */ - if(copy_from_user(lp->his_range, wrq->u.data.pointer, - sizeof(char) * lp->his_number)) - { - ret = -EFAULT; - break; - } - - /* Reset structure... */ - memset(lp->his_sum, 0x00, sizeof(long) * 16); + /* Get the data in the driver */ + if (wrq->u.data.pointer) { + if (copy_from_user(buffer, + wrq->u.data.pointer, + sizeof(struct sockaddr) * + wrq->u.data.length)) { + ret = -EFAULT; + break; + } + } else if (wrq->u.data.length != 0) { + ret = -EINVAL; + break; } + ret = wavelan_set_histo(dev, NULL, &(wrq->u), + buffer); + } break; case SIOCGIPHISTO: - /* Set the number of intervals */ - wrq->u.data.length = lp->his_number; - - /* Give back the distribution statistics */ - if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) - { - /* Copy data to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, lp->his_sum, - sizeof(long) * lp->his_number)) + { + long buffer[16]; + ret = wavelan_get_histo(dev, NULL, &(wrq->u), + (char *) buffer); + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, + buffer, + (wrq->u.data.length * sizeof(long)))) ret = -EFAULT; - - } /* if(pointer != NULL) */ + } + } break; #endif /* HISTOGRAM */ @@ -2531,14 +3167,12 @@ ret = -EOPNOTSUPP; } - /* ReEnable interrupts & restore flags */ - wv_splx(lp, &flags); - #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); #endif return ret; } +#endif /* WIRELESS_EXT > 12 */ /*------------------------------------------------------------------*/ /* @@ -2559,7 +3193,7 @@ #endif /* Disable interrupts & save flags */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); wstats = &lp->wstats; @@ -2585,7 +3219,7 @@ wstats->discard.misc = 0L; /* ReEnable interrupts & restore flags */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); @@ -2921,7 +3555,7 @@ printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); #endif - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Check if we need some padding */ if(clen < ETH_ZLEN) @@ -2951,7 +3585,7 @@ /* Keep stats up to date */ lp->stats.tx_bytes += length; - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_TX_INFO wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); @@ -2991,9 +3625,9 @@ * we can do it now */ if(lp->reconfig_82593) { - wv_splhi(lp, &flags); /* Disable interrupts */ + spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */ wv_82593_config(dev); - wv_splx(lp, &flags); /* Re-enable interrupts */ + spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */ /* Note : the configure procedure was totally synchronous, * so the Tx buffer is now free */ } @@ -3230,7 +3864,7 @@ printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name); #endif - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* First, send the LAN controller a stop receive command */ wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv", @@ -3255,7 +3889,7 @@ } while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); /* If there was a problem */ if(spin <= 0) @@ -3299,7 +3933,7 @@ if(!wv_ru_stop(dev)) return FALSE; - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Now we know that no command is being executed. */ @@ -3354,7 +3988,7 @@ } #endif - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); @@ -3630,7 +4264,7 @@ return FALSE; /* Disable interrupts */ - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Disguised goto ;-) */ do @@ -3695,7 +4329,7 @@ while(0); /* Re-enable interrupts */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name); @@ -4021,7 +4655,7 @@ /* Prevent reentrancy. We need to do that because we may have * multiple interrupt handler running concurently. - * It is safe because wv_splhi() disable interrupts before aquiring + * It is safe because interrupts are disabled before aquiring * the spinlock. */ spin_lock(&lp->spinlock); @@ -4254,7 +4888,7 @@ dev->name); #endif - wv_splhi(lp, &flags); + spin_lock_irqsave(&lp->spinlock, flags); /* Ask to abort the current command */ outb(OP0_ABORT, LCCR(base)); @@ -4265,7 +4899,7 @@ aborted = TRUE; /* Release spinlock here so that wv_hw_reset() can grab it */ - wv_splx(lp, &flags); + spin_unlock_irqrestore(&lp->spinlock, flags); /* Check if we were successful in aborting it */ if(!aborted) @@ -4530,7 +5164,11 @@ dev->watchdog_timeo = WATCHDOG_JIFFIES; #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ +#if WIRELESS_EXT > 12 + dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def; +#else /* WIRELESS_EXT > 12 */ dev->do_ioctl = wavelan_ioctl; /* wireless extensions */ +#endif /* WIRELESS_EXT > 12 */ dev->get_wireless_stats = wavelan_get_wireless_stats; #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/wireless/wavelan_cs.p.h linux-2.5/drivers/net/wireless/wavelan_cs.p.h --- linux-2.5.5/drivers/net/wireless/wavelan_cs.p.h Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/net/wireless/wavelan_cs.p.h Tue Feb 26 21:24:49 2002 @@ -394,6 +394,12 @@ * o control first busy loop in wv_82593_cmd() * o Extend spinlock protection in wv_hw_config() * + * Changes made for release in 3.1.33 : + * ---------------------------------- + * - Optional use new driver API for Wireless Extensions : + * o got rid of wavelan_ioctl() + * o use a bunch of iw_handler instead + * * Wishes & dreams: * ---------------- * - Cleanup and integrate the roaming code @@ -430,6 +436,9 @@ #ifdef CONFIG_NET_RADIO #include /* Wireless extensions */ +#if WIRELESS_EXT > 12 +#include +#endif /* WIRELESS_EXT > 12 */ #endif /* Pcmcia headers that we need */ @@ -498,7 +507,7 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n"; +static const char *version = "wavelan_cs.c : v24 (SMP + wireless extensions) 11/1/02\n"; #endif /* Watchdog temporisation */ @@ -523,8 +532,8 @@ #define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */ #define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */ -#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */ -#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */ +#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 4 /* Set histogram ranges */ +#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 5 /* Get histogram values */ /*************************** WaveLAN Roaming **************************/ #ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ @@ -589,6 +598,16 @@ typedef struct net_local net_local; typedef struct timer_list timer_list; +#if WIRELESS_EXT <= 12 +/* Wireless extensions backward compatibility */ +/* Part of iw_handler prototype we need */ +struct iw_request_info +{ + __u16 cmd; /* Wireless Extension command */ + __u16 flags; /* More to come ;-) */ +}; +#endif /* WIRELESS_EXT <= 12 */ + /* Basic types */ typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ @@ -661,12 +680,6 @@ #endif /* WAVELAN_ROAMING */ /* ----------------------- MISC SUBROUTINES ------------------------ */ -static inline void - wv_splhi(net_local *, /* Disable interrupts */ - unsigned long *); /* flags */ -static inline void - wv_splx(net_local *, /* ReEnable interrupts */ - unsigned long *); /* flags */ static void cs_error(client_handle_t, /* Report error to cardmgr */ int, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/net/yellowfin.c linux-2.5/drivers/net/yellowfin.c --- linux-2.5.5/drivers/net/yellowfin.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/net/yellowfin.c Thu Feb 14 00:22:28 2002 @@ -1487,7 +1487,7 @@ name: DRV_NAME, id_table: yellowfin_pci_tbl, probe: yellowfin_init_one, - remove: yellowfin_remove_one, + remove: __devexit_p(yellowfin_remove_one), }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/parport/ChangeLog linux-2.5/drivers/parport/ChangeLog --- linux-2.5.5/drivers/parport/ChangeLog Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/parport/ChangeLog Fri Mar 1 15:07:38 2002 @@ -1,19 +1,37 @@ +2001-11-14 Tim Waugh + + * parport_pc.c (parport_pc_pci_probe): Hooks for PCI cards before + and after probing for ports. + * parport_serial.c (parport_register): Likewise. + +2002-01-20 Tim Waugh + + * parport_pc.c (parport_pc_compat_write_block_pio, + parport_pc_ecp_write_block_pio, parport_pc_ecp_read_block_pio): + Use the default implementations if the caller wants to use + O_NONBLOCK. + +2002-02-25 Tim Waugh + + * parport_pc.c: Make sure that priv->ctr_writable includes IntEn + even if IRQ is given as a parameter. + 2002-01-21 Tim Waugh * daisy.c: Apply patch from Max Vorobiev to make parport_daisy_select work for ECP/EPP modes. -2002-01-04 Tim Waugh - - * share.c (parport_claim_or_block): Sleep interruptibly to prevent - a possible deadlock. - 2002-01-13 Niels Kristian Bech Jensen * parport_pc.c: Change some occurrences of frob_set_mode to ECR_WRITE. This fixes PLIP. -2001-10-25 Damian Gruszka +2002-01-04 Tim Waugh + + * share.c (parport_claim_or_block): Sleep interruptibly to prevent + a possible deadlock. + +2001-12-07 Damian Gruszka * parport_pc.c (ECR_WRITE): Define. If there are forbidden bits in the ECR register for some chips, this will be a useful place to @@ -50,7 +68,7 @@ (parport_irq_probe): If no IRQ is found, take ackIntEn out of the writable bit set. -2001-10-25 Tim Waugh +2001-12-07 Tim Waugh * parport_pc.c (parport_pc_fifo_write_block_pio): Correct typo. (parport_pc_init_state): Only set ackIntEn if we know which IRQ @@ -67,6 +85,16 @@ too buggy at the moment. Use 'dma=auto' to restore the previous behaviour. +2001-12-07 Tim Waugh + + * daisy.c (DEBUG): Undefine. + +2001-12-06 Tim Waugh + + * ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off + PARPORT_CONTROL_AUTOFD as well. Bug spotted by Joe + . + 2001-12-03 Rich Liu * parport_pc.c (sio_ite_8872_probe): ITE8873 is a single-port @@ -75,12 +103,6 @@ 2001-11-30 Niels Kristian Bech Jensen * parport_pc.c: Fix compiler warning. - -2001-12-06 Tim Waugh - - * ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off - PARPORT_CONTROL_AUTOFD as well. Bug spotted by Joe - . 2001-11-12 Tim Waugh diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/parport/daisy.c linux-2.5/drivers/parport/daisy.c --- linux-2.5.5/drivers/parport/daisy.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/parport/daisy.c Wed Feb 6 18:54:10 2002 @@ -23,7 +23,7 @@ #include #include -#define DEBUG /* undef me for production */ +#undef DEBUG /* undef me for production */ #ifdef DEBUG #define DPRINTK(stuff...) printk (stuff) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/parport/parport_cs.c linux-2.5/drivers/parport/parport_cs.c --- linux-2.5.5/drivers/parport/parport_cs.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/parport/parport_cs.c Tue Dec 18 14:53:28 2001 @@ -5,7 +5,7 @@ (specifically, for the Quatech SPP-100 EPP card: other cards will probably require driver tweaks) - parport_cs.c 1.20 2000/11/02 23:15:05 + parport_cs.c 1.24 2001/10/13 14:04:05 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -57,32 +58,31 @@ #include #include -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"parport_cs.c 1.20 2000/11/02 23:15:05 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif +/*====================================================================*/ -#ifndef VERSION -#define VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) -#endif +/* Module parameters */ -/*====================================================================*/ +MODULE_AUTHOR("David Hinds "); +MODULE_DESCRIPTION("PCMCIA parallel port card driver"); +MODULE_LICENSE("Dual MPL/GPL"); -/* Parameters that can be set with 'insmod' */ +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +INT_MODULE_PARM(irq_mask, 0xdeb8); static int irq_list[4] = { -1 }; -static int epp_mode = 1; - -MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM(epp_mode, "i"); + +INT_MODULE_PARM(epp_mode, 1); + +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"parport_cs.c 1.24 2001/10/13 14:04:05 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ @@ -105,9 +105,6 @@ static dev_info_t dev_info = "parport_cs"; static dev_link_t *dev_list = NULL; -extern struct parport_operations parport_pc_ops; -static struct parport_operations parport_cs_ops; - /*====================================================================*/ static void cs_error(client_handle_t handle, int func, int ret) @@ -307,19 +304,6 @@ goto failed; } -#if (LINUX_VERSION_CODE < VERSION(2,3,6)) -#if (LINUX_VERSION_CODE >= VERSION(2,2,8)) - p->private_data = kmalloc(sizeof(struct parport_pc_private), - GFP_KERNEL); - ((struct parport_pc_private *)(p->private_data))->ctr = 0x0c; -#endif - parport_proc_register(p); - p->flags |= PARPORT_FLAG_COMA; - parport_pc_write_econtrol(p, 0x00); - parport_pc_write_control(p, 0x0c); - parport_pc_write_data(p, 0x00); -#endif - p->modes |= PARPORT_MODE_PCSPP; if (epp_mode) p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP; @@ -365,14 +349,8 @@ if (info->ndev) { struct parport *p = info->port; -#if (LINUX_VERSION_CODE < VERSION(2,3,6)) - if (!(p->flags & PARPORT_FLAG_COMA)) - parport_quiesce(p); -#endif parport_proc_unregister(p); -#if (LINUX_VERSION_CODE >= VERSION(2,2,8)) kfree(p->private_data); -#endif parport_unregister_port(p); } info->ndev = 0; @@ -430,24 +408,6 @@ /*====================================================================*/ -#if (LINUX_VERSION_CODE < VERSION(2,3,6)) - -static void inc_use_count(void) -{ - MOD_INC_USE_COUNT; - parport_pc_ops.inc_use_count(); -} - -static void dec_use_count(void) -{ - MOD_DEC_USE_COUNT; - parport_pc_ops.dec_use_count(); -} - -#endif - -/*====================================================================*/ - static int __init init_parport_cs(void) { servinfo_t serv; @@ -459,13 +419,6 @@ return -1; } -#if (LINUX_VERSION_CODE < VERSION(2,3,6)) - /* This is to protect against unloading modules out of order */ - parport_cs_ops = parport_pc_ops; - parport_cs_ops.inc_use_count = &inc_use_count; - parport_cs_ops.dec_use_count = &dec_use_count; -#endif - register_pccard_driver(&dev_info, &parport_attach, &parport_detach); return 0; } @@ -480,4 +433,3 @@ module_init(init_parport_cs); module_exit(exit_parport_cs); -MODULE_LICENSE("Dual MPL/GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/parport/parport_pc.c linux-2.5/drivers/parport/parport_pc.c --- linux-2.5.5/drivers/parport/parport_pc.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/parport/parport_pc.c Fri Mar 1 15:07:38 2002 @@ -818,8 +818,9 @@ long int expire; const struct parport_pc_private *priv = port->physport->private_data; - /* Special case: a timeout of zero means we cannot call schedule(). */ - if (!port->physport->cad->timeout) + /* Special case: a timeout of zero means we cannot call schedule(). + * Also if O_NONBLOCK is set then use the default implementation. */ + if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) return parport_ieee1284_write_compat (port, buf, length, flags); @@ -894,8 +895,9 @@ long int expire; const struct parport_pc_private *priv = port->physport->private_data; - /* Special case: a timeout of zero means we cannot call schedule(). */ - if (!port->physport->cad->timeout) + /* Special case: a timeout of zero means we cannot call schedule(). + * Also if O_NONBLOCK is set then use the default implementation. */ + if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) return parport_ieee1284_ecp_write_data (port, buf, length, flags); @@ -1014,8 +1016,9 @@ DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n"); dump_parport_state ("enter fcn", port); - /* Special case: a timeout of zero means we cannot call schedule(). */ - if (!port->cad->timeout) + /* Special case: a timeout of zero means we cannot call schedule(). + * Also if O_NONBLOCK is set then use the default implementation. */ + if (port->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) return parport_ieee1284_ecp_read_data (port, buf, length, flags); @@ -2136,8 +2139,6 @@ { struct parport_pc_private *priv = pb->private_data; - priv->ctr_writable |= 0x10; - if (priv->ecr) { pb->irq = programmable_irq_support(pb); @@ -2162,9 +2163,6 @@ if (pb->irq == PARPORT_IRQ_NONE) pb->irq = get_superio_irq(pb); - if (pb->irq == PARPORT_IRQ_NONE) - priv->ctr_writable &= ~0x10; - return pb->irq; } @@ -2293,6 +2291,7 @@ } if (p->irq != PARPORT_IRQ_NONE) { printk(", irq %d", p->irq); + priv->ctr_writable |= 0x10; if (p->dma == PARPORT_DMA_AUTO) { p->dma = PARPORT_DMA_NONE; @@ -2720,6 +2719,15 @@ int hi; /* -1 if not there, >6 for offset-method (max BAR is 6) */ } addr[4]; + + /* If set, this is called immediately after pci_enable_device. + * If it returns non-zero, no probing will take place and the + * ports will not be used. */ + int (*preinit_hook) (struct pci_dev *pdev, int autoirq, int autodma); + + /* If set, this is called after probing for ports. If 'failed' + * is non-zero we couldn't use any of the ports. */ + void (*postinit_hook) (struct pci_dev *pdev, int failed); } cards[] __devinitdata = { /* siig_1s1p_10x_550 */ { 1, { { 3, 4 }, } }, /* siig_1s1p_10x_650 */ { 1, { { 3, 4 }, } }, @@ -2896,6 +2904,10 @@ if ((err = pci_enable_device (dev)) != 0) return err; + if (cards[i].preinit_hook && + cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) + return -ENODEV; + for (n = 0; n < cards[i].numports; n++) { int lo = cards[i].addr[n].lo; int hi = cards[i].addr[n].hi; @@ -2917,6 +2929,9 @@ PARPORT_DMA_NONE, dev)) count++; } + + if (cards[i].postinit_hook) + cards[i].postinit_hook (dev, count == 0); return count == 0 ? -ENODEV : 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/parport/parport_serial.c linux-2.5/drivers/parport/parport_serial.c --- linux-2.5.5/drivers/parport/parport_serial.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/parport/parport_serial.c Fri Mar 1 15:07:38 2002 @@ -53,6 +53,15 @@ int hi; /* -1 if not there, >6 for offset-method (max BAR is 6) */ } addr[4]; + + /* If set, this is called immediately after pci_enable_device. + * If it returns non-zero, no probing will take place and the + * ports will not be used. */ + int (*preinit_hook) (struct pci_dev *pdev, int autoirq, int autodma); + + /* If set, this is called after probing for ports. If 'failed' + * is non-zero we couldn't use any of the ports. */ + void (*postinit_hook) (struct pci_dev *pdev, int failed); } cards[] __devinitdata = { /* titan_110l */ { 1, { { 3, -1 }, } }, /* titan_210l */ { 1, { { 3, -1 }, } }, @@ -239,6 +248,10 @@ int i = id->driver_data, n; int success = 0; + if (cards[i].preinit_hook && + cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) + return -ENODEV; + for (n = 0; n < cards[i].numports; n++) { struct parport *port; int lo = cards[i].addr[n].lo; @@ -265,6 +278,9 @@ } } + if (cards[i].postinit_hook) + cards[i].postinit_hook (dev, !success); + return success ? 0 : 1; } @@ -331,7 +347,7 @@ name: "parport_serial", id_table: parport_serial_pci_tbl, probe: parport_serial_pci_probe, - remove: parport_serial_pci_remove, + remove: __devexit_p(parport_serial_pci_remove), }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pci/Makefile linux-2.5/drivers/pci/Makefile --- linux-2.5.5/drivers/pci/Makefile Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/pci/Makefile Sun Mar 3 17:54:35 2002 @@ -28,8 +28,8 @@ obj-$(CONFIG_PARISC) += setup-bus.o obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o obj-$(CONFIG_ALL_PPC) += setup-bus.o -obj-$(CONFIG_DDB5476) += setup-bus.o obj-$(CONFIG_SGI_IP27) += setup-irq.o +obj-$(CONFIG_SGI_IP32) += setup-irq.o ifndef CONFIG_X86 obj-y += syscall.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pci/pci.c linux-2.5/drivers/pci/pci.c --- linux-2.5.5/drivers/pci/pci.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/pci/pci.c Sun Mar 3 17:54:35 2002 @@ -966,7 +966,7 @@ } } -void __devinit pci_read_bridge_bases(struct pci_bus *child) +void __devinit pci_read_bridge_bases(struct pci_bus *child) { struct pci_dev *dev = child->self; u8 io_base_lo, io_limit_lo; @@ -1057,7 +1057,7 @@ } } -static struct pci_bus * __devinit pci_alloc_bus(void) +static struct pci_bus * __devinit pci_alloc_bus(void) { struct pci_bus *b; @@ -1392,7 +1392,7 @@ return max; } -int __devinit pci_bus_exists(const struct list_head *list, int nr) +int __devinit pci_bus_exists(const struct list_head *list, int nr) { const struct list_head *l; @@ -1404,7 +1404,7 @@ return 0; } -struct pci_bus * __devinit pci_alloc_primary_bus(int bus) +struct pci_bus * __devinit pci_alloc_primary_bus(int bus) { struct pci_bus *b; @@ -1431,7 +1431,7 @@ return b; } -struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata) +struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata) { struct pci_bus *b = pci_alloc_primary_bus(bus); if (b) { @@ -1965,7 +1965,7 @@ return 0; } -static int __devinit pci_setup(char *str) +static int __devinit pci_setup(char *str) { while (str) { char *k = strchr(str, ','); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pci/pci.ids linux-2.5/drivers/pci/pci.ids --- linux-2.5.5/drivers/pci/pci.ids Wed Feb 20 02:10:52 2002 +++ linux-2.5/drivers/pci/pci.ids Fri Mar 1 20:35:39 2002 @@ -812,6 +812,7 @@ 0074 56k Voice Modem 1033 8014 RCV56ACF 56k Voice Modem 009b Vrc5476 + 00a6 VRC5477 AC97 00e0 USB 2.0 1034 Framatome Connectors USA Inc. 1035 Comp. & Comm. Research Lab @@ -1180,11 +1181,21 @@ 0017 Paddington Mac I/O 0018 UniNorth FireWire 0019 KeyLargo USB - 001e UniNorth PCI + 001e UniNorth Internal PCI 001f UniNorth PCI 0020 UniNorth AGP - 0021 UniNorth GMAC + 0021 UniNorth GMAC (Sun GEM) 0022 KeyLargo Mac I/O + 0024 UniNorth/Pangea GMAC (Sun GEM) + 0025 KeyLargo/Pangea Mac I/O + 0026 KeyLargo/Pangea USB + 0027 UniNorth/Pangea AGP + 0028 UniNorth/Pangea PCI + 0029 UniNorth/Pangea Internal PCI + 002d UniNorth 1.5 AGP + 002e UniNorth 1.5 PCI + 002f UniNorth 1.5 Internal PCI + 0030 UniNorth/Pangea FireWire 106c Hyundai Electronics America 8801 Dual Pentium ISA/PCI Motherboard 8802 PowerPC ISA/PCI Motherboard @@ -2607,6 +2618,8 @@ 0005 ATP850UF 0006 ATP860 NO-BIOS 0007 ATP860 + 0008 ATP865 NO-ROM + 0009 ATP865 8002 AEC6710 SCSI-2 Host Adapter 8010 AEC6712UW SCSI 8020 AEC6712U SCSI @@ -3952,6 +3965,7 @@ 9511 16PCI954 Function 1 15ed 2000 Macrolink MCCR Serial p4-7 of 8 15ed 2001 Macrolink MCCR Serial p4-15 of 16 + 9521 16PCI952 PCI/dual 16950 UART 1416 Multiwave Innovation pte Ltd 1417 Convergenet Technologies Inc 1418 Kyushu electronics systems Inc diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pci/quirks.c linux-2.5/drivers/pci/quirks.c --- linux-2.5.5/drivers/pci/quirks.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/pci/quirks.c Sun Feb 17 23:08:54 2002 @@ -444,13 +444,15 @@ static void __init quirk_amd_ordering(struct pci_dev *dev) { u32 pcic; - - pci_read_config_dword(dev, 0x42, &pcic); - if((pcic&2)==0) + pci_read_config_dword(dev, 0x4C, &pcic); + if((pcic&6)!=6) { - pcic |= 2; - printk(KERN_WARNING "BIOS disabled PCI ordering compliance, so we enabled it again.\n"); - pci_write_config_dword(dev, 0x42, pcic); + pcic |= 6; + printk(KERN_WARNING "BIOS failed to enable PCI standards compliance, fixing this error.\n"); + pci_write_config_dword(dev, 0x4C, pcic); + pci_read_config_dword(dev, 0x84, &pcic); + pcic |= (1<<23); /* Required in this mode */ + pci_write_config_dword(dev, 0x84, pcic); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pci/setup-bus.c linux-2.5/drivers/pci/setup-bus.c --- linux-2.5.5/drivers/pci/setup-bus.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/pci/setup-bus.c Mon Jan 14 22:39:45 2002 @@ -201,6 +201,16 @@ b->resource[0]->end = ranges->io_end - 1; b->resource[1]->end = ranges->mem_end - 1; + /* Add bridge resources to the resource tree. */ + if (b->resource[0]->end > b->resource[0]->start && + request_resource(bus->resource[0], b->resource[0]) < 0) + printk(KERN_ERR "PCI: failed to reserve IO " + "for bus %d\n", b->number); + if (b->resource[1]->end > b->resource[1]->start && + request_resource(bus->resource[1], b->resource[1]) < 0) + printk(KERN_ERR "PCI: failed to reserve MEM " + "for bus %d\n", b->number); + pci_setup_bridge(b); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pcmcia/au1000_generic.c linux-2.5/drivers/pcmcia/au1000_generic.c --- linux-2.5.5/drivers/pcmcia/au1000_generic.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/pcmcia/au1000_generic.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,696 @@ +/* + * + * Alchemy Semi Au1000 pcmcia driver + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" + +#include +#include +#include + +#include +#include + +#ifdef PCMCIA_DEBUG +static int pc_debug; +#endif + +MODULE_AUTHOR("Pete Popov, MontaVista Software "); +MODULE_DESCRIPTION("Linux PCMCIA Card Services: Au1x00 Socket Controller"); + +#define MAP_SIZE 0x1000000 + +/* This structure maintains housekeeping state for each socket, such + * as the last known values of the card detect pins, or the Card Services + * callback value associated with the socket: + */ +static struct au1000_pcmcia_socket *pcmcia_socket; +static int socket_count; + + +/* Returned by the low-level PCMCIA interface: */ +static struct pcmcia_low_level *pcmcia_low_level; + +/* Event poll timer structure */ +static struct timer_list poll_timer; + + +/* Prototypes for routines which are used internally: */ + +static int au1000_pcmcia_driver_init(void); +static void au1000_pcmcia_driver_shutdown(void); +static void au1000_pcmcia_task_handler(void *data); +static void au1000_pcmcia_poll_event(u32 data); +static void au1000_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs); +static struct tq_struct au1000_pcmcia_task; + +#ifdef CONFIG_PROC_FS +static int au1000_pcmcia_proc_status(char *buf, char **start, + off_t pos, int count, int *eof, void *data); +#endif + + +/* Prototypes for operations which are exported to the + * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core: + */ + +static int au1000_pcmcia_init(u32 sock); +static int au1000_pcmcia_suspend(u32 sock); +static int au1000_pcmcia_register_callback(u32 sock, + void (*handler)(void *, u32), void *info); +static int au1000_pcmcia_inquire_socket(u32 sock, socket_cap_t *cap); +static int au1000_pcmcia_get_status(u32 sock, u_int *value); +static int au1000_pcmcia_get_socket(u32 sock, socket_state_t *state); +static int au1000_pcmcia_set_socket(u32 sock, socket_state_t *state); +static int au1000_pcmcia_get_io_map(u32 sock, struct pccard_io_map *io); +static int au1000_pcmcia_set_io_map(u32 sock, struct pccard_io_map *io); +static int au1000_pcmcia_get_mem_map(u32 sock, struct pccard_mem_map *mem); +static int au1000_pcmcia_set_mem_map(u32 sock, struct pccard_mem_map *mem); +#ifdef CONFIG_PROC_FS +static void au1000_pcmcia_proc_setup(u32 sock, struct proc_dir_entry *base); +#endif + +static struct pccard_operations au1000_pcmcia_operations = { + au1000_pcmcia_init, + au1000_pcmcia_suspend, + au1000_pcmcia_register_callback, + au1000_pcmcia_inquire_socket, + au1000_pcmcia_get_status, + au1000_pcmcia_get_socket, + au1000_pcmcia_set_socket, + au1000_pcmcia_get_io_map, + au1000_pcmcia_set_io_map, + au1000_pcmcia_get_mem_map, + au1000_pcmcia_set_mem_map, +#ifdef CONFIG_PROC_FS + au1000_pcmcia_proc_setup +#endif +}; + +static int __init au1000_pcmcia_driver_init(void) +{ + servinfo_t info; + struct pcmcia_init pcmcia_init; + struct pcmcia_state state; + unsigned int i; + unsigned long timing3; + + printk("\nAu1x00 PCMCIA (CS release %s)\n", CS_RELEASE); + + CardServices(GetCardServicesInfo, &info); + + if(info.Revision!=CS_RELEASE_CODE){ + printk(KERN_ERR "Card Services release codes do not match\n"); + return -1; + } + +#ifdef CONFIG_MIPS_PB1000 + pcmcia_low_level=&pb1000_pcmcia_ops; +#elif defined(CONFIG_MIPS_PB1500) + pcmcia_low_level=&pb1500_pcmcia_ops; +#else +#error Unsupported AU1000 board. +#endif + + pcmcia_init.handler=au1000_pcmcia_interrupt; + if((socket_count=pcmcia_low_level->init(&pcmcia_init))<0) { + printk(KERN_ERR "Unable to initialize PCMCIA service.\n"); + return -EIO; + } + + /* setup the static bus controller */ + timing3 = 0x100e3a07; + writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */ + writel(timing3, MEM_STTIME3); + writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */ + au_sync_delay(1); + + pcmcia_socket = + kmalloc(sizeof(struct au1000_pcmcia_socket) * socket_count, + GFP_KERNEL); + if (!pcmcia_socket) { + printk(KERN_ERR "Card Services can't get memory \n"); + return -1; + } + memset(pcmcia_socket, 0, + sizeof(struct au1000_pcmcia_socket) * socket_count); + + for(i=0; i < socket_count; i++) { + + if(pcmcia_low_level->socket_state(i, &state)<0){ + printk(KERN_ERR "Unable to get PCMCIA status\n"); + return -EIO; + } + pcmcia_socket[i].k_state=state; + pcmcia_socket[i].cs_state.csc_mask=SS_DETECT; + + if (i == 0) { + pcmcia_socket[i].virt_io = + (u32)ioremap(0xC0000000, 0x1000); + pcmcia_socket[i].phys_attr = 0xC4000000; + pcmcia_socket[i].phys_mem = 0xC8000000; + } + else { + printk(KERN_ERR "au1000: socket 1 not supported\n"); + return 1; + } + } + + /* Only advertise as many sockets as we can detect: */ + if(register_ss_entry(socket_count, &au1000_pcmcia_operations)<0){ + printk(KERN_ERR "Unable to register socket service routine\n"); + return -ENXIO; + } + + /* Start the event poll timer. + * It will reschedule by itself afterwards. + */ + au1000_pcmcia_poll_event(0); + + DEBUG(1, "au1000: initialization complete\n"); + return 0; + +} /* au1000_pcmcia_driver_init() */ + +module_init(au1000_pcmcia_driver_init); + +static void __exit au1000_pcmcia_driver_shutdown(void) +{ + int i; + + del_timer_sync(&poll_timer); + unregister_ss_entry(&au1000_pcmcia_operations); + pcmcia_low_level->shutdown(); + flush_scheduled_tasks(); + for(i=0; i < socket_count; i++) { + if (pcmcia_socket[i].virt_io) + iounmap((void *)pcmcia_socket[i].virt_io); + } + DEBUG(1, "au1000: shutdown complete\n"); +} + +module_exit(au1000_pcmcia_driver_shutdown); + +static int au1000_pcmcia_init(unsigned int sock) { return 0; } + +static int au1000_pcmcia_suspend(unsigned int sock) +{ + return 0; +} + + +static inline unsigned +au1000_pcmcia_events(struct pcmcia_state *state, + struct pcmcia_state *prev_state, + unsigned int mask, unsigned int flags) +{ + unsigned int events=0; + + if(state->detect!=prev_state->detect){ + DEBUG(2, "%s(): card detect value %u\n", + __FUNCTION__, state->detect); + events |= mask&SS_DETECT; + } + + + if(state->ready!=prev_state->ready){ + DEBUG(2, "%s(): card ready value %u\n", + __FUNCTION__, state->ready); + events |= mask&((flags&SS_IOCARD)?0:SS_READY); + } + + *prev_state=*state; + return events; + +} /* au1000_pcmcia_events() */ + + +/* + * Au1000_pcmcia_task_handler() + * Processes socket events. + */ +static void au1000_pcmcia_task_handler(void *data) +{ + struct pcmcia_state state; + int i, events, irq_status; + + for(i=0; isocket_state(i, &state))<0) + printk(KERN_ERR "low-level PCMCIA error\n"); + + events = au1000_pcmcia_events(&state, + &pcmcia_socket[i].k_state, + pcmcia_socket[i].cs_state.csc_mask, + pcmcia_socket[i].cs_state.flags); + if(pcmcia_socket[i].handler!=NULL) { + pcmcia_socket[i].handler(pcmcia_socket[i].handler_info, + events); + } + } + +} /* au1000_pcmcia_task_handler() */ + +static struct tq_struct au1000_pcmcia_task = { + routine: au1000_pcmcia_task_handler +}; + + +static void au1000_pcmcia_poll_event(u32 dummy) +{ + poll_timer.function = au1000_pcmcia_poll_event; + poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD; + add_timer(&poll_timer); + schedule_task(&au1000_pcmcia_task); +} + + +/* + * au1000_pcmcia_interrupt() + * The actual interrupt work is performed by au1000_pcmcia_task(), + * because the Card Services event handling code performs scheduling + * operations which cannot be executed from within an interrupt context. + */ +static void +au1000_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + schedule_task(&au1000_pcmcia_task); +} + + +static int +au1000_pcmcia_register_callback(unsigned int sock, + void (*handler)(void *, unsigned int), void *info) +{ + if(handler==NULL){ + pcmcia_socket[sock].handler=NULL; + MOD_DEC_USE_COUNT; + } else { + MOD_INC_USE_COUNT; + pcmcia_socket[sock].handler=handler; + pcmcia_socket[sock].handler_info=info; + } + return 0; +} + + +/* au1000_pcmcia_inquire_socket() + * + * From the sa1100 socket driver : + * + * Implements the inquire_socket() operation for the in-kernel PCMCIA + * service (formerly SS_InquireSocket in Card Services). We set + * SS_CAP_STATIC_MAP, which disables the memory resource database check. + * (Mapped memory is set up within the socket driver itself.) + * + * In conjunction with the STATIC_MAP capability is a new field, + * `io_offset', recommended by David Hinds. Rather than go through + * the SetIOMap interface (which is not quite suited for communicating + * window locations up from the socket driver), we just pass up + * an offset which is applied to client-requested base I/O addresses + * in alloc_io_space(). + * + * Returns: 0 on success, -1 if no pin has been configured for `sock' + */ +static int au1000_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap) +{ + struct pcmcia_irq_info irq_info; + + if(sock > socket_count){ + printk(KERN_ERR "au1000: socket %u not configured\n", sock); + return -1; + } + + /* from the sa1100_generic driver: */ + + /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the + * force_low argument to validate_mem() in rsrc_mgr.c -- since in + * general, the mapped * addresses of the PCMCIA memory regions + * will not be within 0xffff, setting force_low would be + * undesirable. + * + * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory + * resource database; we instead pass up physical address ranges + * and allow other parts of Card Services to deal with remapping. + * + * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but + * not 32-bit CardBus devices. + */ + cap->features=(SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD); + + irq_info.sock=sock; + irq_info.irq=-1; + + if(pcmcia_low_level->get_irq_info(&irq_info)<0){ + printk(KERN_ERR "Error obtaining IRQ info socket %u\n", sock); + return -1; + } + + cap->irq_mask=0; + cap->map_size=MAP_SIZE; + cap->pci_irq=irq_info.irq; + cap->io_offset=pcmcia_socket[sock].virt_io; + + return 0; + +} /* au1000_pcmcia_inquire_socket() */ + + +static int +au1000_pcmcia_get_status(unsigned int sock, unsigned int *status) +{ + struct pcmcia_state state; + + + if((pcmcia_low_level->socket_state(sock, &state))<0){ + printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); + return -1; + } + + pcmcia_socket[sock].k_state = state; + + *status = state.detect?SS_DETECT:0; + + *status |= state.ready?SS_READY:0; + + *status |= pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0; + + if(pcmcia_socket[sock].cs_state.flags&SS_IOCARD) + *status |= state.bvd1?SS_STSCHG:0; + else { + if(state.bvd1==0) + *status |= SS_BATDEAD; + else if(state.bvd2 == 0) + *status |= SS_BATWARN; + } + + *status|=state.vs_3v?SS_3VCARD:0; + + *status|=state.vs_Xv?SS_XVCARD:0; + + DEBUG(2, "\tstatus: %s%s%s%s%s%s%s%s\n", + (*status&SS_DETECT)?"DETECT ":"", + (*status&SS_READY)?"READY ":"", + (*status&SS_BATDEAD)?"BATDEAD ":"", + (*status&SS_BATWARN)?"BATWARN ":"", + (*status&SS_POWERON)?"POWERON ":"", + (*status&SS_STSCHG)?"STSCHG ":"", + (*status&SS_3VCARD)?"3VCARD ":"", + (*status&SS_XVCARD)?"XVCARD ":""); + + return 0; + +} /* au1000_pcmcia_get_status() */ + + +static int +au1000_pcmcia_get_socket(unsigned int sock, socket_state_t *state) +{ + *state = pcmcia_socket[sock].cs_state; + return 0; +} + + +static int +au1000_pcmcia_set_socket(unsigned int sock, socket_state_t *state) +{ + struct pcmcia_configure configure; + + DEBUG(2, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n" + "\tVcc %d Vpp %d irq %d\n", + (state->csc_mask==0)?"":"", + (state->csc_mask&SS_DETECT)?"DETECT ":"", + (state->csc_mask&SS_READY)?"READY ":"", + (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", + (state->csc_mask&SS_BATWARN)?"BATWARN ":"", + (state->csc_mask&SS_STSCHG)?"STSCHG ":"", + (state->flags==0)?"":"", + (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", + (state->flags&SS_IOCARD)?"IOCARD ":"", + (state->flags&SS_RESET)?"RESET ":"", + (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", + (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"", + state->Vcc, state->Vpp, state->io_irq); + + configure.sock=sock; + configure.vcc=state->Vcc; + configure.vpp=state->Vpp; + configure.output=(state->flags&SS_OUTPUT_ENA)?1:0; + configure.speaker=(state->flags&SS_SPKR_ENA)?1:0; + configure.reset=(state->flags&SS_RESET)?1:0; + + if(pcmcia_low_level->configure_socket(&configure)<0){ + printk(KERN_ERR "Unable to configure socket %u\n", sock); + return -1; + } + + pcmcia_socket[sock].cs_state = *state; + return 0; + +} /* au1000_pcmcia_set_socket() */ + + +static int +au1000_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map) +{ + DEBUG(1, "au1000_pcmcia_get_io_map: sock %d\n", sock); + if(map->map>=MAX_IO_WIN){ + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + *map=pcmcia_socket[sock].io_map[map->map]; + return 0; +} + + +int +au1000_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) +{ + unsigned int speed; + unsigned long start; + + if(map->map>=MAX_IO_WIN){ + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + + if(map->flags&MAP_ACTIVE){ + speed=(map->speed>0)?map->speed:AU1000_PCMCIA_IO_SPEED; + pcmcia_socket[sock].speed_io=speed; + } + + start=map->start; + + if(map->stop==1) { + map->stop=PAGE_SIZE-1; + } + + map->start=pcmcia_socket[sock].virt_io; + map->stop=map->start+(map->stop-start); + pcmcia_socket[sock].io_map[map->map]=*map; + DEBUG(3, "set_io_map %d start %x stop %x\n", + map->map, map->start, map->stop); + return 0; + +} /* au1000_pcmcia_set_io_map() */ + + +static int +au1000_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + + if(map->map>=MAX_WIN) { + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + *map=pcmcia_socket[sock].mem_map[map->map]; + return 0; +} + + +static int +au1000_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + unsigned int speed; + unsigned long start; + u_long flags; + + if(map->map>=MAX_WIN){ + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + + if(map->flags&MAP_ACTIVE){ + speed=(map->speed>0)?map->speed:AU1000_PCMCIA_MEM_SPEED; + + /* TBD */ + if(map->flags&MAP_ATTRIB){ + pcmcia_socket[sock].speed_attr=speed; + } + else { + pcmcia_socket[sock].speed_mem=speed; + } + } + + save_flags(flags); + cli(); + start=map->sys_start; + + if(map->sys_stop==0) + map->sys_stop=MAP_SIZE-1; + + if (map->flags & MAP_ATTRIB) { + map->sys_start = pcmcia_socket[sock].phys_attr + + map->card_start; + } + else { + map->sys_start = pcmcia_socket[sock].phys_mem + + map->card_start; + } + + map->sys_stop=map->sys_start+(map->sys_stop-start); + pcmcia_socket[sock].mem_map[map->map]=*map; + restore_flags(flags); + DEBUG(3, "set_mem_map %d start %x stop %x card_start %x\n", + map->map, map->sys_start, map->sys_stop, + map->card_start); + return 0; + +} /* au1000_pcmcia_set_mem_map() */ + + +#if defined(CONFIG_PROC_FS) + +static void +au1000_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base) +{ + struct proc_dir_entry *entry; + + if((entry=create_proc_entry("status", 0, base))==NULL){ + printk(KERN_ERR "Unable to install \"status\" procfs entry\n"); + return; + } + + entry->read_proc=au1000_pcmcia_proc_status; + entry->data=(void *)sock; +} + + +/* au1000_pcmcia_proc_status() + * Implements the /proc/bus/pccard/??/status file. + * + * Returns: the number of characters added to the buffer + */ +static int +au1000_pcmcia_proc_status(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + char *p=buf; + unsigned int sock=(unsigned int)data; + + p+=sprintf(p, "k_flags : %s%s%s%s%s%s%s\n", + pcmcia_socket[sock].k_state.detect?"detect ":"", + pcmcia_socket[sock].k_state.ready?"ready ":"", + pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"", + pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"", + pcmcia_socket[sock].k_state.wrprot?"wrprot ":"", + pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"", + pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":""); + + p+=sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n", + pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"", + pcmcia_socket[sock].k_state.ready?"SS_READY ":"", + pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"", + pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ + "SS_IOCARD ":"", + (pcmcia_socket[sock].cs_state.flags&SS_IOCARD && + pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"", + ((pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && + (pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"", + ((pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && + (pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"", + pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"", + pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":""); + + p+=sprintf(p, "mask : %s%s%s%s%s\n", + pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\ + "SS_DETECT ":"", + pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\ + "SS_READY ":"", + pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\ + "SS_BATDEAD ":"", + pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\ + "SS_BATWARN ":"", + pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\ + "SS_STSCHG ":""); + + p+=sprintf(p, "cs_flags : %s%s%s%s%s\n", + pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\ + "SS_PWR_AUTO ":"", + pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ + "SS_IOCARD ":"", + pcmcia_socket[sock].cs_state.flags&SS_RESET?\ + "SS_RESET ":"", + pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\ + "SS_SPKR_ENA ":"", + pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\ + "SS_OUTPUT_ENA ":""); + + p+=sprintf(p, "Vcc : %d\n", pcmcia_socket[sock].cs_state.Vcc); + p+=sprintf(p, "Vpp : %d\n", pcmcia_socket[sock].cs_state.Vpp); + p+=sprintf(p, "irq : %d\n", pcmcia_socket[sock].cs_state.io_irq); + p+=sprintf(p, "I/O : %u\n", pcmcia_socket[sock].speed_io); + p+=sprintf(p, "attribute: %u\n", pcmcia_socket[sock].speed_attr); + p+=sprintf(p, "common : %u\n", pcmcia_socket[sock].speed_mem); + return p-buf; +} + + +#endif /* defined(CONFIG_PROC_FS) */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pcmcia/au1000_pb1000.c linux-2.5/drivers/pcmcia/au1000_pb1000.c --- linux-2.5.5/drivers/pcmcia/au1000_pb1000.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/pcmcia/au1000_pb1000.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,307 @@ +/* + * + * Alchemy Semi PB1000 board specific pcmcia routines. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" + +#include +#include +#include + +#include +#include +#include + + +extern struct pcmcia_x_table x_table; + +static int pb1000_pcmcia_init(struct pcmcia_init *init) +{ + u32 pcr; + pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; + + writel(0x8000, PB1000_MDR); /* clear pcmcia interrupt */ + au_sync_delay(100); + writel(0x4000, PB1000_MDR); /* enable pcmcia interrupt */ + au_sync(); + + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); + writew(pcr, PB1000_PCR); + au_sync_delay(20); + + /* There's two sockets, but only the first one, 0, is used and tested */ + return 1; +} + +static int pb1000_pcmcia_shutdown(void) +{ + u16 pcr; + pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); + writew(pcr, PB1000_PCR); + au_sync_delay(20); + return 0; +} + +static int +pb1000_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state) +{ + u16 levels, pcr; + unsigned char vs; + + levels = readw(PB1000_ACR1); + pcr = readw(PB1000_PCR); + + state->ready = 0; + state->vs_Xv = 0; + state->vs_3v = 0; + state->detect = 0; + + /* + * This is tricky. The READY pin is also the #IRQ pin. We'll treat + * READY as #IRQ and set state->ready to 1 whenever state->detect + * is true. + */ + + /* + * CD1/2 are active low; so are the VSS pins; Ready is active high + */ + if (sock == 0) { + if (!(levels & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2))) { + state->detect = 1; + vs = (levels >> 4) & 0x3; + switch (vs) { + case 0: + case 1: + case 2: + state->vs_3v=1; + break; + case 3: + default: + break; + } + } + } + else if (sock == 1) { + if (!(levels & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2))) { + state->detect = 1; + vs = (levels >> 12) & 0x3; + switch (vs) { + case 0: + case 1: + case 2: + state->vs_3v=1; + break; + case 3: + default: + break; + } + } + } + else { + printk(KERN_ERR "pb1000 socket_state bad sock %d\n", sock); + } + + if (state->detect) + state->ready = 1; + + state->bvd1=1; + state->bvd2=1; + state->wrprot=0; + return 1; +} + + +static int pb1000_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + + if(info->sock > PCMCIA_MAX_SOCK) return -1; + + if(info->sock == 0) + info->irq = AU1000_GPIO_15; + else + info->irq = -1; + + return 0; +} + + +static int +pb1000_pcmcia_configure_socket(const struct pcmcia_configure *configure) +{ + u16 pcr; + + if(configure->sock > PCMCIA_MAX_SOCK) return -1; + + pcr = readw(PB1000_PCR); + + if (configure->sock == 0) { + pcr &= ~(PCR_SLOT_0_VCC0 | PCR_SLOT_0_VCC1 | + PCR_SLOT_0_VPP0 | PCR_SLOT_0_VPP1); + } + else { + pcr &= ~(PCR_SLOT_1_VCC0 | PCR_SLOT_1_VCC1 | + PCR_SLOT_1_VPP0 | PCR_SLOT_1_VPP1); + } + + pcr &= ~PCR_SLOT_0_RST; + /* + writew(pcr, PB1000_PCR); + au_sync_delay(200); + */ + DEBUG(KERN_INFO "Vcc %dV Vpp %dV, pcr %x\n", + configure->vcc, configure->vpp, pcr); + switch(configure->vcc){ + case 0: /* Vcc 0 */ + switch(configure->vpp) { + case 0: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_GND, + configure->sock); + break; + case 12: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_12V, + configure->sock); + break; + case 50: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_5V, + configure->sock); + break; + case 33: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_3V, + configure->sock); + break; + default: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, + configure->sock); + printk("%s: bad Vcc/Vpp (%d:%d)\n", + __FUNCTION__, + configure->vcc, + configure->vpp); + break; + } + break; + case 50: /* Vcc 5V */ + switch(configure->vpp) { + case 0: + pcr |= SET_VCC_VPP(VCC_5V,VPP_GND, + configure->sock); + break; + case 50: + pcr |= SET_VCC_VPP(VCC_5V,VPP_5V, + configure->sock); + break; + case 12: + pcr |= SET_VCC_VPP(VCC_5V,VPP_12V, + configure->sock); + break; + case 33: + pcr |= SET_VCC_VPP(VCC_5V,VPP_3V, + configure->sock); + break; + default: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, + configure->sock); + printk("%s: bad Vcc/Vpp (%d:%d)\n", + __FUNCTION__, + configure->vcc, + configure->vpp); + break; + } + break; + case 33: /* Vcc 3.3V */ + switch(configure->vpp) { + case 0: + pcr |= SET_VCC_VPP(VCC_3V,VPP_GND, + configure->sock); + break; + case 50: + pcr |= SET_VCC_VPP(VCC_3V,VPP_5V, + configure->sock); + break; + case 12: + pcr |= SET_VCC_VPP(VCC_3V,VPP_12V, + configure->sock); + break; + case 33: + pcr |= SET_VCC_VPP(VCC_3V,VPP_3V, + configure->sock); + break; + default: + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, + configure->sock); + printk("%s: bad Vcc/Vpp (%d:%d)\n", + __FUNCTION__, + configure->vcc, + configure->vpp); + break; + } + break; + default: /* what's this ? */ + pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock); + printk(KERN_ERR "%s: bad Vcc %d\n", + __FUNCTION__, configure->vcc); + break; + } + + pcr &= ~(PCR_SLOT_0_RST); + if (configure->reset) { + pcr |= PCR_SLOT_0_RST; + } + writew(pcr, PB1000_PCR); + au_sync_delay(300); + return 0; +} + +struct pcmcia_low_level pb1000_pcmcia_ops = { + pb1000_pcmcia_init, + pb1000_pcmcia_shutdown, + pb1000_pcmcia_socket_state, + pb1000_pcmcia_get_irq_info, + pb1000_pcmcia_configure_socket +}; + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pcmcia/cardbus.c linux-2.5/drivers/pcmcia/cardbus.c --- linux-2.5.5/drivers/pcmcia/cardbus.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/pcmcia/cardbus.c Mon Feb 11 02:04:57 2002 @@ -286,6 +286,10 @@ strcpy(dev->dev.bus_id, dev->slot_name); device_register(&dev->dev); + strcpy(dev->dev.name, dev->name); + strcpy(dev->dev.bus_id, dev->slot_name); + device_register(&dev->dev); + /* FIXME: Do we need to enable the expansion ROM? */ for (r = 0; r < 7; r++) { struct resource *res = dev->resource + r; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pcmcia/cistpl.c linux-2.5/drivers/pcmcia/cistpl.c --- linux-2.5.5/drivers/pcmcia/cistpl.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/pcmcia/cistpl.c Thu Dec 13 16:32:36 2001 @@ -264,11 +264,11 @@ (s->cis_mem.sys_start == 0)) { int low = !(s->cap.features & SS_CAP_PAGE_REGS); vs = s; - validate_mem(cis_readable, checksum_match, low); + validate_mem(cis_readable, checksum_match, low, s); s->cis_mem.sys_start = 0; vs = NULL; if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size, - s->cap.map_size, low, "card services")) { + s->cap.map_size, low, "card services", s)) { printk(KERN_NOTICE "cs: unable to map card memory!\n"); return CS_OUT_OF_RESOURCE; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pcmcia/cs.c linux-2.5/drivers/pcmcia/cs.c --- linux-2.5.5/drivers/pcmcia/cs.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/pcmcia/cs.c Fri Mar 1 20:36:36 2002 @@ -809,7 +809,7 @@ return 1; for (i = 0; i < MAX_IO_WIN; i++) { if (s->io[i].NumPorts == 0) { - if (find_io_region(base, num, align, name) == 0) { + if (find_io_region(base, num, align, name, s) == 0) { s->io[i].Attributes = attr; s->io[i].BasePort = *base; s->io[i].NumPorts = s->io[i].InUse = num; @@ -821,7 +821,7 @@ /* Try to extend top of window */ try = s->io[i].BasePort + s->io[i].NumPorts; if ((*base == 0) || (*base == try)) - if (find_io_region(&try, num, 0, name) == 0) { + if (find_io_region(&try, num, 0, name, s) == 0) { *base = try; s->io[i].NumPorts += num; s->io[i].InUse += num; @@ -830,7 +830,7 @@ /* Try to extend bottom of window */ try = s->io[i].BasePort - num; if ((*base == 0) || (*base == try)) - if (find_io_region(&try, num, 0, name) == 0) { + if (find_io_region(&try, num, 0, name, s) == 0) { s->io[i].BasePort = *base = try; s->io[i].NumPorts += num; s->io[i].InUse += num; @@ -1268,7 +1268,7 @@ } else c = CONFIG(handle); if ((c != NULL) && (c->state & CONFIG_LOCKED) && - (c->IntType & INT_MEMORY_AND_IO)) { + (c->IntType & (INT_MEMORY_AND_IO|INT_ZOOMED_VIDEO))) { u_char reg; if (c->Present & PRESENT_PIN_REPLACE) { read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®); @@ -1696,6 +1696,8 @@ c->Attributes = req->Attributes; if (req->IntType & INT_MEMORY_AND_IO) s->socket.flags |= SS_IOCARD; + if (req->IntType & INT_ZOOMED_VIDEO) + s->socket.flags |= SS_ZVCARD|SS_IOCARD; if (req->Attributes & CONF_ENABLE_DMA) s->socket.flags |= SS_DMA_MODE; if (req->Attributes & CONF_ENABLE_SPKR) @@ -1974,7 +1976,7 @@ find_mem_region(&win->base, win->size, align, (req->Attributes & WIN_MAP_BELOW_1MB) || !(s->cap.features & SS_CAP_PAGE_REGS), - (*handle)->dev_info)) + (*handle)->dev_info, s)) return CS_IN_USE; (*handle)->state |= CLIENT_WIN_REQ(w); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pcmcia/cs_internal.h linux-2.5/drivers/pcmcia/cs_internal.h --- linux-2.5.5/drivers/pcmcia/cs_internal.h Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/pcmcia/cs_internal.h Tue Feb 26 16:31:43 2002 @@ -238,11 +238,11 @@ /* In rsrc_mgr */ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), - int force_low); + int force_low, socket_info_t *s); int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, - char *name); + char *name, socket_info_t *s); int find_mem_region(u_long *base, u_long num, u_long align, - int force_low, char *name); + int force_low, char *name, socket_info_t *s); int try_irq(u_int Attributes, int irq, int specific); void undo_irq(u_int Attributes, int irq); int adjust_resource_info(client_handle_t handle, adjust_t *adj); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pcmcia/i82092.c linux-2.5/drivers/pcmcia/i82092.c --- linux-2.5.5/drivers/pcmcia/i82092.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/pcmcia/i82092.c Thu Dec 13 17:35:27 2001 @@ -42,7 +42,7 @@ name: "i82092aa", id_table: i82092aa_pci_ids, probe: i82092aa_pci_probe, - remove: i82092aa_pci_remove, + remove: __devexit_p(i82092aa_pci_remove), suspend: NULL, resume: NULL }; @@ -160,7 +160,7 @@ return 0; } -static void __exit i82092aa_pci_remove(struct pci_dev *dev) +static void __devexit i82092aa_pci_remove(struct pci_dev *dev) { enter("i82092aa_pci_remove"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pcmcia/pci_socket.c linux-2.5/drivers/pcmcia/pci_socket.c --- linux-2.5.5/drivers/pcmcia/pci_socket.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/pcmcia/pci_socket.c Thu Dec 13 16:32:36 2001 @@ -249,7 +249,7 @@ name: "cardbus", id_table: cardbus_table, probe: cardbus_probe, - remove: cardbus_remove, + remove: __devexit_p(cardbus_remove), suspend: cardbus_suspend, resume: cardbus_resume, }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pcmcia/pci_socket.h linux-2.5/drivers/pcmcia/pci_socket.h --- linux-2.5.5/drivers/pcmcia/pci_socket.h Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/pcmcia/pci_socket.h Sun Mar 3 17:54:35 2002 @@ -23,7 +23,9 @@ struct socket_info_t *pcmcia_socket; struct tq_struct tq_task; struct timer_list poll_timer; - + /* Zoom video behaviour is so chip specific its not worth adding + this to _ops */ + void (*zoom_video)(struct pci_socket *, int); /* A few words of private data for the low-level driver.. */ unsigned int private[8]; } pci_socket_t; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pcmcia/rsrc_mgr.c linux-2.5/drivers/pcmcia/rsrc_mgr.c --- linux-2.5.5/drivers/pcmcia/rsrc_mgr.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/pcmcia/rsrc_mgr.c Thu Dec 13 16:32:36 2001 @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -103,8 +104,82 @@ ======================================================================*/ -#define check_io_resource(b,n) check_resource(&ioport_resource, (b), (n)) -#define check_mem_resource(b,n) check_resource(&iomem_resource, (b), (n)) +static struct resource *resource_parent(unsigned long b, unsigned long n, + int flags, struct pci_dev *dev) +{ +#ifdef CONFIG_PCI + struct resource res, *pr; + + if (dev != NULL) { + res.start = b; + res.end = b + n - 1; + res.flags = flags; + pr = pci_find_parent_resource(dev, &res); + if (pr) + return pr; + } +#endif /* CONFIG_PCI */ + if (flags & IORESOURCE_MEM) + return &iomem_resource; + return &ioport_resource; +} + +static inline int check_io_resource(unsigned long b, unsigned long n, + struct pci_dev *dev) +{ + return check_resource(resource_parent(b, n, IORESOURCE_IO, dev), b, n); +} + +static inline int check_mem_resource(unsigned long b, unsigned long n, + struct pci_dev *dev) +{ + return check_resource(resource_parent(b, n, IORESOURCE_MEM, dev), b, n); +} + +static struct resource *make_resource(unsigned long b, unsigned long n, + int flags, char *name) +{ + struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL); + + if (res) { + memset(res, 0, sizeof(*res)); + res->name = name; + res->start = b; + res->end = b + n - 1; + res->flags = flags | IORESOURCE_BUSY; + } + return res; +} + +static int request_io_resource(unsigned long b, unsigned long n, + char *name, struct pci_dev *dev) +{ + struct resource *res = make_resource(b, n, IORESOURCE_IO, name); + struct resource *pr = resource_parent(b, n, IORESOURCE_IO, dev); + int err = -ENOMEM; + + if (res) { + err = request_resource(pr, res); + if (err) + kfree(res); + } + return err; +} + +static int request_mem_resource(unsigned long b, unsigned long n, + char *name, struct pci_dev *dev) +{ + struct resource *res = make_resource(b, n, IORESOURCE_MEM, name); + struct resource *pr = resource_parent(b, n, IORESOURCE_MEM, dev); + int err = -ENOMEM; + + if (res) { + err = request_resource(pr, res); + if (err) + kfree(res); + } + return err; +} /*====================================================================== @@ -194,7 +269,7 @@ } memset(b, 0, 256); for (i = base, most = 0; i < base+num; i += 8) { - if (check_io_resource(i, 8)) + if (check_io_resource(i, 8, NULL)) continue; hole = inb(i); for (j = 1; j < 8; j++) @@ -207,7 +282,7 @@ bad = any = 0; for (i = base; i < base+num; i += 8) { - if (check_io_resource(i, 8)) + if (check_io_resource(i, 8, NULL)) continue; for (j = 0; j < 8; j++) if (inb(i+j) != most) break; @@ -247,7 +322,8 @@ ======================================================================*/ static int do_mem_probe(u_long base, u_long num, - int (*is_valid)(u_long), int (*do_cksum)(u_long)) + int (*is_valid)(u_long), int (*do_cksum)(u_long), + socket_info_t *s) { u_long i, j, bad, fail, step; @@ -258,13 +334,14 @@ for (i = j = base; i < base+num; i = j + step) { if (!fail) { for (j = i; j < base+num; j += step) - if ((check_mem_resource(j, step) == 0) && is_valid(j)) + if ((check_mem_resource(j, step, s->cap.cb_dev) == 0) && + is_valid(j)) break; fail = ((i == base) && (j == base+num)); } if (fail) { for (j = i; j < base+num; j += 2*step) - if ((check_mem_resource(j, 2*step) == 0) && + if ((check_mem_resource(j, 2*step, s->cap.cb_dev) == 0) && do_cksum(j) && do_cksum(j+step)) break; } @@ -283,12 +360,12 @@ static u_long inv_probe(int (*is_valid)(u_long), int (*do_cksum)(u_long), - resource_map_t *m) + resource_map_t *m, socket_info_t *s) { u_long ok; if (m == &mem_db) return 0; - ok = inv_probe(is_valid, do_cksum, m->next); + ok = inv_probe(is_valid, do_cksum, m->next, s); if (ok) { if (m->base >= 0x100000) sub_interval(&mem_db, m->base, m->num); @@ -296,11 +373,11 @@ } if (m->base < 0x100000) return 0; - return do_mem_probe(m->base, m->num, is_valid, do_cksum); + return do_mem_probe(m->base, m->num, is_valid, do_cksum, s); } void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), - int force_low) + int force_low, socket_info_t *s) { resource_map_t *m, *n; static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; @@ -310,7 +387,7 @@ if (!probe_mem) return; /* We do up to four passes through the list */ if (!force_low) { - if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next) > 0)) + if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next, s) > 0)) return; printk(KERN_NOTICE "cs: warning: no high memory space " "available!\n"); @@ -321,7 +398,7 @@ /* Only probe < 1 MB */ if (m->base >= 0x100000) continue; if ((m->base | m->num) & 0xffff) { - ok += do_mem_probe(m->base, m->num, is_valid, do_cksum); + ok += do_mem_probe(m->base, m->num, is_valid, do_cksum, s); continue; } /* Special probe for 64K-aligned block */ @@ -331,7 +408,7 @@ if (ok >= mem_limit) sub_interval(&mem_db, b, 0x10000); else - ok += do_mem_probe(b, 0x10000, is_valid, do_cksum); + ok += do_mem_probe(b, 0x10000, is_valid, do_cksum, s); } } } @@ -340,7 +417,7 @@ #else /* CONFIG_ISA */ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), - int force_low) + int force_low, socket_info_t *s) { resource_map_t *m; static int done = 0; @@ -348,7 +425,7 @@ if (!probe_mem || done++) return; for (m = mem_db.next; m != &mem_db; m = m->next) - if (do_mem_probe(m->base, m->num, is_valid, do_cksum)) + if (do_mem_probe(m->base, m->num, is_valid, do_cksum, s)) return; } @@ -368,7 +445,7 @@ ======================================================================*/ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, - char *name) + char *name, socket_info_t *s) { ioaddr_t try; resource_map_t *m; @@ -378,9 +455,8 @@ for (try = (try >= m->base) ? try : try+align; (try >= m->base) && (try+num <= m->base+m->num); try += align) { - if (check_io_resource(try, num) == 0) { + if (request_io_resource(try, num, name, s->cap.cb_dev) == 0) { *base = try; - request_region(try, num, name); return 0; } if (!align) break; @@ -390,7 +466,7 @@ } int find_mem_region(u_long *base, u_long num, u_long align, - int force_low, char *name) + int force_low, char *name, socket_info_t *s) { u_long try; resource_map_t *m; @@ -403,8 +479,7 @@ for (try = (try >= m->base) ? try : try+align; (try >= m->base) && (try+num <= m->base+m->num); try += align) { - if (check_mem_resource(try, num) == 0) { - request_mem_region(try, num, name); + if (request_mem_resource(try, num, name, s->cap.cb_dev) == 0) { *base = try; return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pcmcia/ti113x.h linux-2.5/drivers/pcmcia/ti113x.h --- linux-2.5.5/drivers/pcmcia/ti113x.h Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/pcmcia/ti113x.h Sun Mar 3 17:54:35 2002 @@ -170,9 +170,88 @@ return 0; } +/* + * Zoom video control for TI122x/113x chips + */ + +static void ti_zoom_video(pci_socket_t *socket, int onoff) +{ + u8 reg; + + /* If we don't have a Zoom Video switch this is harmless, + we just tristate the unused (ZV) lines */ + reg = config_readb(socket, TI113X_CARD_CONTROL); + if (onoff) + /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */ + reg |= TI113X_CCR_ZVENABLE; + else + reg &= ~TI113X_CCR_ZVENABLE; + config_writeb(socket, TI113X_CARD_CONTROL, reg); +} + +/* + * The 145x series can also use this. They have an additional + * ZV autodetect mode we don't use but don't actually need. + * FIXME: manual says its in func0 and func1 but disagrees with + * itself about this - do we need to force func0, if so we need + * to know a lot more about socket pairings in pci_socket than we + * do now.. uggh. + */ + +static void ti1250_zoom_video(pci_socket_t *socket, int onoff) +{ + int shift = 0; + u8 reg; + + ti_zoom_video(socket, onoff); + + reg = config_readb(socket, 0x84); + reg |= (1<<7); /* ZV bus enable */ + + if(PCI_FUNC(socket->dev->devfn)==1) + shift = 1; + + if(onoff) + { + reg &= ~(1<<6); /* Clear select bit */ + reg |= shift<<6; /* Favour our socket */ + reg |= 1<dev->vendor == PCI_VENDOR_ID_TI) + { + switch(socket->dev->device) + { + /* There may be more .. */ + case PCI_DEVICE_ID_TI_1220: + case PCI_DEVICE_ID_TI_1221: + case PCI_DEVICE_ID_TI_1225: + socket->zoom_video = ti_zoom_video; + break; + case PCI_DEVICE_ID_TI_1250: + case PCI_DEVICE_ID_TI_1251A: + case PCI_DEVICE_ID_TI_1251B: + case PCI_DEVICE_ID_TI_1450: + socket->zoom_video = ti1250_zoom_video; + } + } +} + static int ti_init(pci_socket_t *socket) { yenta_init(socket); + ti_set_zv(socket); ti_intctl(socket); return 0; } @@ -251,7 +330,7 @@ static int ti1250_init(pci_socket_t *socket) { yenta_init(socket); - + ti_set_zv(socket); config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket)); ti_intctl(socket); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pcmcia/yenta.c linux-2.5/drivers/pcmcia/yenta.c --- linux-2.5.5/drivers/pcmcia/yenta.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/pcmcia/yenta.c Mon Feb 4 16:35:16 2002 @@ -234,6 +234,8 @@ static int yenta_set_socket(pci_socket_t *socket, socket_state_t *state) { + /* hack for the moment */ + static void yenta_set_zoomvideo(pci_socket_t *s, int onoff); u16 bridge; if (state->flags & SS_DEBOUNCED) { @@ -286,6 +288,8 @@ } exca_writeb(socket, I365_CSCINT, reg); exca_readb(socket, I365_CSC); + + yenta_set_zoomvideo(socket, state->flags & SS_ZVCARD); } config_writew(socket, CB_BRIDGE_CONTROL, bridge); /* Socket event mask: get card insert/remove events.. */ @@ -688,7 +692,7 @@ /* * This does not work currently. The controller - * loses too much informationduring D3 to come up + * loses too much information during D3 to come up * cleanly. We should probably fix yenta_init() * to update all the critical registers, notably * the IO and MEM bridging region data.. That is @@ -783,6 +787,29 @@ #include "ti113x.h" #include "ricoh.h" + +/* + * This belongs somewhere else - maybe as a pci socket op - as + * it is only valid for TI devices + */ + +static void yenta_set_zoomvideo(pci_socket_t *socket, int onoff) +{ + u8 reg; + + if(socket->dev->vendor != PCI_VENDOR_ID_TI) + return; + + /* If we don't have a Zoom Video switch this is harmless, + we just tristate the unused (ZV) lines */ + reg = config_readb(socket, TI113X_CARD_CONTROL); + if (onoff) + /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */ + reg |= TI113X_CCR_ZVENABLE; + else + reg &= ~TI113X_CCR_ZVENABLE; + config_writeb(socket, TI113X_CARD_CONTROL, reg); +} /* * Different cardbus controllers have slightly different diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pnp/isapnp.c linux-2.5/drivers/pnp/isapnp.c --- linux-2.5.5/drivers/pnp/isapnp.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/pnp/isapnp.c Thu Feb 14 00:47:46 2002 @@ -21,7 +21,7 @@ * 2000-01-01 Added quirks handling for buggy hardware * Peter Denison * 2000-06-14 Added isapnp_probe_devs() and isapnp_activate_dev() - * Christoph Hellwig + * Christoph Hellwig * 2001-06-03 Added release_region calls to correspond with * request_region calls when a failure occurs. Also * added KERN_* constants to printk() calls. @@ -56,10 +56,6 @@ #define ISAPNP_DEBUG #endif -struct resource *pidxr_res; -struct resource *pnpwrp_res; -struct resource *isapnp_rdp_res; - int isapnp_disable; /* Disable ISA PnP */ int isapnp_rdp; /* Read Data Port */ int isapnp_reset = 1; /* reset all PnP cards (deactivate) */ @@ -2147,13 +2143,10 @@ static void isapnp_free_all_resources(void) { #ifdef ISAPNP_REGION_OK - if (pidxr_res) - release_resource(pidxr_res); + release_region(_PIDXR, 1); #endif - if (pnpwrp_res) - release_resource(pnpwrp_res); - if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff && isapnp_rdp_res) - release_resource(isapnp_rdp_res); + release_region(_PNPWRP, 1); + release_region(isapnp_rdp, 1); #ifdef MODULE #ifdef CONFIG_PROC_FS isapnp_proc_done(); @@ -2284,14 +2277,12 @@ return 0; } #ifdef ISAPNP_REGION_OK - pidxr_res=request_region(_PIDXR, 1, "isapnp index"); - if(!pidxr_res) { + if (!request_region(_PIDXR, 1, "isapnp index")) { printk(KERN_ERR "isapnp: Index Register 0x%x already used\n", _PIDXR); return -EBUSY; } #endif - pnpwrp_res=request_region(_PNPWRP, 1, "isapnp write"); - if(!pnpwrp_res) { + if (!request_region(_PNPWRP, 1, "isapnp write")) { printk(KERN_ERR "isapnp: Write Data Register 0x%x already used\n", _PNPWRP); #ifdef ISAPNP_REGION_OK release_region(_PIDXR, 1); @@ -2307,13 +2298,12 @@ printk(KERN_INFO "isapnp: Scanning for PnP cards...\n"); if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) { isapnp_rdp |= 3; - isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read"); - if(!isapnp_rdp_res) { + if (!request_region(isapnp_rdp, 1, "isapnp read")) { printk(KERN_ERR "isapnp: Read Data Register 0x%x already used\n", isapnp_rdp); #ifdef ISAPNP_REGION_OK release_region(_PIDXR, 1); #endif - release_region(isapnp_rdp, 1); + release_region(_PNPWRP, 1); return -EBUSY; } isapnp_set_rdp(); @@ -2323,12 +2313,15 @@ cards = isapnp_isolate(); if (cards < 0 || (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) { - isapnp_free_all_resources(); +#ifdef ISAPNP_REGION_OK + release_region(_PIDXR, 1); +#endif + release_region(_PNPWRP, 1); isapnp_detected = 0; printk(KERN_INFO "isapnp: No Plug & Play device found\n"); return 0; } - isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read"); + request_region(isapnp_rdp, 1, "isapnp read"); } isapnp_build_device_list(); cards = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pnp/pnpbios_core.c linux-2.5/drivers/pnp/pnpbios_core.c --- linux-2.5.5/drivers/pnp/pnpbios_core.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/pnp/pnpbios_core.c Sun Feb 10 20:53:58 2002 @@ -190,8 +190,8 @@ /* If we get here and this is set then the PnP BIOS faulted on us. */ if(pnp_bios_is_utter_crap) { - printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue.\n"); - printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"nobiospnp\" option to operate stably.\n"); + printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue\n"); + printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"nobiospnp\" option to operate stably\n"); printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n"); } @@ -209,7 +209,7 @@ { void *p = kmalloc( size, f ); if ( p == NULL ) - printk(KERN_ERR "PnPBIOS: kmalloc() failed.\n"); + printk(KERN_ERR "PnPBIOS: kmalloc() failed\n"); return p; } @@ -299,7 +299,7 @@ int status; status = __pnp_bios_get_dev_node( nodenum, boot, data ); if ( status ) - printk(KERN_WARNING "PnPBIOS: get_dev_node: Unexpected 0x%x\n", status); + printk(KERN_WARNING "PnPBIOS: get_dev_node: Unexpected status 0x%x\n", status); return status; } @@ -327,17 +327,14 @@ int status; status = __pnp_bios_set_dev_node( nodenum, boot, data ); if ( status ) { - printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected set_dev_node status 0x%x\n", status); + printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected status 0x%x\n", status); return status; } - if ( !boot ) { - /* Update devlist */ + if ( !boot ) { /* Update devlist */ u8 thisnodenum = nodenum; - status = __pnp_bios_get_dev_node( &nodenum, boot, data ); - if ( status ) { - printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected get_dev_node status 0x%x\n", status); + status = pnp_bios_get_dev_node( &nodenum, boot, data ); + if ( status ) return status; - } update_devlist( thisnodenum, data ); } return status; @@ -403,12 +400,11 @@ } #endif -#if needed /* * Call PnP BIOS with function 0x0a, "get statically allocated resource * information" */ -static int pnp_bios_get_stat_res(char *info) +static int __pnp_bios_get_stat_res(char *info) { u16 status; if (!pnp_bios_present ()) @@ -417,7 +413,15 @@ status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0); return status; } -#endif + +int pnp_bios_get_stat_res(char *info) +{ + int status; + status = __pnp_bios_get_stat_res( info ); + if ( status ) + printk(KERN_WARNING "PnPBIOS: get_stat_res: Unexpected status 0x%x\n", status); + return status; +} #if needed /* @@ -435,11 +439,10 @@ } #endif -#if needed /* * Call PnP BIOS with function 0x40, "get isa pnp configuration structure" */ -static int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data) +static int __pnp_bios_isapnp_config(struct pnp_isa_config_struc *data) { u16 status; if (!pnp_bios_present ()) @@ -448,13 +451,20 @@ status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0); return status; } -#endif -#if needed +int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data) +{ + int status; + status = __pnp_bios_isapnp_config( data ); + if ( status ) + printk(KERN_WARNING "PnPBIOS: isapnp_config: Unexpected status 0x%x\n", status); + return status; +} + /* * Call PnP BIOS with function 0x41, "get ESCD info" */ -static int pnp_bios_escd_info(struct escd_info_struc *data) +static int __pnp_bios_escd_info(struct escd_info_struc *data) { u16 status; if (!pnp_bios_present ()) @@ -463,14 +473,21 @@ status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS); return status; } -#endif -#if needed +int pnp_bios_escd_info(struct escd_info_struc *data) +{ + int status; + status = __pnp_bios_escd_info( data ); + if ( status ) + printk(KERN_WARNING "PnPBIOS: escd_info: Unexpected status 0x%x\n", status); + return status; +} + /* * Call PnP BIOS function 0x42, "read ESCD" * nvram_base is determined by calling escd_info */ -static int pnp_bios_read_escd(char *data, u32 nvram_base) +static int __pnp_bios_read_escd(char *data, u32 nvram_base) { u16 status; if (!pnp_bios_present ()) @@ -481,7 +498,15 @@ status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0); return status; } -#endif + +int pnp_bios_read_escd(char *data, u32 nvram_base) +{ + int status; + status = __pnp_bios_read_escd( data, nvram_base ); + if ( status ) + printk(KERN_ERR "PnPBIOS: read_escd: Unexpected status 0x%x\n", status); + return status; +} #if needed /* @@ -574,7 +599,7 @@ static int pnp_dock_thread(void * unused) { static struct pnp_docking_station_info now; - int docked = -1, d; + int docked = -1, d = 0; daemonize(); reparent_to_init(); strcpy(current->comm, "kpnpbios"); @@ -606,7 +631,7 @@ d = 1; break; default: - printk(KERN_WARNING "PnPBIOS: pnp_dock_thread: Unexpected status 0x%x returned by BIOS.\n", err); + printk(KERN_WARNING "PnPBIOS: pnp_dock_thread: Unexpected status 0x%x\n", err); continue; } if(d != docked) @@ -615,7 +640,7 @@ { docked = d; #if 0 - printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de"); + printk(KERN_INFO "PnPBIOS: Docking station %stached\n", docked?"at":"de"); #endif } } @@ -848,8 +873,7 @@ */ static void __init build_devlist(void) { - int i; - int nodenum; + u8 nodenum; int nodes_got = 0; int devs = 0; struct pnp_bios_node *node; @@ -866,26 +890,20 @@ if (!node) return; - for(i=0,nodenum=0; i<0xff && nodenum!=0xff; i++) { - int thisnodenum = nodenum; - /* For now we build the list from the "boot" config - * because asking for the "current" config causes - * some BIOSes to crash. */ - if (pnp_bios_get_dev_node((u8 *)&nodenum, (char )1 , node)) { - printk(KERN_WARNING "PnPBIOS: PnP BIOS reported error on attempt to get dev node.\n"); - break; - } - /* The BIOS returns with nodenum = the next node number */ - if (nodenum < thisnodenum) { - printk(KERN_WARNING "PnPBIOS: Node number is out of sequence. Naughty BIOS!\n"); + for(nodenum=0; nodenum<0xff; ) { + u8 thisnodenum = nodenum; + /* We build the list from the "boot" config because + * asking for the "current" config causes some + * BIOSes to crash. + */ + if (pnp_bios_get_dev_node(&nodenum, (char )1 , node)) break; - } nodes_got++; dev = pnpbios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL); if (!dev) break; memset(dev,0,sizeof(struct pci_dev)); - dev->devfn=thisnodenum; + dev->devfn = thisnodenum; memcpy(dev->name,"PNPBIOS",8); pnpid32_to_pnpid(node->eisa_id,dev->slot_name); node_resource_data_to_dev(node,dev); @@ -893,10 +911,14 @@ kfree(dev); else devs++; + if (nodenum <= thisnodenum) { + printk(KERN_ERR "PnPBIOS: build_devlist(): Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", (int)nodenum, (int)thisnodenum); + break; + } } kfree(node); - printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver.\n", + printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver\n", nodes_got, nodes_got != 1 ? "s" : "", devs); } @@ -1062,7 +1084,7 @@ regionid = pnpbios_kmalloc(16, GFP_KERNEL); if ( regionid == NULL ) return; - sprintf(regionid, "PnPBIOS %s", pnpid); + snprintf(regionid, 16, "PnPBIOS %s", pnpid); res = request_region(start,end-start+1,regionid); if ( res == NULL ) kfree( regionid ); @@ -1074,7 +1096,7 @@ * have double reservations. */ printk(KERN_INFO - "PnPBIOS: %s: ioport range 0x%x-0x%x %s reserved.\n", + "PnPBIOS: %s: ioport range 0x%x-0x%x %s reserved\n", pnpid, start, end, NULL != res ? "has been" : "could not be" ); @@ -1199,7 +1221,7 @@ spin_lock_init(&pnpbios_devices_lock); if(pnpbios_disabled) { - printk(KERN_INFO "PnPBIOS: Disabled.\n"); + printk(KERN_INFO "PnPBIOS: Disabled\n"); return; } @@ -1224,13 +1246,13 @@ if (sum) continue; if (check->fields.version < 0x10) { - printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported.\n", + printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported\n", check->fields.version >> 4, check->fields.version & 15); continue; } - printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p.\n", check); - printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x.\n", + printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p\n", check); + printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x\n", check->fields.version >> 4, check->fields.version & 15, check->fields.pm16cseg, check->fields.pm16offset, check->fields.pm16dseg); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pnp/pnpbios_proc.c linux-2.5/drivers/pnp/pnpbios_proc.c --- linux-2.5.5/drivers/pnp/pnpbios_proc.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/pnp/pnpbios_proc.c Sun Feb 10 20:53:33 2002 @@ -1,7 +1,8 @@ /* - * pnp_proc.c: /proc/bus/pnp interface for Plug and Play devices + * /proc/bus/pnp interface for Plug and Play devices * * Written by David Hinds, dahinds@users.sourceforge.net + * Modified by Thomas Hood, jdthood_AT_mail.com */ //#include @@ -19,30 +20,118 @@ static struct proc_dir_entry *proc_pnp_boot = NULL; static struct pnp_dev_node_info node_info; +static int proc_read_pnpconfig(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + struct pnp_isa_config_struc pnps; + + if (pnp_bios_isapnp_config(&pnps)) + return -EIO; + return snprintf(buf, count, + "structure_revision %d\n" + "number_of_CSNs %d\n" + "ISA_read_data_port 0x%x\n", + pnps.revision, + pnps.no_csns, + pnps.isa_rd_data_port + ); +} + +static int proc_read_escdinfo(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + struct escd_info_struc escd; + + if (pnp_bios_escd_info(&escd)) + return -EIO; + return snprintf(buf, count, + "min_ESCD_write_size %d\n" + "ESCD_size %d\n" + "NVRAM_base 0x%x\n", + escd.min_escd_write_size, + escd.escd_size, + escd.nv_storage_base + ); +} + +static int proc_read_escd(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + struct escd_info_struc escd; + char *tmpbuf; + int escd_size, escd_left_to_read, n; + + if (pnp_bios_escd_info(&escd)) + return -EIO; + + /* sanity check */ + if (escd.escd_size > (32*1024)) { + printk(KERN_ERR "PnPBIOS: Error: ESCD size is too great\n"); + return -EFBIG; + } + + tmpbuf = pnpbios_kmalloc(escd.escd_size, GFP_KERNEL); + if (!tmpbuf) return -ENOMEM; + + if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) + return -EIO; + + escd_size = (unsigned char)(buf[0]) + (unsigned char)(buf[1])*256; + escd_left_to_read = escd_size - pos; + if (escd_left_to_read < 0) escd_left_to_read = 0; + if (escd_left_to_read == 0) *eof = 1; + n = min(count,escd_left_to_read); + memcpy(buf, tmpbuf + pos, n); + kfree(tmpbuf); + *start = buf; + return n; +} + +static int proc_read_legacyres(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + /* Assume that the following won't overflow the buffer */ + if (pnp_bios_get_stat_res(buf)) + return -EIO; + + return count; // FIXME: Return actual length +} + static int proc_read_devices(char *buf, char **start, off_t pos, int count, int *eof, void *data) { struct pnp_bios_node *node; - int i; u8 nodenum; char *p = buf; - if (pos != 0) { - *eof = 1; - return 0; - } + if (pos >= 0xff) + return 0; + node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -ENOMEM; - for (i=0,nodenum=0;i<0xff && nodenum!=0xff; i++) { - if ( pnp_bios_get_dev_node(&nodenum, 1, node) ) + + for (nodenum=pos; nodenum<0xff; ) { + u8 thisnodenum = nodenum; + /* 26 = the number of characters per line sprintf'ed */ + if ((p - buf + 26) > count) + break; + if (pnp_bios_get_dev_node(&nodenum, 1, node)) break; p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n", node->handle, node->eisa_id, node->type_code[0], node->type_code[1], node->type_code[2], node->flags); + if (nodenum <= thisnodenum) { + printk(KERN_ERR "PnPBIOS: proc_read_devices(): Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", (int)nodenum, (int)thisnodenum); + *eof = 1; + break; + } } kfree(node); - return (p-buf); + if (nodenum == 0xff) + *eof = 1; + *start = (char *)((off_t)nodenum - pos); + return p - buf; } static int proc_read_node(char *buf, char **start, off_t pos, @@ -53,13 +142,9 @@ u8 nodenum = (long)data; int len; - if (pos != 0) { - *eof = 1; - return 0; - } node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -ENOMEM; - if ( pnp_bios_get_dev_node(&nodenum, boot, node) ) + if (pnp_bios_get_dev_node(&nodenum, boot, node)) return -EIO; len = node->size - sizeof(struct pnp_bios_node); memcpy(buf, node->data, len); @@ -107,6 +192,10 @@ proc_pnp_boot = proc_mkdir("boot", proc_pnp); if (!proc_pnp_boot) return; create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL); + create_proc_read_entry("configuration_info", 0, proc_pnp, proc_read_pnpconfig, NULL); + create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, NULL); + create_proc_read_entry("escd", 0, proc_pnp, proc_read_escd, NULL); + create_proc_read_entry("legacy_device_resources", 0, proc_pnp, proc_read_legacyres, NULL); node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return; @@ -145,7 +234,11 @@ remove_proc_entry(name, proc_pnp); remove_proc_entry(name, proc_pnp_boot); } - remove_proc_entry("boot", proc_pnp); + remove_proc_entry("legacy_device_resources", proc_pnp); + remove_proc_entry("escd", proc_pnp); + remove_proc_entry("escd_info", proc_pnp); + remove_proc_entry("configuration_info", proc_pnp); remove_proc_entry("devices", proc_pnp); + remove_proc_entry("boot", proc_pnp); remove_proc_entry("pnp", proc_bus); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/pnp/quirks.c linux-2.5/drivers/pnp/quirks.c --- linux-2.5.5/drivers/pnp/quirks.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/pnp/quirks.c Tue Feb 19 15:46:36 2002 @@ -18,6 +18,10 @@ #include #include +#if 0 +#define ISAPNP_DEBUG +#endif + static void __init quirk_awe32_resources(struct pci_dev *dev) { struct isapnp_port *port, *port2, *port3; @@ -139,8 +143,10 @@ while (isapnp_fixups[i].vendor != 0) { if ((isapnp_fixups[i].vendor == dev->vendor) && (isapnp_fixups[i].device == dev->device)) { +#ifdef ISAPNP_DEBUG printk(KERN_DEBUG "isapnp: Calling quirk for %02x:%02x\n", dev->bus->number, dev->devfn); +#endif isapnp_fixups[i].quirk_function(dev); } i++; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/s390/block/dasd_int.h linux-2.5/drivers/s390/block/dasd_int.h --- linux-2.5.5/drivers/s390/block/dasd_int.h Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/s390/block/dasd_int.h Sun Mar 3 17:54:35 2002 @@ -201,14 +201,14 @@ debug_sprintf_event(d_device->debug_area,d_level,\ DASD_DEVICE_FORMAT_STRING d_str "\n",\ d_device, d_data);\ -} while(0); +} while(0) #define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\ do {\ if ( d_device->debug_area != NULL )\ debug_sprintf_exception(d_device->debug_area,d_level,\ DASD_DEVICE_FORMAT_STRING d_str "\n",\ d_device, d_data);\ -} while(0); +} while(0) #define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>" #define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\ @@ -217,14 +217,14 @@ debug_sprintf_event(dasd_debug_area, d_level,\ DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ d_fn, d_data);\ -} while(0); +} while(0) #define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\ do {\ if ( dasd_debug_area != NULL )\ debug_sprintf_exception(dasd_debug_area, d_level,\ DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\ d_fn, d_data);\ -} while(0); +} while(0) struct dasd_device_t; struct request; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/s390/block/xpram.c linux-2.5/drivers/s390/block/xpram.c --- linux-2.5.5/drivers/s390/block/xpram.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/s390/block/xpram.c Fri Mar 1 15:07:38 2002 @@ -654,7 +654,7 @@ (u64 *) arg); case BLKFLSBUF: /* flush, 0x1261 */ - fsync_dev(inode->i_rdev); + fsync_bdev(inode->i_bdev); if ( capable(CAP_SYS_ADMIN) )invalidate_buffers(inode->i_rdev); return 0; @@ -1191,10 +1191,7 @@ { int i; - /* first of all, flush it all and reset all the data structures */ - - for (i=0; isch.irq)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/sbus/char/aurora.c linux-2.5/drivers/sbus/char/aurora.c --- linux-2.5.5/drivers/sbus/char/aurora.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/sbus/char/aurora.c Mon Feb 4 22:15:16 2002 @@ -179,7 +179,7 @@ #ifdef AURORA_DEBUG printk("aurora_long_delay: start\n"); #endif - for (i = jiffies + delay; i > jiffies; ) ; + for (i = jiffies + delay; time_before(jiffies, i); ) ; #ifdef AURORA_DEBUG printk("aurora_long_delay: end\n"); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/sbus/char/jsflash.c linux-2.5/drivers/sbus/char/jsflash.c --- linux-2.5.5/drivers/sbus/char/jsflash.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/sbus/char/jsflash.c Fri Feb 8 02:38:26 2002 @@ -43,11 +43,8 @@ #define MAJOR_NR JSFD_MAJOR #define DEVICE_NAME "jsfd" -#define DEVICE_REQUEST jsfd_do_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) -#define DEVICE_NO_RANDOM +#define LOCAL_END_REQUEST #include @@ -199,6 +196,14 @@ } } +static inline void jfsd_end_request(struct request *req, int uptodate) +{ + if (!end_that_request_first(req, uptodate, req->hard_cur_sectors)) { + blkdev_dequeue_request(req); + end_that_request_last(req); + } +} + static void jsfd_do_request(request_queue_t *q) { struct request *req; @@ -206,6 +211,7 @@ struct jsfd_part *jdp; unsigned long offset; size_t len; + int uptodate; for (;;) { INIT_REQUEST; /* if (QUEUE_EMPTY) return; */ @@ -213,7 +219,7 @@ dev = MINOR(req->rq_dev); if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { - end_request(0); + jfsd_end_request(req, 0); continue; } jdp = &jsf0.dv[dev & JSF_PART_MASK]; @@ -221,31 +227,31 @@ offset = req->sector << 9; len = req->current_nr_sectors << 9; if ((offset + len) > jdp->dsize) { - end_request(0); + jfsd_end_request(req, 0); continue; } if (req->cmd == WRITE) { printk(KERN_ERR "jsfd: write\n"); - end_request(0); + jfsd_end_request(req, 0); continue; } if (req->cmd != READ) { printk(KERN_ERR "jsfd: bad req->cmd %d\n", req->cmd); - end_request(0); + jfsd_end_request(req, 0); continue; } if ((jdp->dbase & 0xff000000) != 0x20000000) { printk(KERN_ERR "jsfd: bad base %x\n", (int)jdp->dbase); - end_request(0); + jfsd_end_request(req, 0); continue; } /* printk("jsfd%d: read buf %p off %x len %x\n", dev, req->buffer, (int)offset, (int)len); */ /* P3 */ jsfd_read(req->buffer, jdp->dbase + offset, len); - end_request(1); + jfsd_end_request(req, 1); } } @@ -668,7 +674,7 @@ blksize_size[JSFD_MAJOR] = jsfd_blksizes; blk_size[JSFD_MAJOR] = jsfd_sizes; - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), jsfd_do_request); for (i = 0; i < JSF_MAX; i++) { if ((i & JSF_PART_MASK) >= JSF_NPART) continue; jsf = &jsf0; /* actually, &jsfv[i >> JSF_PART_BITS] */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/sbus/char/riowatchdog.c linux-2.5/drivers/sbus/char/riowatchdog.c --- linux-2.5.5/drivers/sbus/char/riowatchdog.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/sbus/char/riowatchdog.c Thu Jan 24 19:36:18 2002 @@ -1,4 +1,4 @@ -/* $Id: riowatchdog.c,v 1.3 2001/10/08 22:19:51 davem Exp $ +/* $Id: riowatchdog.c,v 1.3.2.2 2002/01/23 18:48:02 davem Exp $ * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO * * Copyright (C) 2001 David S. Miller (davem@redhat.com) @@ -127,8 +127,11 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - static struct watchdog_info info = { 0, 0, "Natl. Semiconductor PC97317" }; + static struct watchdog_info info = { + WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317" + }; unsigned int options; + int new_margin; switch (cmd) { case WDIOC_GETSUPPORT: @@ -158,6 +161,18 @@ return -EINVAL; break; + + case WDIOC_SETTIMEOUT: + if (get_user(new_margin, (int *)arg)) + return -EFAULT; + if ((new_margin < 60) || (new_margin > (255 * 60))) + return -EINVAL; + riowd_timeout = (new_margin + 59) / 60; + riowd_pingtimer(); + /* Fall */ + + case WDIOC_GETTIMEOUT: + return put_user(riowd_timeout * 60, (int *)arg); default: return -EINVAL; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/sbus/char/sab82532.c linux-2.5/drivers/sbus/char/sab82532.c --- linux-2.5.5/drivers/sbus/char/sab82532.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/sbus/char/sab82532.c Tue Jan 15 12:22:32 2002 @@ -2251,7 +2251,9 @@ serial_driver.table = sab82532_table; serial_driver.termios = sab82532_termios; serial_driver.termios_locked = sab82532_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sab82532_console; +#endif serial_driver.open = sab82532_open; serial_driver.close = sab82532_close; serial_driver.write = sab82532_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/sbus/char/su.c linux-2.5/drivers/sbus/char/su.c --- linux-2.5.5/drivers/sbus/char/su.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/sbus/char/su.c Tue Jan 15 12:22:32 2002 @@ -2506,7 +2506,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = su_open; serial_driver.close = su_close; serial_driver.write = su_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/sbus/char/sunkbd.c linux-2.5/drivers/sbus/char/sunkbd.c --- linux-2.5.5/drivers/sbus/char/sunkbd.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/sbus/char/sunkbd.c Sun Mar 3 23:50:42 2002 @@ -504,7 +504,7 @@ } do_poke_blanked_console = 1; - schedule_console_callback(); + schedule_task(&vt_cons->vt_tq); add_keyboard_randomness(keycode); tty = ttytab? ttytab[fg_console]: NULL; @@ -544,7 +544,7 @@ #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq hack */ if (l1a_state.l1_down) { if (!up_flag) - handle_sysrq(sun_sysrq_xlate[keycode], pt_regs, kbd, tty); + handle_sysrq(sun_sysrq_xlate[keycode], pt_regs, tty); goto out; } #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/sbus/char/zs.c linux-2.5/drivers/sbus/char/zs.c --- linux-2.5.5/drivers/sbus/char/zs.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/sbus/char/zs.c Wed Jan 16 00:23:26 2002 @@ -2460,7 +2460,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &zs_console; +#endif serial_driver.open = zs_open; serial_driver.close = zs_close; serial_driver.write = zs_write; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/3w-xxxx.c linux-2.5/drivers/scsi/3w-xxxx.c --- linux-2.5.5/drivers/scsi/3w-xxxx.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/scsi/3w-xxxx.c Fri Feb 8 03:15:29 2002 @@ -6,7 +6,7 @@ Arnaldo Carvalho de Melo Brad Strand - Copyright (C) 1999-2001 3ware Inc. + Copyright (C) 1999-2002 3ware Inc. Kernel compatablity By: Andre Hedrick Non-Copyright (C) 2000 Andre Hedrick @@ -106,6 +106,21 @@ Add entire aen code string list. 1.02.00.010 - Cleanup queueing code, fix jbod thoughput. Fix get_param for specific units. + 1.02.00.011 - Fix bug in tw_aen_complete() where aen's could be lost. + Fix tw_aen_drain_queue() to display useful info at init. + Set tw_host->max_id for 12 port cards. + Add ioctl support for raw command packet post from userspace + with sglist fragments (parameter and io). + 1.02.00.012 - Fix read capacity to under report by 1 sector to fix get + last sector ioctl. + 1.02.00.013 - Fix bug where more AEN codes weren't coming out during + driver initialization. + Improved handling of PCI aborts. + 1.02.00.014 - Fix bug in tw_findcards() where AEN code could be lost. + Increase timeout in tw_aen_drain_queue() to 30 seconds. + 1.02.00.015 - Re-write raw command post with data ioctl method. + 1.02.00.016 - Set max_cmd_len for 3dm. + Set max sectors to 256 for non raid5 & 6XXX. */ #error Please convert me to Documentation/DMA-mapping.txt @@ -116,7 +131,6 @@ MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver"); MODULE_LICENSE("GPL"); - #include #include #include @@ -151,11 +165,11 @@ /* Notifier block to get a notify on system shutdown/halt/reboot */ static struct notifier_block tw_notifier = { - tw_halt, NULL, 0 + tw_halt, NULL, 0 }; /* Globals */ -char *tw_driver_version="1.02.00.010"; +char *tw_driver_version="1.02.00.016"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; @@ -166,6 +180,7 @@ { TW_Param *param; unsigned short aen; + int error = 0; dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n"); if (tw_dev->alignment_virtual_address[request_id] == NULL) { @@ -184,12 +199,15 @@ if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') { printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8); } else { - printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]); + if (aen != 0x0) + printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]); } - } else + } else { printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen); + } } - tw_dev->aen_count++; + if (aen != 0x0) + tw_dev->aen_count++; /* Now queue the code */ tw_dev->aen_queue[tw_dev->aen_tail] = aen; @@ -205,8 +223,18 @@ tw_dev->aen_head = tw_dev->aen_head + 1; } } - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); + + if (aen != TW_AEN_QUEUE_EMPTY) { + error = tw_aen_read_queue(tw_dev, request_id); + if (error) { + printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no); + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + } + } else { + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + } return 0; } /* End tw_aen_complete() */ @@ -237,10 +265,11 @@ status_reg_addr = tw_dev->registers.status_reg_addr; response_que_addr = tw_dev->registers.response_que_addr; - if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 15)) { + if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 30)) { dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count); return 1; } + tw_clear_attention_interrupt(tw_dev); /* Initialize command packet */ if (tw_dev->command_packet_virtual_address[request_id] == NULL) { @@ -288,7 +317,7 @@ do { /* Post command packet */ outl(command_que_value, command_que_addr); - + /* Now poll for completion */ for (i=0;iaen_count++; queue = 1; } break; - case TW_AEN_DEGRADED_MIRROR: - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_DEGRADED_MIRROR.\n"); - queue = 1; - break; - case TW_AEN_CONTROLLER_ERROR: - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_CONTROLLER_ERROR.\n"); - queue = 1; - break; - case TW_AEN_REBUILD_FAIL: - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_FAIL.\n"); - queue = 1; - break; - case TW_AEN_REBUILD_DONE: - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_DONE.\n"); - queue = 1; - break; - case TW_AEN_QUEUE_FULL: - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_FULL.\n"); - queue = 1; - break; - case TW_AEN_APORT_TIMEOUT: - printk(KERN_WARNING "3w-xxxx: Received drive timeout AEN on port %d, check drive and drive cables.\n", aen >> 8); - queue = 1; - break; - case TW_AEN_DRIVE_ERROR: - printk(KERN_WARNING "3w-xxxx: Received drive error AEN on port %d, check/replace cabling, or possible bad drive.\n", aen >> 8); - queue = 1; - break; - case TW_AEN_SMART_FAIL: - printk(KERN_WARNING "3w-xxxx: Received S.M.A.R.T. threshold AEN on port %d, check drive/cooling, or possible bad drive.\n", aen >> 8); - queue = 1; - break; - case TW_AEN_SBUF_FAIL: - printk(KERN_WARNING "3w-xxxx: Received SBUF integrity check failure AEN, reseat card or bad card.\n"); - queue = 1; - break; default: - dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unknown AEN code 0x%x.\n", aen_code); + if (aen == 0x0ff) { + printk(KERN_WARNING "3w-xxxx: AEN: AEN queue overflow.\n"); + } else { + if ((aen & 0x0ff) < TW_AEN_STRING_MAX) { + if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') { + printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8); + } else { + printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]); + } + } else + printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen); + } + tw_dev->aen_count++; queue = 1; } @@ -608,7 +614,7 @@ } } /* End tw_copy_mem_info() */ -/* This function will print readable messages from statsu register errors */ +/* This function will print readable messages from status register errors */ void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value) { dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n"); @@ -621,6 +627,11 @@ case TW_STATUS_MICROCONTROLLER_ERROR: printk(KERN_WARNING "3w-xxxx: Microcontroller Error.\n"); break; + case TW_STATUS_PCI_ABORT: + printk(KERN_WARNING "3w-xxxx: PCI Abort: clearing.\n"); + outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr); + pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT); + break; } } /* End tw_decode_bits() */ @@ -691,11 +702,22 @@ u32 control_reg_value, control_reg_addr; control_reg_addr = tw_dev->registers.control_reg_addr; + control_reg_value = (TW_CONTROL_ENABLE_INTERRUPTS | + TW_CONTROL_UNMASK_RESPONSE_INTERRUPT); + outl(control_reg_value, control_reg_addr); +} /* End tw_enable_interrupts() */ + +/* This function will enable interrupts on the controller */ +void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev) +{ + u32 control_reg_value, control_reg_addr; + + control_reg_addr = tw_dev->registers.control_reg_addr; control_reg_value = (TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | TW_CONTROL_UNMASK_RESPONSE_INTERRUPT | TW_CONTROL_ENABLE_INTERRUPTS); outl(control_reg_value, control_reg_addr); -} /* End tw_enable_interrupts() */ +} /* End tw_enable_and_clear_interrupts() */ /* This function will find and initialize all cards */ int tw_findcards(Scsi_Host_Template *tw_host) @@ -763,14 +785,14 @@ error = tw_aen_drain_queue(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", numcards); tries++; continue; } /* Check for controller errors */ if (tw_check_errors(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: Controller errors found, retrying for card %d.\n", numcards); tries++; continue; } @@ -778,7 +800,7 @@ /* Empty the response queue */ error = tw_empty_response_que(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: Couldn't empty response queue, retrying for card %d.\n", numcards); tries++; continue; } @@ -788,7 +810,7 @@ } if (tries >= TW_MAX_RESET_TRIES) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", numcards); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; @@ -818,7 +840,7 @@ error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", numcards); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); kfree(tw_dev); @@ -843,16 +865,27 @@ /* Register the card with the kernel SCSI layer */ host = scsi_register(tw_host, sizeof(TW_Device_Extension)); if (host == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards-1); + printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; } + /* Set max target id's */ + host->max_id = TW_MAX_UNITS; + + /* Set max cdb size in bytes */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,15) + host->max_cmd_len = TW_MAX_CDB_LEN; +#endif + /* Set max sectors per io */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) - host->max_sectors = TW_MAX_SECTORS; + if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) + host->max_sectors = TW_MAX_BOUNCE_SECTORS; + else + host->max_sectors = TW_MAX_SECTORS; #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) @@ -874,7 +907,7 @@ tw_device_extension_count = numcards; tw_dev2->host = host; } else { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1); + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards); scsi_unregister(host); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); @@ -1054,6 +1087,7 @@ tw_dev->state[i] = TW_S_INITIAL; tw_dev->ioctl_size[i] = 0; tw_dev->aen_queue[i] = 0; + tw_dev->ioctl_data[i] = NULL; } for (i=0;itw_pci_dev->device == TW_DEVICE_ID)) { for (i=0;ibounce_buffer[i] == NULL) { printk(KERN_WARNING "3w-xxxx: Bounce buffer allocation failed.\n"); return 1; } - memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*TW_MAX_SECTORS); + memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS); } } @@ -1332,7 +1366,7 @@ if (tw_dev->tw_pci_dev->irq == irq) { spin_lock(&tw_dev->tw_lock); - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt()\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n"); /* Read the registers */ status_reg_addr = tw_dev->registers.status_reg_addr; @@ -1455,18 +1489,21 @@ tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); } - if (error) { + if (error == 1) { /* Tell scsi layer there was an error */ dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n"); tw_dev->srb[request_id]->result = (DID_RESET << 16); - } else { + } + if (error == 0) { /* Tell scsi layer command was a success */ tw_dev->srb[request_id]->result = (DID_OK << 16); } - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - tw_dev->posted_request_count--; - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); + if (error != 2) { + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + tw_dev->posted_request_count--; + tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); + } status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); @@ -1479,19 +1516,21 @@ } spin_unlock_irqrestore(tw_dev->host->host_lock, flags); clear_bit(TW_IN_INTR, &tw_dev->flags); -} /* End tw_interrupt() */ +} /* End tw_interrupt() */ /* This function handles ioctls from userspace to the driver */ int tw_ioctl(TW_Device_Extension *tw_dev, int request_id) { unsigned char opcode; - int bufflen; + int bufflen, error = 0; TW_Param *param; - TW_Command *command_packet; + TW_Command *command_packet, *command_save; u32 param_value; TW_Ioctl *ioctl = NULL; TW_Passthru *passthru = NULL; - int tw_aen_code; + int tw_aen_code, i, use_sg; + char *data_ptr; + int total_bytes = 0; ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer; if (ioctl == NULL) { @@ -1612,6 +1651,159 @@ printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n"); return 1; } + case TW_CMD_PACKET_WITH_DATA: + dprintk(KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n"); + command_save = (TW_Command *)tw_dev->alignment_virtual_address[request_id]; + if (command_save == NULL) { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad alignment virtual address.\n", tw_dev->host->host_no); + return 1; + } + if (ioctl->data != NULL) { + /* Copy down the command packet */ + memcpy(command_packet, ioctl->data, sizeof(TW_Command)); + memcpy(command_save, ioctl->data, sizeof(TW_Command)); + command_packet->request_id = request_id; + + /* Now deal with the two possible sglists */ + if (command_packet->byte0.sgl_offset == 2) { + use_sg = command_packet->size - 3; + for (i=0;ibyte8.param.sgl[i].length; + tw_dev->ioctl_data[request_id] = kmalloc(total_bytes, GFP_ATOMIC); + if (!tw_dev->ioctl_data[request_id]) { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id); + return 1; + } + + /* Copy param sglist into the kernel */ + data_ptr = tw_dev->ioctl_data[request_id]; + for (i=0;ibyte8.param.sgl[i].address != NULL) { + error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length); + if (error) { + printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n", tw_dev->host->host_no); + goto tw_ioctl_bail; + } + } else { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no); + tw_dev->srb[request_id]->result = (DID_RESET << 16); + goto tw_ioctl_bail; + } + data_ptr+=command_packet->byte8.param.sgl[i].length; + } + command_packet->size = 4; + command_packet->byte8.param.sgl[0].address = virt_to_bus(tw_dev->ioctl_data[request_id]); + command_packet->byte8.param.sgl[0].length = total_bytes; + } + if (command_packet->byte0.sgl_offset == 3) { + use_sg = command_packet->size - 4; + for (i=0;ibyte8.io.sgl[i].length; + tw_dev->ioctl_data[request_id] = kmalloc(total_bytes, GFP_ATOMIC); + if (!tw_dev->ioctl_data[request_id]) { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id); + return 1; + } + if (command_packet->byte0.opcode == TW_OP_WRITE) { + /* Copy io sglist into the kernel */ + data_ptr = tw_dev->ioctl_data[request_id]; + for (i=0;ibyte8.io.sgl[i].address != NULL) { + error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length); + if (error) { + printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n", tw_dev->host->host_no); + goto tw_ioctl_bail; + } + } else { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no); + tw_dev->srb[request_id]->result = (DID_RESET << 16); + goto tw_ioctl_bail; + } + data_ptr+=command_packet->byte8.io.sgl[i].length; + } + } + command_packet->size = 5; + command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->ioctl_data[request_id]); + command_packet->byte8.io.sgl[0].length = total_bytes; + } + + spin_unlock_irq(&io_request_lock); + spin_unlock_irq(&tw_dev->tw_lock); + + /* Finally post the command packet */ + tw_post_command_packet(tw_dev, request_id); + + mdelay(TW_IOCTL_WAIT_TIME); + spin_lock_irq(&tw_dev->tw_lock); + spin_lock_irq(&io_request_lock); + + if (signal_pending(current)) { + dprintk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Signal pending, aborting ioctl().\n", tw_dev->host->host_no); + tw_dev->srb[request_id]->result = (DID_OK << 16); + goto tw_ioctl_bail; + } + + tw_dev->srb[request_id]->result = (DID_OK << 16); + /* Now copy up the param or io sglist to userspace */ + if (command_packet->byte0.sgl_offset == 2) { + use_sg = command_save->size - 3; + data_ptr = phys_to_virt(command_packet->byte8.param.sgl[0].address); + for (i=0;ibyte8.param.sgl[i].address != NULL) { + error = copy_to_user((u32 *)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length); + if (error) { + printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n", tw_dev->host->host_no); + goto tw_ioctl_bail; + } + dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.param.sgl[i].length, current->pid); + data_ptr+=command_save->byte8.param.sgl[i].length; + } else { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no); + tw_dev->srb[request_id]->result = (DID_RESET << 16); + goto tw_ioctl_bail; + } + } + } + if (command_packet->byte0.sgl_offset == 3) { + use_sg = command_save->size - 4; + if (command_packet->byte0.opcode == TW_OP_READ) { + data_ptr = phys_to_virt(command_packet->byte8.io.sgl[0].address); + for(i=0;ibyte8.io.sgl[i].address != NULL) { + error = copy_to_user((u32 *)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length); + if (error) { + printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n", tw_dev->host->host_no); + goto tw_ioctl_bail; + } + dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.io.sgl[i].length, current->pid); + data_ptr+=command_save->byte8.io.sgl[i].length; + } else { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no); + tw_dev->srb[request_id]->result = (DID_RESET << 16); + goto tw_ioctl_bail; + } + } + } + } + + tw_ioctl_bail: + + /* Free up sglist memory */ + if (tw_dev->ioctl_data[request_id]) + kfree(tw_dev->ioctl_data[request_id]); + else + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Error freeing ioctl data.\n", tw_dev->host->host_no); + + /* Now complete the io */ + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + tw_dev->posted_request_count--; + tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); + return 0; + } else { + printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n"); + return 1; + } default: printk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode); tw_dev->state[request_id] = TW_S_COMPLETED; @@ -1655,6 +1847,7 @@ TW_Param *param; TW_Ioctl *ioctl = NULL; TW_Passthru *passthru = NULL; + TW_Command *command_packet; ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer; dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete()\n"); @@ -1663,6 +1856,13 @@ printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Request buffer NULL.\n"); return 1; } + + command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; + if (command_packet == NULL) { + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl_complete(): Bad command packet virtual address.\n", tw_dev->host->host_no); + return 1; + } + dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n", tw_dev->srb[request_id]->request_bufflen); ioctl = (TW_Ioctl *)buff; @@ -1671,6 +1871,9 @@ passthru = (TW_Passthru *)ioctl->data; memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512); break; + case TW_CMD_PACKET_WITH_DATA: + dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n"); + return 2; /* Special case for isr to not complete io */ default: memset(buff, 0, tw_dev->srb[request_id]->request_bufflen); param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; @@ -1821,7 +2024,7 @@ error = tw_aen_drain_queue(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Card not responding, retrying.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no); tries++; continue; } @@ -1857,7 +2060,7 @@ } /* Re-enable interrupts */ - tw_enable_interrupts(tw_dev); + tw_enable_and_clear_interrupts(tw_dev); return 0; } /* End tw_reset_sequence() */ @@ -2381,6 +2584,9 @@ capacity = (param_data[3] << 24) | (param_data[2] << 16) | (param_data[1] << 8) | param_data[0]; + /* Subtract one sector to fix get last sector ioctl */ + capacity -= 1; + dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): Capacity = 0x%x.\n", capacity); /* Number of LBA's */ @@ -2671,7 +2877,7 @@ } /* Re-enable interrupts */ - tw_enable_interrupts(tw_dev); + tw_enable_and_clear_interrupts(tw_dev); return 0; } /* End tw_shutdown_device() */ @@ -2719,7 +2925,7 @@ int id = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start()\n"); - + /* Obtain next free request_id */ do { if (tw_dev->free_head == tw_dev->free_wrap) { @@ -2749,7 +2955,6 @@ } /* End tw_unmask_command_interrupt() */ /* Now get things going */ - static Scsi_Host_Template driver_template = TWXXXX; #include "scsi_module.c" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/3w-xxxx.h linux-2.5/drivers/scsi/3w-xxxx.h --- linux-2.5.5/drivers/scsi/3w-xxxx.h Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/scsi/3w-xxxx.h Thu Feb 14 00:36:31 2002 @@ -6,7 +6,7 @@ Arnaldo Carvalho de Melo Brad Strand - Copyright (C) 1999-2001 3ware Inc. + Copyright (C) 1999-2002 3ware Inc. Kernel compatablity By: Andre Hedrick Non-Copyright (C) 2000 Andre Hedrick @@ -62,7 +62,7 @@ static char *tw_aen_string[] = { "AEN queue empty", // 0x000 "Soft reset occurred", // 0x001 - "Mirorr degraded: Unit #", // 0x002 + "Unit degraded: Unit #", // 0x002 "Controller error", // 0x003 "Rebuild failed: Unit #", // 0x004 "Rebuild complete: Unit #", // 0x005 @@ -90,10 +90,12 @@ "DCB unsupported version: Port #", // 0x028 "Verify started: Unit #", // 0x029 "Verify failed: Port #", // 0x02A - "Verify complete: Unit #" // 0x02B + "Verify complete: Unit #", // 0x02B + "Overwrote bad sector during rebuild: Port #", //0x2C + "Encountered bad sector during rebuild: Port #" //0x2D }; -#define TW_AEN_STRING_MAX 0x02C +#define TW_AEN_STRING_MAX 0x02E /* Control register bit definitions */ #define TW_CONTROL_CLEAR_HOST_INTERRUPT 0x00080000 @@ -108,6 +110,7 @@ #define TW_CONTROL_DISABLE_INTERRUPTS 0x00000040 #define TW_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020 #define TW_CONTROL_CLEAR_PARITY_ERROR 0x00800000 +#define TW_CONTROL_CLEAR_PCI_ABORT 0x00100000 /* Status register bit definitions */ #define TW_STATUS_MAJOR_VERSION_MASK 0xF0000000 @@ -140,6 +143,7 @@ #define TW_DEVICE_ID2 (0x1001) /* 7000 series controller */ #define TW_NUMDEVICES 2 #define TW_PCI_CLEAR_PARITY_ERRORS 0xc100 +#define TW_PCI_CLEAR_PCI_ABORT 0x2000 /* Command packet opcodes */ #define TW_OP_NOP 0x0 @@ -153,6 +157,7 @@ #define TW_OP_AEN_LISTEN 0x1c #define TW_CMD_PACKET 0x1d #define TW_ATA_PASSTHRU 0x1e +#define TW_CMD_PACKET_WITH_DATA 0x1f /* Asynchronous Event Notification (AEN) Codes */ #define TW_AEN_QUEUE_EMPTY 0x0000 @@ -191,12 +196,11 @@ #define TW_MAX_AEN_TRIES 100 #define TW_UNIT_ONLINE 1 #define TW_IN_INTR 1 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,7) #define TW_MAX_SECTORS 256 -#else -#define TW_MAX_SECTORS 128 -#endif +#define TW_MAX_BOUNCE_SECTORS 128 #define TW_AEN_WAIT_TIME 1000 +#define TW_IOCTL_WAIT_TIME (1 * HZ) /* 1 second */ +#define TW_MAX_CDB_LEN 16 /* Macros */ #define TW_STATUS_ERRORS(x) \ @@ -209,7 +213,7 @@ #ifdef TW_DEBUG #define dprintk(msg...) printk(msg) #else -#define dprintk(msg...) do { } while(0); +#define dprintk(msg...) do { } while(0) #endif /* Scatter Gather List Entry */ @@ -262,7 +266,9 @@ } TW_Command; typedef struct TAG_TW_Ioctl { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,15) int buffer; +#endif unsigned char opcode; unsigned short table_id; unsigned char parameter_id; @@ -381,6 +387,7 @@ unsigned char aen_head; unsigned char aen_tail; long flags; /* long req'd for set_bit --RR */ + char *ioctl_data[TW_Q_LENGTH]; } TW_Device_Extension; /* Function prototypes */ @@ -397,6 +404,7 @@ void tw_disable_interrupts(TW_Device_Extension *tw_dev); int tw_empty_response_que(TW_Device_Extension *tw_dev); void tw_enable_interrupts(TW_Device_Extension *tw_dev); +void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev); int tw_findcards(Scsi_Host_Template *tw_host); void tw_free_device_extension(TW_Device_Extension *tw_dev); int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/53c7,8xx.c linux-2.5/drivers/scsi/53c7,8xx.c --- linux-2.5.5/drivers/scsi/53c7,8xx.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/scsi/53c7,8xx.c Fri Feb 8 02:15:53 2002 @@ -1869,7 +1869,7 @@ */ timeout = jiffies + 5 * HZ / 10; - while ((hostdata->test_completed == -1) && jiffies < timeout) { + while ((hostdata->test_completed == -1) && time_before(jiffies, timeout)) { barrier(); cpu_relax(); } @@ -1955,7 +1955,7 @@ restore_flags(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ - while ((hostdata->test_completed == -1) && jiffies < timeout) { + while ((hostdata->test_completed == -1) && time_before(jiffies, timeout)) { barrier(); cpu_relax(); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/53c7xx.c linux-2.5/drivers/scsi/53c7xx.c --- linux-2.5.5/drivers/scsi/53c7xx.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/scsi/53c7xx.c Mon Feb 4 22:15:17 2002 @@ -1627,7 +1627,7 @@ */ timeout = jiffies + 5 * HZ / 10; - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && time_before(jiffies, timeout)) barrier(); failed = 1; @@ -1713,7 +1713,7 @@ restore_flags(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && time_before(jiffies, timeout)) barrier(); NCR53c7x0_write32 (DSA_REG, 0); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/Config.help linux-2.5/drivers/scsi/Config.help --- linux-2.5.5/drivers/scsi/Config.help Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/scsi/Config.help Mon Mar 4 00:00:02 2002 @@ -145,6 +145,13 @@ so most people can say N here and should in fact do so, because it is safer. +CONFIG_SCSI_REPORT_LUNS + If you want to build with SCSI REPORT LUNS support in the kernel, say Y here. + The REPORT LUNS command is useful for devices (such as disk arrays) with + large numbers of LUNs where the LUN values are not contiguous (sparse LUN). + REPORT LUNS scanning is done only for SCSI-3 devices. Most users can safely + answer N here. + CONFIG_SCSI_CONSTANTS The error messages regarding your SCSI hardware will be easier to understand if you say Y here; it will enlarge your kernel by about @@ -172,6 +179,10 @@ there should be no noticeable performance impact as long as you have logging turned off. +CONFIG_SGIWD93_SCSI + If you have a Western Digital WD93 SCSI controller on + an SGI MIPS system, say Y. Otherwise, say N. + CONFIG_SCSI_DECNCR Say Y here to support the NCR53C94 SCSI controller chips on IOASIC based TURBOchannel DECstations and TURBOchannel PMAZ-A cards. @@ -970,6 +981,11 @@ inserted in and removed from the running kernel whenever you want). The module will be called qlogicfc.o. If you want to compile it as a module, say M here and read . + +CONFIG_SCSI_QLOGIC_FC_FIRMWARE + Say Y to include ISP2100 Fabric Initiator/Target Firmware, with + expanded LUN addressing and FcTape (FCP-2) support, in the + Qlogic QLA 1280 driver. CONFIG_SCSI_QLOGIC_1280 Say Y if you have a QLogic ISP1x80/1x160 SCSI host adapter. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/Config.in linux-2.5/drivers/scsi/Config.in --- linux-2.5.5/drivers/scsi/Config.in Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/scsi/Config.in Mon Mar 4 00:00:02 2002 @@ -21,6 +21,7 @@ comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' bool ' Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN +bool ' Build with SCSI REPORT LUNS support' CONFIG_SCSI_REPORT_LUNS bool ' Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS bool ' SCSI logging facility' CONFIG_SCSI_LOGGING @@ -46,6 +47,9 @@ dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate 'Adaptec AACRAID support (EXPERIMENTAL)' CONFIG_SCSI_AACRAID $CONFIG_SCSI $CONFIG_PCI +fi source drivers/scsi/aic7xxx/Config.in if [ "$CONFIG_SCSI_AIC7XXX" != "y" ]; then dep_tristate 'Old Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX_OLD $CONFIG_SCSI @@ -207,7 +211,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'SCSI debugging host simulator (EXPERIMENTAL)' CONFIG_SCSI_DEBUG $CONFIG_SCSI fi -if [ "$CONFIG_PPC" = "y" ]; then +if [ "$CONFIG_ALL_PPC" = "y" ]; then dep_tristate 'MESH (Power Mac internal SCSI) support' CONFIG_SCSI_MESH $CONFIG_SCSI if [ "$CONFIG_SCSI_MESH" != "n" ]; then int ' maximum synchronous transfer rate (MB/s) (0 = async)' CONFIG_SCSI_MESH_SYNC_RATE 5 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/Makefile linux-2.5/drivers/scsi/Makefile --- linux-2.5.5/drivers/scsi/Makefile Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/scsi/Makefile Mon Feb 4 22:15:17 2002 @@ -1,7 +1,7 @@ # # Makefile for linux/drivers/scsi # -# 30 May 2000, Christoph Hellwig +# 30 May 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # # 20 Sep 2000, Torben Mathiasen @@ -25,6 +25,7 @@ mod-subdirs := pcmcia ../acorn/scsi +subdir-$(CONFIG_SCSI_AACRAID) += aacraid subdir-$(CONFIG_SCSI_AIC7XXX) += aic7xxx subdir-$(CONFIG_PCMCIA) += pcmcia @@ -64,6 +65,9 @@ obj-$(CONFIG_SCSI_AHA152X) += aha152x.o obj-$(CONFIG_SCSI_AHA1542) += aha1542.o obj-$(CONFIG_SCSI_AHA1740) += aha1740.o +ifeq ($(CONFIG_SCSI_AACRAID),y) + obj-$(CONFIG_SCSI_AACRAID) += aacraid/aacraid.o +endif ifeq ($(CONFIG_SCSI_AIC7XXX),y) obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/aic7xxx_drv.o endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/NCR5380.c linux-2.5/drivers/scsi/NCR5380.c --- linux-2.5.5/drivers/scsi/NCR5380.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/scsi/NCR5380.c Thu Dec 27 15:14:59 2001 @@ -83,8 +83,6 @@ * basically, transfer size needs to be reduced by one * and the last byte read as is done with PSEUDO_DMA. * - * 3. Test USLEEP code - * * 4. Test SCSI-II tagged queueing (I have no devices which support * tagged queueing) * @@ -110,6 +108,12 @@ #define READ_OVERRUNS #endif +#ifdef BOARD_REQUIRES_NO_DELAY +#define io_recovery_delay(x) +#else +#define io_recovery_delay(x) udelay(x) +#endif + /* * Design * Issues : @@ -192,9 +196,8 @@ * phase goes through the various phases as instructed by the target. * if the target goes into MSG IN and sends a DISCONNECT message, * the command structure is placed into the per instance disconnected - * queue, and NCR5380_main tries to find more work. If USLEEP - * was defined, and the target is idle for too long, the system - * will try to sleep. + * queue, and NCR5380_main tries to find more work. If the target is + * idle for too long, the system will try to sleep. * * If a command has disconnected, eventually an interrupt will trigger, * calling NCR5380_intr() which will in turn call NCR5380_reselect @@ -244,21 +247,14 @@ * rely on phase mismatch and EOP interrupts to determine end * of phase. * - * SCSI2 - if defined, SCSI-2 tagged queuing is used where possible - * * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You * only really want to use this if you're having a problem with * dropped characters during high speed communications, and even * then, you're going to be better off twiddling with transfersize * in the high level code. * - * USLEEP - if defined, on devices that aren't disconnecting from the - * bus, we will go to sleep so that the CPU can get real work done - * when we run a command that won't complete immediately. - * - * Defaults for these will be provided if USLEEP is defined, although - * the user may want to adjust these to allocate CPU resources to - * the SCSI driver or "real" code. + * Defaults for these will be provided although the user may want to adjust + * these to allocate CPU resources to the SCSI driver or "real" code. * * USLEEP_SLEEP - amount of time, in jiffies, to sleep * @@ -322,18 +318,13 @@ static void do_reset(struct Scsi_Host *host); static struct Scsi_Host *first_instance = NULL; static Scsi_Host_Template *the_template = NULL; - -#ifdef USLEEP -struct timer_list usleep_timer; -#endif +static struct timer_list usleep_timer; /* - * Function : void initialize_SCp(Scsi_Cmnd *cmd) + * initialize_SCp - init the scsi pointer field + * @cmd: command block to set up * - * Purpose : initialize the saved data pointers for cmd to point to the - * start of the buffer. - * - * Inputs : cmd - Scsi_Cmnd structure to have pointers reset. + * Set up the internal fields in the SCSI command. */ static __inline__ void initialize_SCp(Scsi_Cmnd * cmd) @@ -362,88 +353,49 @@ static struct { unsigned char mask; const char *name; -} signals[] = { { - - SR_DBP, "PARITY" -}, { - SR_RST, "RST" -}, { - SR_BSY, "BSY" -}, -{ - SR_REQ, "REQ" -}, { - SR_MSG, "MSG" -}, { - SR_CD, "CD" -}, { - SR_IO, "IO" -}, -{ - SR_SEL, "SEL" -}, { - 0, NULL -} -}, - -basrs[] = { { - BASR_ATN, "ATN" -}, { - BASR_ACK, "ACK" -}, { - 0, NULL -} -}, - -icrs[] = { { - ICR_ASSERT_RST, "ASSERT RST" -}, { - ICR_ASSERT_ACK, "ASSERT ACK" -}, -{ - ICR_ASSERT_BSY, "ASSERT BSY" -}, { - ICR_ASSERT_SEL, "ASSERT SEL" -}, -{ - ICR_ASSERT_ATN, "ASSERT ATN" -}, { - ICR_ASSERT_DATA, "ASSERT DATA" -}, -{ - 0, NULL -} -}, - -mrs[] = { { - MR_BLOCK_DMA_MODE, "MODE BLOCK DMA" -}, { - MR_TARGET, "MODE TARGET" -}, -{ - MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK" -}, { - MR_ENABLE_PAR_INTR, - "MODE PARITY INTR" -}, { - MR_MONITOR_BSY, "MODE MONITOR BSY" -}, -{ - MR_DMA_MODE, "MODE DMA" -}, { - MR_ARBITRATE, "MODE ARBITRATION" -}, -{ - 0, NULL -} +} signals[] = { + {SR_DBP, "PARITY"}, + {SR_RST, "RST"}, + {SR_BSY, "BSY"}, + {SR_REQ, "REQ"}, + {SR_MSG, "MSG"}, + {SR_CD, "CD"}, + {SR_IO, "IO"}, + {SR_SEL, "SEL"}, + {0, NULL} +}, +basrs[] = { + {BASR_ATN, "ATN"}, + {BASR_ACK, "ACK"}, + {0, NULL} +}, +icrs[] = { + {ICR_ASSERT_RST, "ASSERT RST"}, + {ICR_ASSERT_ACK, "ASSERT ACK"}, + {ICR_ASSERT_BSY, "ASSERT BSY"}, + {ICR_ASSERT_SEL, "ASSERT SEL"}, + {ICR_ASSERT_ATN, "ASSERT ATN"}, + {ICR_ASSERT_DATA, "ASSERT DATA"}, + {0, NULL} +}, +mrs[] = { + {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, + {MR_TARGET, "MODE TARGET"}, + {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, + {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"}, + {MR_MONITOR_BSY, "MODE MONITOR BSY"}, + {MR_DMA_MODE, "MODE DMA"}, + {MR_ARBITRATE, "MODE ARBITRATION"}, + {0, NULL} }; -/* - * Function : void NCR5380_print(struct Scsi_Host *instance) +/** + * NCR5380_print - print scsi bus signals + * @instance: adapter state to dump * - * Purpose : print the SCSI bus signals for debugging purposes + * Print the SCSI bus signals for debugging purposes * - * Input : instance - which NCR5380 + * Locks: none */ static void NCR5380_print(struct Scsi_Host *instance) @@ -452,6 +404,7 @@ unsigned long flags; unsigned char status, data, basr, mr, icr, i; NCR5380_setup(instance); + /* FIXME - this needs proper locking */ save_flags(flags); cli(); data = NCR5380_read(CURRENT_SCSI_DATA_REG); @@ -483,32 +436,22 @@ unsigned char value; const char *name; } phases[] = { - - { - PHASE_DATAOUT, "DATAOUT" - }, { - PHASE_DATAIN, "DATAIN" - }, { - PHASE_CMDOUT, "CMDOUT" - }, - { - PHASE_STATIN, "STATIN" - }, { - PHASE_MSGOUT, "MSGOUT" - }, { - PHASE_MSGIN, "MSGIN" - }, - { - PHASE_UNKNOWN, "UNKNOWN" - } + {PHASE_DATAOUT, "DATAOUT"}, + {PHASE_DATAIN, "DATAIN"}, + {PHASE_CMDOUT, "CMDOUT"}, + {PHASE_STATIN, "STATIN"}, + {PHASE_MSGOUT, "MSGOUT"}, + {PHASE_MSGIN, "MSGIN"}, + {PHASE_UNKNOWN, "UNKNOWN"} }; /* - * Function : void NCR5380_print_phase(struct Scsi_Host *instance) + * NCR5380_print_phase - show SCSI phase + * @instance: adapter to dump * - * Purpose : print the current SCSI phase for debugging purposes + * Print the current SCSI phase for debugging purposes * - * Input : instance - which NCR5380 + * Locks: none */ static void NCR5380_print_phase(struct Scsi_Host *instance) @@ -520,11 +463,9 @@ status = NCR5380_read(STATUS_REG); if (!(status & SR_REQ)) - printk("scsi%d : REQ not asserted, phase unknown.\n", - instance->host_no); + printk("scsi%d : REQ not asserted, phase unknown.\n", instance->host_no); else { - for (i = 0; (phases[i].value != PHASE_UNKNOWN) && - (phases[i].value != (status & PHASE_MASK)); ++i); + for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); printk("scsi%d : phase %s\n", instance->host_no, phases[i].name); } } @@ -549,7 +490,7 @@ * conditions are possible. */ -static volatile int main_running = 0; +static unsigned long main_running = 0; /* * Function : run_main(void) @@ -563,14 +504,10 @@ static __inline__ void run_main(void) { - if (!main_running) { - main_running = 1; + if (!test_and_set_bit(0, &main_running)) NCR5380_main(); - } } -#ifdef USLEEP - /* * These need tweaking, and would probably work best as per-device * flags initialized differently for disk, tape, cd, etc devices. @@ -621,63 +558,67 @@ static int should_disconnect(unsigned char cmd) { switch (cmd) { - case READ_6: - case WRITE_6: - case SEEK_6: - case READ_10: - case WRITE_10: - case SEEK_10: - return DISCONNECT_TIME_TO_DATA; - case FORMAT_UNIT: - case SEARCH_HIGH: - case SEARCH_LOW: - case SEARCH_EQUAL: - return DISCONNECT_LONG; - default: - return DISCONNECT_NONE; + case READ_6: + case WRITE_6: + case SEEK_6: + case READ_10: + case WRITE_10: + case SEEK_10: + return DISCONNECT_TIME_TO_DATA; + case FORMAT_UNIT: + case SEARCH_HIGH: + case SEARCH_LOW: + case SEARCH_EQUAL: + return DISCONNECT_LONG; + default: + return DISCONNECT_NONE; } } /* * Assumes instance->time_expires has been set in higher level code. + * + * Locks: Caller must hold io_request_lock */ static int NCR5380_set_timer(struct Scsi_Host *instance) { - unsigned long flags; struct Scsi_Host *tmp, **prev; - save_flags(flags); - cli(); if (((struct NCR5380_hostdata *) (instance->hostdata))->next_timer) { - restore_flags(flags); return -1; } - for (prev = &expires_first, tmp = expires_first; tmp; - prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer), - tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer) - if (((struct NCR5380_hostdata *)instance->hostdata)->time_expires < - ((struct NCR5380_hostdata *)tmp->hostdata)->time_expires) + for (prev = &expires_first, tmp = expires_first; tmp; prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer), tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer) + if (((struct NCR5380_hostdata *) instance->hostdata)->time_expires < ((struct NCR5380_hostdata *) tmp->hostdata)->time_expires) break; ((struct NCR5380_hostdata *) instance->hostdata)->next_timer = tmp; *prev = instance; - + mod_timer(&usleep_timer, ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires); - restore_flags(flags); return 0; } -/* Doing something about unwanted reentrancy here might be useful */ -void NCR5380_timer_fn(unsigned long surplus_to_requirements) +/** + * NCR5380_timer_fn - handle polled timeouts + * @unused: unused + * + * Walk the list of controllers, find which controllers have exceeded + * their expiry timeout and then schedule the processing co-routine to + * do the real work. + * + * Doing something about unwanted reentrancy here might be useful + * + * Locks: disables irqs, takes and frees io_request_lock + */ + +static void NCR5380_timer_fn(unsigned long unused) { - unsigned long flags; struct Scsi_Host *instance; - save_flags(flags); - cli(); - for (; expires_first && - time_before_eq(((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires, jiffies); ) - { + + spin_lock_irq(&io_request_lock); + + for (; expires_first && time_before_eq(((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires, jiffies);) { instance = ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer; ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer = NULL; ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires = 0; @@ -685,90 +626,91 @@ } del_timer(&usleep_timer); - if (expires_first) - { - usleep_timer.expires = ((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires; + if (expires_first) { + usleep_timer.expires = ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires; add_timer(&usleep_timer); } - restore_flags(flags); - - spin_lock_irqsave(instance->host_lock, flags); run_main(); - spin_unlock_irqrestore(instance->host_lock, flags); + spin_unlock_irq(&io_request_lock); } -#endif /* def USLEEP */ +/** + * NCR5380_all_init - global setup + * + * Set up the global values and timers needed by the NCR5380 driver + */ + static inline void NCR5380_all_init(void) { static int done = 0; if (!done) { -#if (NDEBUG & NDEBUG_INIT) - printk("scsi : NCR5380_all_init()\n"); -#endif + dprintk(NDEBUG_INIT, ("scsi : NCR5380_all_init()\n")); done = 1; -#ifdef USLEEP init_timer(&usleep_timer); usleep_timer.function = NCR5380_timer_fn; -#endif } } -#ifdef AUTOPROBE_IRQ -/* - * Function : int NCR5380_probe_irq (struct Scsi_Host *instance, int possible) - * - * Purpose : autoprobe for the IRQ line used by the NCR5380. - * - * Inputs : instance - pointer to this instance of the NCR5380 driver, - * possible - bitmask of permissible interrupts. - * - * Returns : number of the IRQ selected, IRQ_NONE if no interrupt fired. - * - * XXX no effort is made to deal with spurious interrupts. - */ - static int probe_irq __initdata = 0; +/** + * probe_intr - helper for IRQ autoprobe + * @irq: interrupt number + * @dev_id: unused + * @regs: unused + * + * Set a flag to indicate the IRQ in question was received. This is + * used by the IRQ probe code. + */ + static void __init probe_intr(int irq, void *dev_id, struct pt_regs *regs) { probe_irq = irq; } +/** + * NCR5380_probe_irq - find the IRQ of an NCR5380 + * @instance: NCR5380 controller + * @possible: bitmask of ISA IRQ lines + * + * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ + * and then looking to see what interrupt actually turned up. + * + * Locks: none, irqs must be enabled on entry + */ + static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible) { NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; unsigned long timeout; int trying_irqs, i, mask; NCR5380_setup(instance); for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1) - if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", instance) - == 0)) + if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL) == 0)) trying_irqs |= mask; timeout = jiffies + (250 * HZ / 1000); probe_irq = IRQ_NONE; -/* - * A interrupt is triggered whenever BSY = false, SEL = true - * and a bit set in the SELECT_ENABLE_REG is asserted on the - * SCSI bus. - * - * Note that the bus is only driven when the phase control signals - * (I/O, C/D, and MSG) match those in the TCR, so we must reset that - * to zero. - */ + /* + * A interrupt is triggered whenever BSY = false, SEL = true + * and a bit set in the SELECT_ENABLE_REG is asserted on the + * SCSI bus. + * + * Note that the bus is only driven when the phase control signals + * (I/O, C/D, and MSG) match those in the TCR, so we must reset that + * to zero. + */ NCR5380_write(TARGET_COMMAND_REG, 0); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | - ICR_ASSERT_SEL); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL); - while (probe_irq == IRQ_NONE && time_before(jiffies,timeout)) + while (probe_irq == IRQ_NONE && time_before(jiffies, timeout)) barrier(); NCR5380_write(SELECT_ENABLE_REG, 0); @@ -780,15 +722,16 @@ return probe_irq; } -#endif /* AUTOPROBE_IRQ */ -/* - * Function : void NCR58380_print_options (struct Scsi_Host *instance) - * - * Purpose : called by probe code indicating the NCR5380 driver - * options that were selected. +/** + * NCR58380_print_options - show options + * @instance: unused for now + * + * Called by probe code indicating the NCR5380 driver options that + * were selected. At some point this will switch to runtime options + * read from the adapter in question * - * Inputs : instance, pointer to this instance. Unused. + * Locks: none */ static void __init NCR5380_print_options(struct Scsi_Host *instance) @@ -815,29 +758,25 @@ #ifdef PSEUDO_DMA " PSEUDO DMA" #endif -#ifdef SCSI2 - " SCSI-2" -#endif #ifdef UNSAFE " UNSAFE " #endif ); -#ifdef USLEEP printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP); -#endif printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) { printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE); } } -/* - * Function : void NCR5380_print_status (struct Scsi_Host *instance) +/** + * NCR5380_print_status - dump controller info + * @instance: controller to dump * - * Purpose : print commands in the various queues, called from - * NCR5380_abort and NCR5380_debug to aid debugging. + * Print commands in the various queues, called from NCR5380_abort + * and NCR5380_debug to aid debugging. * - * Inputs : instance, pointer to this instance. + * Locks: called functions disable irqs, missing queue lock in proc call */ static void NCR5380_print_status(struct Scsi_Host *instance) @@ -846,16 +785,12 @@ char *start; int len; - printk("NCR5380 : coroutine is%s running.\n", - main_running ? "" : "n't"); + printk("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't"); -#ifdef NDEBUG - NCR5380_print(instance); - NCR5380_print_phase(instance); -#endif + NCR5380_dprint(NDEBUG_ANY, instance); + NCR5380_dprint_phase(NDEBUG_ANY, instance); - len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), - instance->host_no, 0); + len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), instance->host_no, 0); pr_bfr[len] = 0; printk("\n%s\n", pr_bfr); } @@ -886,18 +821,14 @@ #ifndef NCR5380_proc_info static #endif -int NCR5380_proc_info( - char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { - unsigned long flags; char *pos = buffer; struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; Scsi_Cmnd *ptr; - for (instance = first_instance; instance && - instance->host_no != hostno; instance = instance->next); + for (instance = first_instance; instance && instance->host_no != hostno; instance = instance->next); if (!instance) return (-ESRCH); hostdata = (struct NCR5380_hostdata *) instance->hostdata; @@ -935,32 +866,27 @@ SPRINTF("IRQ: %d.\n", instance->irq); #ifdef DTC_PUBLIC_RELEASE - SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", - dtc_wmaxi, dtc_maxi); + SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", dtc_wmaxi, dtc_maxi); #endif #ifdef PAS16_PUBLIC_RELEASE - SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", - pas_wmaxi, pas_maxi); + SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", pas_wmaxi, pas_maxi); #endif - save_flags(flags); - cli(); + spin_lock_irq(&io_request_lock); SPRINTF("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't"); if (!hostdata->connected) SPRINTF("scsi%d: no currently connected command\n", instance->host_no); else - pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, - pos, buffer, length); + pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, pos, buffer, length); SPRINTF("scsi%d: issue_queue\n", instance->host_no); - for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) + for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); SPRINTF("scsi%d: disconnected_queue\n", instance->host_no); - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); - restore_flags(flags); + spin_unlock_irq(&io_request_lock); + *start = buffer; if (pos - buffer < offset) return 0; @@ -972,16 +898,14 @@ static char *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length) { - SPRINTF("scsi%d : destination target %d, lun %d\n", - cmd->host->host_no, cmd->target, cmd->lun); + SPRINTF("scsi%d : destination target %d, lun %d\n", cmd->host->host_no, cmd->target, cmd->lun); SPRINTF(" command = "); pos = lprint_command(cmd->cmnd, pos, buffer, length); return (pos); } static -char *lprint_command(unsigned char *command, - char *pos, char *buffer, int length) +char *lprint_command(unsigned char *command, char *pos, char *buffer, int length) { int i, s; pos = lprint_opcode(command[0], pos, buffer, length); @@ -999,17 +923,18 @@ } -/* - * Function : void NCR5380_init (struct Scsi_Host *instance, flags) +/** + * NCR5380_init - initialise an NCR5380 + * @instance: adapter to configure + * @flags: control flags * - * Purpose : initializes *instance and corresponding 5380 chip, + * Initializes *instance and corresponding 5380 chip, * with flags OR'd into the initial flags value. * - * Inputs : instance - instantiation of the 5380 driver. - * - * Notes : I assume that the host, hostno, and id bits have been + * Notes : I assume that the host, hostno, and id bits have been * set correctly. I don't care about the irq and other fields. - * + * + * Locks: interrupts must be enabled when we are called */ static void __init NCR5380_init(struct Scsi_Host *instance, int flags) @@ -1017,9 +942,10 @@ NCR5380_local_declare(); int i, pass; unsigned long timeout; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; + if(in_interrupt()) + printk(KERN_ERR "NCR5380_init called with interrupts off!\n"); /* * On NCR53C400 boards, NCR5380 registers are mapped 8 past * the base address. @@ -1031,7 +957,6 @@ #endif NCR5380_setup(instance); - NCR5380_all_init(); hostdata->aborted = 0; @@ -1070,17 +995,13 @@ the_template = instance->hostt; first_instance = instance; } -#ifdef USLEEP hostdata->time_expires = 0; hostdata->next_timer = NULL; -#endif #ifndef AUTOSENSE if ((instance->cmd_per_lun > 1) || instance->can_queue > 1) - ) - printk("scsi%d : WARNING : support for multiple outstanding commands enabled\n" - " without AUTOSENSE option, contingent allegiance conditions may\n" - " be incorrectly cleared.\n", instance->host_no); + printk(KERN_WARNING "scsi%d : WARNING : support for multiple outstanding commands enabled\n" " without AUTOSENSE option, contingent allegiance conditions may\n" + " be incorrectly cleared.\n", instance->host_no); #endif /* def AUTOSENSE */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); @@ -1106,50 +1027,40 @@ * failing, do a hard reset of the SCSI bus */ - for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && - pass <= 6; ++pass) { + for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) { switch (pass) { case 1: case 3: case 5: - printk("scsi%d: SCSI bus busy, waiting up to five seconds\n", - instance->host_no); + printk("scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no); timeout = jiffies + 5 * HZ; - while (time_before(jiffies,timeout) && (NCR5380_read(STATUS_REG) & SR_BSY)); + while (time_before(jiffies, timeout) && (NCR5380_read(STATUS_REG) & SR_BSY)); break; case 2: - printk("scsi%d: bus busy, attempting abort\n", - instance->host_no); + printk("scsi%d: bus busy, attempting abort\n", instance->host_no); do_abort(instance); break; case 4: - printk("scsi%d: bus busy, attempting reset\n", - instance->host_no); + printk("scsi%d: bus busy, attempting reset\n", instance->host_no); do_reset(instance); break; case 6: - printk("scsi%d: bus locked solid or invalid override\n", - instance->host_no); + printk("scsi%d: bus locked solid or invalid override\n", instance->host_no); } } } -/* - * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, - * void (*done)(Scsi_Cmnd *)) - * - * Purpose : enqueues a SCSI command - * - * Inputs : cmd - SCSI command, done - function called on completion, with - * a pointer to the command descriptor. - * - * Returns : 0 +/** + * NCR5380_queue_command - queue a command + * @cmd: SCSI command + * @done: completion handler * - * Side effects : * cmd is added to the per instance issue_queue, with minor * twiddling done to the host specific fields of cmd. If the * main coroutine is not running, it is restarted. * + * Locks: io_request lock held by caller. Called functions drop and + * retake this lock. Called functions take dma lock. */ /* Only make static if a wrapper function is used */ @@ -1158,16 +1069,14 @@ #endif int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { struct Scsi_Host *instance = cmd->host; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; Scsi_Cmnd *tmp; #if (NDEBUG & NDEBUG_NO_WRITE) switch (cmd->cmnd[0]) { - case WRITE_6: - case WRITE_10: - printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", - instance->host_no); + case WRITE_6: + case WRITE_10: + printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", instance->host_no); cmd->result = (DID_ERROR << 16); done(cmd); return 0; @@ -1175,31 +1084,22 @@ #endif /* (NDEBUG & NDEBUG_NO_WRITE) */ #ifdef NCR5380_STATS -#if 0 - if (!hostdata->connected && !hostdata->issue_queue && - !hostdata->disconnected_queue) { - hostdata->timebase = jiffies; - } -#endif -#ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) -#endif - switch (cmd->cmnd[0]) { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase); + switch (cmd->cmnd[0]) { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase); hostdata->bytes_write[cmd->target] += cmd->request_bufflen; hostdata->pendingw++; break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase); + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase); hostdata->bytes_read[cmd->target] += cmd->request_bufflen; hostdata->pendingr++; break; - } + } #endif /* @@ -1209,10 +1109,8 @@ cmd->host_scribble = NULL; cmd->scsi_done = done; - cmd->result = 0; - /* * Insert the cmd into the issue queue. Note that REQUEST SENSE * commands are added to the head of the queue since any command will @@ -1225,31 +1123,28 @@ cmd->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = cmd; } else { - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; - tmp = (Scsi_Cmnd *) tmp->host_scribble); + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble); LIST(cmd, tmp); tmp->host_scribble = (unsigned char *) cmd; } -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command added to %s of queue\n", instance->host_no, - (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail")); -/* Run the coroutine if it isn't already running. */ + /* Run the coroutine if it isn't already running. */ run_main(); return 0; } -/* - * Function : NCR5380_main (void) +/** + * NCR5380_main - NCR state machines * - * Purpose : NCR5380_main is a coroutine that runs as long as more work can + * NCR5380_main is a coroutine that runs as long as more work can * be done on the NCR5380 host adapters in a system. Both * NCR5380_queue_command() and NCR5380_intr() will try to start it * in case it is not running. * - * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should - * reenable them. This prevents reentrancy and kernel stack overflow. + * Locks; The caller must hold the io_request_lock. The lock will still be + * held on return but may be dropped while running. Called functions take + * the DMA lock. */ static void NCR5380_main(void) { @@ -1257,7 +1152,6 @@ struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; int done; - unsigned long flags; /* * We run (with interrupts disabled) until we're sure that none of @@ -1271,43 +1165,22 @@ * this should prevent any race conditions. */ - spin_unlock_irq(instance->host_lock); - - save_flags(flags); - do { - cli(); /* Freeze request queues */ + /* Lock held here */ done = 1; - for (instance = first_instance; instance && - instance->hostt == the_template; instance = instance->next) { - hostdata = (struct NCR5380_hostdata *) instance->hostdata; - cli(); -#ifdef USLEEP + for (instance = first_instance; instance && instance->hostt == the_template; instance = instance->next) { + hostdata = (struct NCR5380_hostdata *) instance->hostdata; + /* Lock held here */ if (!hostdata->connected && !hostdata->selecting) { -#else - if (!hostdata->connected) { -#endif -#if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : not connected\n", instance->host_no); -#endif + dprintk(NDEBUG_MAIN, ("scsi%d : not connected\n", instance->host_no)); /* * Search through the issue_queue for a command destined * for a target that's not busy. */ -#if (NDEBUG & NDEBUG_LISTS) - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp && (tmp != prev); prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble); - /*printk("%p ", tmp); */ - if ((tmp == prev) && tmp) - printk(" LOOP\n"); /* else printk("\n"); */ -#endif - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, - prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) - tmp->host_scribble) { - -#if (NDEBUG & NDEBUG_LISTS) + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) + { if (prev != tmp) - printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun); -#endif + dprintk(NDEBUG_LISTS, ("MAIN tmp=%p target=%d busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun)); /* When we find one, remove it from the issue queue. */ if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) { if (prev) { @@ -1319,8 +1192,6 @@ } tmp->host_scribble = NULL; - /* reenable interrupts after finding one */ - restore_flags(flags); /* * Attempt to establish an I_T_L nexus here. @@ -1328,10 +1199,7 @@ * On failure, we must add the command back to the * issue queue so we can keep trying. */ -#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) - printk("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", - instance->host_no, tmp->target, tmp->lun); -#endif + dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", instance->host_no, tmp->target, tmp->lun)); /* * A successful selection is defined as one that @@ -1343,105 +1211,81 @@ * and see if we can do an information transfer, * with failures we will restart. */ -#ifdef USLEEP - hostdata->selecting = 0; /* RvC: have to preset this - to indicate a new command is being performed */ -#endif + hostdata->selecting = 0; + /* RvC: have to preset this to indicate a new command is being performed */ if (!NCR5380_select(instance, tmp, - /* - * REQUEST SENSE commands are issued without tagged - * queueing, even on SCSI-II devices because the - * contingent allegiance condition exists for the - * entire unit. - */ - (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : - TAG_NEXT)) { + /* + * REQUEST SENSE commands are issued without tagged + * queueing, even on SCSI-II devices because the + * contingent allegiance condition exists for the + * entire unit. + */ + (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) { break; } else { - cli(); LIST(tmp, hostdata->issue_queue); - tmp->host_scribble = (unsigned char *) - hostdata->issue_queue; + tmp->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = tmp; done = 0; - restore_flags(flags); -#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) - printk("scsi%d : main(): select() failed, returned to issue_queue\n", - instance->host_no); -#endif + dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main(): select() failed, returned to issue_queue\n", instance->host_no)); } + /* lock held here still */ } /* if target/lun is not busy */ } /* for */ + /* exited locked */ } /* if (!hostdata->connected) */ -#ifdef USLEEP - if (hostdata->selecting) - { - tmp = (Scsi_Cmnd *)hostdata->selecting; - if (!NCR5380_select(instance, tmp, - (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) - { + if (hostdata->selecting) { + tmp = (Scsi_Cmnd *) hostdata->selecting; + /* Selection will drop and retake the lock */ + if (!NCR5380_select(instance, tmp, (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) { /* Ok ?? */ - } - else - { + } else { /* RvC: device failed, so we wait a long time - this is needed for Mustek scanners, that - do not respond to commands immediately - after a scan */ - printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", - instance->host_no, tmp->target); - cli(); + this is needed for Mustek scanners, that + do not respond to commands immediately + after a scan */ + printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", instance->host_no, tmp->target); + //spin_lock_irq(&io_request_lock); LIST(tmp, hostdata->issue_queue); tmp->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = tmp; - restore_flags(flags); + //spin_unlock_irq(&io_request_lock); hostdata->time_expires = jiffies + USLEEP_WAITLONG; - NCR5380_set_timer (instance); + NCR5380_set_timer(instance); } - } /* if hostdata->selecting */ -#endif + } /* if hostdata->selecting */ if (hostdata->connected #ifdef REAL_DMA && !hostdata->dmalen #endif -#ifdef USLEEP && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies)) -#endif ) { - restore_flags(flags); -#if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : main() : performing information transfer\n", - instance->host_no); -#endif + dprintk(NDEBUG_MAIN, ("scsi%d : main() : performing information transfer\n", instance->host_no)); NCR5380_information_transfer(instance); -#if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : main() : done set false\n", instance->host_no); -#endif + dprintk(NDEBUG_MAIN, ("scsi%d : main() : done set false\n", instance->host_no)); done = 0; } else break; } /* for instance */ } while (!done); - spin_lock_irq(instance->host_lock); - /* cli();*/ - main_running = 0; + /* Exit lock held */ + clear_bit(0, &main_running); } #ifndef DONT_USE_INTR #include #include -/* - * Function : void NCR5380_intr (int irq) - * - * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses +/** + * NCR5380_intr - generic NCR5380 irq handler + * + * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses * from the disconnected queue, and restarting NCR5380_main() * as required. * - * Inputs : int irq, irq that caused this interrupt. - * + * Locks: caller must hold the io_request lock. */ static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { @@ -1449,17 +1293,12 @@ struct Scsi_Host *instance; int done; unsigned char basr; - unsigned long flags; - save_flags(flags); - cli(); -#if (NDEBUG & NDEBUG_INTR) - printk("scsi : NCR5380 irq %d triggered\n", irq); -#endif + dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", irq)); + do { done = 1; - for (instance = first_instance; instance && (instance->hostt == - the_template); instance = instance->next) + for (instance = first_instance; instance && (instance->hostt == the_template); instance = instance->next) if (instance->irq == irq) { /* Look for pending interrupts */ @@ -1467,34 +1306,19 @@ basr = NCR5380_read(BUS_AND_STATUS_REG); /* XXX dispatch to appropriate routine if found and done=0 */ if (basr & BASR_IRQ) { -#if (NDEBUG & NDEBUG_INTR) - NCR5380_print(instance); -#endif - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == - (SR_SEL | SR_IO)) { + NCR5380_dprint(NDEBUG_INTR, instance); + if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { done = 0; - restore_flags(flags); -#if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : SEL interrupt\n", instance->host_no); -#endif + dprintk(NDEBUG_INTR, ("scsi%d : SEL interrupt\n", instance->host_no)); NCR5380_reselect(instance); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else if (basr & BASR_PARITY_ERROR) { -#if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : PARITY interrupt\n", instance->host_no); -#endif + dprintk(NDEBUG_INTR, ("scsi%d : PARITY interrupt\n", instance->host_no)); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { -#if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : RESET interrupt\n", instance->host_no); -#endif + dprintk(NDEBUG_INTR, ("scsi%d : RESET interrupt\n", instance->host_no)); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else { -/* - * XXX the rest of the interrupt conditions should *only* occur during a - * DMA transfer, which I haven't gotten around to fixing yet. - */ - #if defined(REAL_DMA) /* * We should only get PHASE MISMATCH and EOP interrupts @@ -1502,14 +1326,11 @@ * the current setting of the MODE register. */ - if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & - BASR_END_DMA_TRANSFER) || - !(basr & BASR_PHASE_MATCH))) { + if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & BASR_END_DMA_TRANSFER) || !(basr & BASR_PHASE_MATCH))) { int transfered; if (!hostdata->connected) - panic("scsi%d : received end of DMA interrupt with no connected cmd\n", - instance->hostno); + panic("scsi%d : received end of DMA interrupt with no connected cmd\n", instance->hostno); transfered = (hostdata->dmalen - NCR5380_dma_residual(instance)); hostdata->connected->SCp.this_residual -= transferred; @@ -1521,16 +1342,14 @@ { unsigned long timeout = jiffies + NCR_TIMEOUT; - spin_unlock_irq(instance->host_lock); - while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK - && time_before(jiffies, timeout)); - spin_lock_irq(instance->host_lock); - - if (time_after_eq(jiffies, timeout) ) - printk("scsi%d: timeout at NCR5380.c:%d\n", - host->host_no, __LINE__); + spin_unlock_irq(&io_request_lock); + while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK && time_before(jiffies, timeout)); + spin_lock_irq(&io_request_lock); + + if (time_after_eq(jiffies, timeout)) + printk("scsi%d: timeout at NCR5380.c:%d\n", host->host_no, __LINE__); } -#else /* NCR_TIMEOUT */ +#else /* NCR_TIMEOUT */ while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); #endif @@ -1538,9 +1357,7 @@ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); } #else -#if (NDEBUG & NDEBUG_INTR) - printk("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); -#endif + dprintk(NDEBUG_INTR, ("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG))); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); #endif } @@ -1551,42 +1368,57 @@ } while (!done); } +/** + * do_NCR5380_intr + * @irq: interrupt number + * @dev_id: device info + * @regs: registers (unused) + * + * Takes the io_request_lock and invokes the generic NCR5380 interrupt + * handler code + * + * Locks: takes and releases the io_request lock + */ static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; - - struct Scsi_Host *dev = dev_id; - - spin_lock_irqsave(dev->host_lock, flags); + + spin_lock_irqsave(&io_request_lock, flags); NCR5380_intr(irq, dev_id, regs); - spin_unlock_irqrestore(dev->host_lock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); } - #endif + +/** + * collect_stats - collect stats on a scsi command + * @hostdata: adapter + * @cmd: command being issued + * + * Update the statistical data by parsing the command in question + */ + +static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) +{ #ifdef NCR5380_STATS -static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { -#ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) -#endif - switch (cmd->cmnd[0]) { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen; */ - hostdata->pendingw--; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen; */ - hostdata->pendingr--; - break; - } -} + switch (cmd->cmnd[0]) { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); + hostdata->pendingw--; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); + hostdata->pendingr--; + break; + } #endif +} + + /* * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, * int tag); @@ -1616,69 +1448,58 @@ * * If failed (no target) : cmd->scsi_done() will be called, and the * cmd->result host byte set to DID_BAD_TARGET. + * + * Locks: caller holds io_request_lock */ -static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) { + +static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) +{ NCR5380_local_declare(); struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; unsigned char tmp[3], phase; unsigned char *data; int len; unsigned long timeout; - unsigned long flags; -#ifdef USLEEP unsigned char value; -#endif - NCR5380_setup(instance); -#ifdef USLEEP - - if (hostdata->selecting) - { + if (hostdata->selecting) { goto part2; /* RvC: sorry prof. Dijkstra, but it keeps the rest of the code nearly the same */ } -#endif - hostdata->restart_select = 0; -#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION) - NCR5380_print(instance); - printk("scsi%d : starting arbitration, id = %d\n", instance->host_no, - instance->this_id); -#endif - save_flags(flags); - cli(); + hostdata->restart_select = 0; + + NCR5380_dprint(NDEBUG_ARBITRATION, instance); + dprintk(NDEBUG_ARBITRATION, ("scsi%d : starting arbitration, id = %d\n", instance->host_no, instance->this_id)); /* * Set the phase bits to 0, otherwise the NCR5380 won't drive the * data bus during SELECTION. */ - NCR5380_write(TARGET_COMMAND_REG, 0); - + NCR5380_write(TARGET_COMMAND_REG, 0); /* * Start arbitration. */ - NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(MODE_REG, MR_ARBITRATE); - - restore_flags(flags); + NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); + NCR5380_write(MODE_REG, MR_ARBITRATE); /* Wait for arbitration logic to complete */ #if NCR_TIMEOUT { unsigned long timeout = jiffies + 2 * NCR_TIMEOUT; - spin_unlock_irq(instance->host_lock); + spin_unlock_irq(&io_request_lock); while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) - && time_before(jiffies,timeout)); + && time_before(jiffies, timeout)); + + spin_lock_irq(&io_request_lock); - spin_lock_irq(instance->host_lock); - - if (time_after_eq(jiffies,timeout)) { + if (time_after_eq(jiffies, timeout)) { printk("scsi: arbitration timeout at %d\n", __LINE__); NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -1689,11 +1510,7 @@ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)); #endif -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : arbitration complete\n", instance->host_no); -/* Avoid GCC 2.4.5 asm needs to many reloads error */ - __asm__("nop"); -#endif + dprintk(NDEBUG_ARBITRATION, ("scsi%d : arbitration complete\n", instance->host_no)); /* * The arbitration delay is 2.2us, but this is a minimum and there is @@ -1702,34 +1519,25 @@ * */ - udelay(3); + udelay(3); /* Check for lost arbitration */ - if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || - (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { + if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { NCR5380_write(MODE_REG, MR_BASE); -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", - instance->host_no); -#endif + dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no)); return -1; } NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL); if (!(hostdata->flags & FLAG_DTC3181E) && - /* RvC: DTC3181E has some trouble with this - * so we simply removed it. Seems to work with - * only Mustek scanner attached - */ - (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) - { + /* RvC: DTC3181E has some trouble with this + * so we simply removed it. Seems to work with + * only Mustek scanner attached + */ + (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", - instance->host_no); -#endif + dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", instance->host_no)); return -1; } /* @@ -1739,10 +1547,7 @@ udelay(2); -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : won arbitration\n", instance->host_no); -#endif - + dprintk(NDEBUG_ARBITRATION, ("scsi%d : won arbitration\n", instance->host_no)); /* * Now that we have won arbitration, start Selection process, asserting @@ -1757,8 +1562,7 @@ * phase immediately after selection. */ - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); NCR5380_write(MODE_REG, MR_BASE); /* @@ -1774,8 +1578,7 @@ udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ /* Reset BSY */ - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | - ICR_ASSERT_ATN | ICR_ASSERT_SEL)); + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); /* * Something weird happens when we cease to drive BSY - looks @@ -1796,9 +1599,7 @@ udelay(1); -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : selecting target %d\n", instance->host_no, cmd->target); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : selecting target %d\n", instance->host_no, cmd->target)); /* * The SCSI specification calls for a 250 ms timeout for the actual @@ -1813,40 +1614,30 @@ * and it's detecting as true. Sigh. */ -#ifdef USLEEP - hostdata->select_time = 0; /* we count the clock ticks at which we polled */ + hostdata->select_time = 0; /* we count the clock ticks at which we polled */ hostdata->selecting = cmd; part2: - /* RvC: here we enter after a sleeping period, or immediately after - execution of part 1 - we poll only once ech clock tick */ + /* RvC: here we enter after a sleeping period, or immediately after + execution of part 1 + we poll only once ech clock tick */ value = NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO); - if (!value && (hostdata->select_time < 25)) - { + if (!value && (hostdata->select_time < 25)) { /* RvC: we still must wait for a device response */ - hostdata->select_time++; /* after 25 ticks the device has failed */ + hostdata->select_time++; /* after 25 ticks the device has failed */ hostdata->time_expires = jiffies + 1; NCR5380_set_timer(instance); return 0; /* RvC: we return here with hostdata->selecting set, to go to sleep */ } - hostdata->selecting = 0; /* clear this pointer, because we passed the - waiting period */ -#else - spin_unlock_irq(instance->host_lock); - while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & - (SR_BSY | SR_IO))); - spin_lock_irq(instance->host_lock); -#endif - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == - (SR_SEL | SR_IO)) { + hostdata->selecting = 0; /* clear this pointer, because we passed the + waiting period */ + if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); NCR5380_reselect(instance); - printk("scsi%d : reselection after won arbitration?\n", - instance->host_no); + printk("scsi%d : reselection after won arbitration?\n", instance->host_no); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; } @@ -1866,22 +1657,15 @@ printk("scsi%d : weirdness\n", instance->host_no); if (hostdata->restart_select) printk("\trestart select\n"); -#if (NDEBUG & NDEBUG_SELECTION) - NCR5380_print(instance); -#endif + NCR5380_dprint(NDEBUG_SELECTION, instance); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; } cmd->result = DID_BAD_TARGET << 16; -#ifdef NCR5380_STATS collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : target did not respond within 250ms\n", - instance->host_no); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : target did not respond within 250ms\n", instance->host_no)); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return 0; } @@ -1907,10 +1691,10 @@ { unsigned long timeout = jiffies + NCR_TIMEOUT; - spin_unlock_irq(instance->host_lock); + spin_unlock_irq(&io_request_lock); while (!(NCR5380_read(STATUS_REG) & SR_REQ) && time_before(jiffies, timeout)); - spin_lock_irq(instance->host_lock); - + spin_lock_irq(&io_request_lock); + if (time_after_eq(jiffies, timeout)) { printk("scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -1921,47 +1705,20 @@ while (!(NCR5380_read(STATUS_REG) & SR_REQ)); #endif /* def NCR_TIMEOUT */ -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", - instance->host_no, cmd->target); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->target)); tmp[0] = IDENTIFY(((instance->irq == IRQ_NONE) ? 0 : 1), cmd->lun); -#ifdef SCSI2 - if (cmd->device->tagged_queue && (tag != TAG_NONE)) { - tmp[1] = SIMPLE_QUEUE_TAG; - if (tag == TAG_NEXT) { - /* 0 is TAG_NONE, used to imply no tag for this command */ - if (cmd->device->current_tag == 0) - cmd->device->current_tag = 1; - - cmd->tag = cmd->device->current_tag; - cmd->device->current_tag++; - } else - cmd->tag = (unsigned char) tag; - - tmp[2] = cmd->tag; - hostdata->last_message = SIMPLE_QUEUE_TAG; - len = 3; - } else -#endif /* def SCSI2 */ - { - len = 1; - cmd->tag = 0; - } + + len = 1; + cmd->tag = 0; /* Send message(s) */ data = tmp; phase = PHASE_MSGOUT; NCR5380_transfer_pio(instance, &phase, &len, &data); -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : nexus established.\n", instance->host_no); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : nexus established.\n", instance->host_no)); /* XXX need to handle errors here */ hostdata->connected = cmd; -#ifdef SCSI2 - if (!cmd->device->tagged_queue) -#endif - hostdata->busy[cmd->target] |= (1 << cmd->lun); + hostdata->busy[cmd->target] |= (1 << cmd->lun); initialize_SCp(cmd); @@ -1994,27 +1751,22 @@ * counts, we will always do a pseudo DMA or DMA transfer. */ -static int NCR5380_transfer_pio(struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data) { +static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { NCR5380_local_declare(); - register unsigned char p = *phase, tmp; - register int c = *count; - register unsigned char *d = *data; -#ifdef USLEEP + unsigned char p = *phase, tmp; + int c = *count; + unsigned char *d = *data; /* - * RvC: some administrative data to process polling time + * RvC: some administrative data to process polling time */ int break_allowed = 0; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; -#endif NCR5380_setup(instance); -#if (NDEBUG & NDEBUG_PIO) if (!(p & SR_IO)) - printk("scsi%d : pio write %d bytes\n", instance->host_no, c); + dprintk(NDEBUG_PIO, ("scsi%d : pio write %d bytes\n", instance->host_no, c)); else - printk("scsi%d : pio read %d bytes\n", instance->host_no, c); -#endif + dprintk(NDEBUG_PIO, ("scsi%d : pio read %d bytes\n", instance->host_no, c)); /* * The NCR5380 chip will only drive the SCSI bus when the @@ -2024,56 +1776,42 @@ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); -#ifdef USLEEP /* RvC: don't know if this is necessary, but other SCSI I/O is short - * so breaks are not necessary there + * so breaks are not necessary there */ - if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) - { + if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) { break_allowed = 1; } -#endif - - do { /* * Wait for assertion of REQ, after which the phase bits will be * valid */ -#ifdef USLEEP /* RvC: we simply poll once, after that we stop temporarily - * and let the device buffer fill up - * if breaking is not allowed, we keep polling as long as needed + * and let the device buffer fill up + * if breaking is not allowed, we keep polling as long as needed */ - while ( !((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && - !break_allowed ); - if (!(tmp & SR_REQ)) - { + while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && !break_allowed); + if (!(tmp & SR_REQ)) { /* timeout condition */ hostdata->time_expires = jiffies + USLEEP_SLEEP; - NCR5380_set_timer (instance); + NCR5380_set_timer(instance); break; } -#else - while ( !((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) ); -#endif -#if (NDEBUG & NDEBUG_HANDSHAKE) - printk("scsi%d : REQ detected\n", instance->host_no); -#endif + dprintk(NDEBUG_HANDSHAKE, ("scsi%d : REQ detected\n", instance->host_no)); /* Check for phase mismatch */ if ((tmp & PHASE_MASK) != p) { -#if (NDEBUG & NDEBUG_PIO) - printk("scsi%d : phase mismatch\n", instance->host_no); - NCR5380_print_phase(instance); -#endif + dprintk(NDEBUG_HANDSHAKE, ("scsi%d : phase mismatch\n", instance->host_no)); + NCR5380_dprint_phase(NDEBUG_HANDSHAKE, instance); break; } - /* Do actual transfer from SCSI bus to / from memory */ if (!(p & SR_IO)) - NCR5380_write(OUTPUT_DATA_REG, *d); + /* Do actual transfer from SCSI bus to / from memory */ + if (!(p & SR_IO)) + NCR5380_write(OUTPUT_DATA_REG, *d); else *d = NCR5380_read(CURRENT_SCSI_DATA_REG); @@ -2088,34 +1826,22 @@ if (!(p & SR_IO)) { if (!((p & SR_MSG) && c > 1)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA); -#if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); -#endif - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ACK); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); + NCR5380_dprint(NDEBUG_PIO, instance); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK); } else { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN); -#if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); -#endif - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN); + NCR5380_dprint(NDEBUG_PIO, instance); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); } } else { -#if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); -#endif + NCR5380_dprint(NDEBUG_PIO, instance); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); } while (NCR5380_read(STATUS_REG) & SR_REQ); -#if (NDEBUG & NDEBUG_HANDSHAKE) - printk("scsi%d : req false, handshake complete\n", instance->host_no); -#endif + dprintk(NDEBUG_HANDSHAKE, ("scsi%d : req false, handshake complete\n", instance->host_no)); /* * We have several special cases to consider during REQ/ACK handshaking : @@ -2136,9 +1862,7 @@ } } while (--c); -#if (NDEBUG & NDEBUG_PIO) - printk("scsi%d : residual %d\n", instance->host_no, c); -#endif + dprintk(NDEBUG_PIO, ("scsi%d : residual %d\n", instance->host_no, c)); *count = c; *data = d; @@ -2154,36 +1878,46 @@ return -1; } +/** + * do_reset - issue a reset command + * @host: adapter to reset + * + * Issue a reset sequence to the NCR5380 and try and get the bus + * back into sane shape. + * + * Locks: caller holds io_request lock + */ + static void do_reset(struct Scsi_Host *host) { - unsigned long flags; - NCR5380_local_declare(); - NCR5380_setup(host); + NCR5380_local_declare(); + NCR5380_setup(host); + + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); + udelay(25); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +} + +/* + * Function : do_abort (Scsi_Host *host) + * + * Purpose : abort the currently established nexus. Should only be + * called from a routine which can drop into a + * + * Returns : 0 on success, -1 on failure. + * + * Locks: io_request lock held by caller + */ - save_flags(flags); - cli(); - NCR5380_write(TARGET_COMMAND_REG, - PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); - udelay(25); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - restore_flags(flags); -} /* - - * Function : do_abort (Scsi_Host *host) - * - * Purpose : abort the currently established nexus. Should only be - * called from a routine which can drop into a - * - * Returns : 0 on success, -1 on failure. - */ static int do_abort(struct Scsi_Host *host) { +static int do_abort(struct Scsi_Host *host) { NCR5380_local_declare(); unsigned char tmp, *msgptr, phase; int len; - NCR5380_setup(host); + NCR5380_setup(host); /* Request message out phase */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); /* * Wait for the target to indicate a valid phase by asserting @@ -2197,11 +1931,10 @@ while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); while (NCR5380_read(STATUS_REG) & SR_REQ); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); } @@ -2237,54 +1970,46 @@ * * Also, *phase, *count, *data are modified in place. * + * Locks: io_request lock held by caller */ -static int NCR5380_transfer_dma(struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data) { +static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { NCR5380_local_declare(); register int c = *count; register unsigned char p = *phase; register unsigned char *d = *data; unsigned char tmp; -#if defined(PSEUDO_DMA) && !defined(UNSAFE) - unsigned long flags; -#endif int foo; #if defined(REAL_DMA_POLL) int cnt, toPIO; unsigned char saved_data = 0, overrun = 0, residue; #endif - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - NCR5380_setup(instance); + NCR5380_setup(instance); if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { *phase = tmp; return -1; } #if defined(REAL_DMA) || defined(REAL_DMA_POLL) -#ifdef READ_OVERRUNS - if (p & SR_IO) { c -= 2; } -#endif -#if (NDEBUG & NDEBUG_DMA) -printk("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", - instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : - "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d); +#ifdef READ_OVERRUNS + if (p & SR_IO) { + c -= 2; + } #endif -hostdata->dma_len = (p & SR_IO) ? -NCR5380_dma_read_setup(instance, d, c) : -NCR5380_dma_write_setup(instance, d, c); + dprintk(NDEBUG_DMA, ("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d)); + hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c); #endif -NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); #ifdef REAL_DMA -NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); #elif defined(REAL_DMA_POLL) -NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); #else /* * Note : on my sample board, watch-dog timeouts occurred when interrupts @@ -2292,58 +2017,38 @@ * before the setting of DMA mode to after transfer of the last byte. */ -#if defined(PSEUDO_DMA) && !defined(UNSAFE) -save_flags(flags); -cli(); +#if defined(PSEUDO_DMA) && defined(UNSAFE) + spin_unlock_irq(&io_request_lock); #endif /* KLL May need eop and parity in 53c400 */ -if (hostdata->flags & FLAG_NCR53C400) - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK - | MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE - | MR_MONITOR_BSY); -else - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); + if (hostdata->flags & FLAG_NCR53C400) + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK | MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE | MR_MONITOR_BSY); + else + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); #endif /* def REAL_DMA */ -#if (NDEBUG & NDEBUG_DMA) & 0 -printk("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG)); -#endif + dprintk(NDEBUG_DMA, ("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG))); -/* - * FOO stuff. For some UNAPPARENT reason, I'm getting - * watchdog timers fired on bootup for NO APPARENT REASON, meaning it's - * probably a timing problem. - * - * Since this is the only place I have back-to-back writes, perhaps this - * is the problem? - */ + /* + * On the PAS16 at least I/O recovery delays are not needed here. + * Everyone else seems to want them. + */ -if (p & SR_IO) -{ -#ifndef FOO -udelay(1); -#endif -NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); -} else { -#ifndef FOO - udelay(1); -#endif - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); -#ifndef FOO - udelay(1); -#endif - NCR5380_write(START_DMA_SEND_REG, 0); -#ifndef FOO - udelay(1); -#endif -} + if (p & SR_IO) { + io_recovery_delay(1); + NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); + } else { + io_recovery_delay(1); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); + io_recovery_delay(1); + NCR5380_write(START_DMA_SEND_REG, 0); + io_recovery_delay(1); + } #if defined(REAL_DMA_POLL) -do { - tmp = NCR5380_read(BUS_AND_STATUS_REG); -} while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | - - BASR_END_DMA_TRANSFER))); + do { + tmp = NCR5380_read(BUS_AND_STATUS_REG); + } while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | BASR_END_DMA_TRANSFER))); /* At this point, either we've completed DMA, or we have a phase mismatch, @@ -2381,172 +2086,128 @@ request. */ -if (p & SR_IO) { + if (p & SR_IO) { #ifdef READ_OVERRUNS - udelay(10); - if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == - (BASR_PHASE_MATCH | BASR_ACK))) { - saved_data = NCR5380_read(INPUT_DATA_REGISTER); - overrun = 1; - } + udelay(10); + if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == (BASR_PHASE_MATCH | BASR_ACK))) { + saved_data = NCR5380_read(INPUT_DATA_REGISTER); + overrun = 1; + } #endif -} else { - int limit = 100; - while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || - (NCR5380_read(STATUS_REG) & SR_REQ)) { - if (!(tmp & BASR_PHASE_MATCH)) - break; - if (--limit < 0) - break; + } else { + int limit = 100; + while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || (NCR5380_read(STATUS_REG) & SR_REQ)) { + if (!(tmp & BASR_PHASE_MATCH)) + break; + if (--limit < 0) + break; + } } -} + dprintk(NDEBUG_DMA, ("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", instance->host_no, tmp, NCR5380_read(STATUS_REG))); -#if (NDEBUG & NDEBUG_DMA) -printk("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", - instance->host_no, tmp, NCR5380_read(STATUS_REG)); -#endif + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); -NCR5380_write(MODE_REG, MR_BASE); -NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - -residue = NCR5380_dma_residual(instance); -c -= residue; -*count -= c; -*data += c; -*phase = NCR5380_read(STATUS_REG) & PHASE_MASK; + residue = NCR5380_dma_residual(instance); + c -= residue; + *count -= c; + *data += c; + *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; #ifdef READ_OVERRUNS -if (*phase == p && (p & SR_IO) && residue == 0) -{ -if (overrun) { -#if (NDEBUG & NDEBUG_DMA) - printk("Got an input overrun, using saved byte\n"); -#endif - **data = saved_data; - *data += 1; - *count -= 1; - cnt = toPIO = 1; -} else { - printk("No overrun??\n"); - cnt = toPIO = 2; -} -#if (NDEBUG & NDEBUG_DMA) -printk("Doing %d-byte PIO to 0x%X\n", cnt, *data); -#endif -NCR5380_transfer_pio(instance, phase, &cnt, data); -*count -= toPIO - cnt; -} + if (*phase == p && (p & SR_IO) && residue == 0) { + if (overrun) { + dprintk(NDEBUG_DMA, ("Got an input overrun, using saved byte\n")); + **data = saved_data; + *data += 1; + *count -= 1; + cnt = toPIO = 1; + } else { + printk("No overrun??\n"); + cnt = toPIO = 2; + } + dprintk(NDEBUG_DMA, ("Doing %d-byte PIO to 0x%X\n", cnt, *data)); + NCR5380_transfer_pio(instance, phase, &cnt, data); + *count -= toPIO - cnt; + } #endif -#if (NDEBUG & NDEBUG_DMA) -printk("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", - *data, *count, *(*data + *count - 1), *(*data + *count)); -#endif -return 0; + dprintk(NDEBUG_DMA, ("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data + *count - 1), *(*data + *count))); + return 0; #elif defined(REAL_DMA) -return 0; + return 0; #else /* defined(REAL_DMA_POLL) */ -if (p & SR_IO) { + if (p & SR_IO) { #ifdef DMA_WORKS_RIGHT - foo = NCR5380_pread(instance, d, c); + foo = NCR5380_pread(instance, d, c); #else - int diff = 1; - if (hostdata->flags & FLAG_NCR53C400) { - diff = 0; - } - if (!(foo = NCR5380_pread(instance, d, c - diff))) { - /* - * We can't disable DMA mode after successfully transferring - * what we plan to be the last byte, since that would open up - * a race condition where if the target asserted REQ before - * we got the DMA mode reset, the NCR5380 would have latched - * an additional byte into the INPUT DATA register and we'd - * have dropped it. - * - * The workaround was to transfer one fewer bytes than we - * intended to with the pseudo-DMA read function, wait for - * the chip to latch the last byte, read it, and then disable - * pseudo-DMA mode. - * - * After REQ is asserted, the NCR5380 asserts DRQ and ACK. - * REQ is deasserted when ACK is asserted, and not reasserted - * until ACK goes false. Since the NCR5380 won't lower ACK - * until DACK is asserted, which won't happen unless we twiddle - * the DMA port or we take the NCR5380 out of DMA mode, we - * can guarantee that we won't handshake another extra - * byte. - */ + int diff = 1; + if (hostdata->flags & FLAG_NCR53C400) { + diff = 0; + } + if (!(foo = NCR5380_pread(instance, d, c - diff))) { + /* + * We can't disable DMA mode after successfully transferring + * what we plan to be the last byte, since that would open up + * a race condition where if the target asserted REQ before + * we got the DMA mode reset, the NCR5380 would have latched + * an additional byte into the INPUT DATA register and we'd + * have dropped it. + * + * The workaround was to transfer one fewer bytes than we + * intended to with the pseudo-DMA read function, wait for + * the chip to latch the last byte, read it, and then disable + * pseudo-DMA mode. + * + * After REQ is asserted, the NCR5380 asserts DRQ and ACK. + * REQ is deasserted when ACK is asserted, and not reasserted + * until ACK goes false. Since the NCR5380 won't lower ACK + * until DACK is asserted, which won't happen unless we twiddle + * the DMA port or we take the NCR5380 out of DMA mode, we + * can guarantee that we won't handshake another extra + * byte. + */ - if (!(hostdata->flags & FLAG_NCR53C400)) { - while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)); - /* Wait for clean handshake */ - while (NCR5380_read(STATUS_REG) & SR_REQ); - d[c - 1] = NCR5380_read(INPUT_DATA_REG); + if (!(hostdata->flags & FLAG_NCR53C400)) { + while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)); + /* Wait for clean handshake */ + while (NCR5380_read(STATUS_REG) & SR_REQ); + d[c - 1] = NCR5380_read(INPUT_DATA_REG); + } } - } #endif -} else { + } else { #ifdef DMA_WORKS_RIGHT - foo = NCR5380_pwrite(instance, d, c); -#else - int timeout; -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("About to pwrite %d bytes\n", c); -#endif - if (!(foo = NCR5380_pwrite(instance, d, c))) { - /* - * Wait for the last byte to be sent. If REQ is being asserted for - * the byte we're interested, we'll ACK it and it will go false. - */ - if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) { - timeout = 20000; -#if 1 -#if 1 - while (!(NCR5380_read(BUS_AND_STATUS_REG) & - BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & - BASR_PHASE_MATCH)); + foo = NCR5380_pwrite(instance, d, c); #else - if (NCR5380_read(STATUS_REG) & SR_REQ) { - for (; timeout && - !(NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); - --timeout); - for (; timeout && (NCR5380_read(STATUS_REG) & SR_REQ); - --timeout); - } -#endif - - -#if (NDEBUG & NDEBUG_LAST_BYTE_SENT) - if (!timeout) - printk("scsi%d : timed out on last byte\n", - instance->host_no); -#endif - - - if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) { - hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT; - if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) { - hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT; -#if (NDEBUG & NDEBUG_LAST_BYTE_SENT) - printk("scsi%d : last bit sent works\n", - instance->host_no); -#endif + int timeout; + dprintk(NDEBUG_C400_PWRITE, ("About to pwrite %d bytes\n", c)); + if (!(foo = NCR5380_pwrite(instance, d, c))) { + /* + * Wait for the last byte to be sent. If REQ is being asserted for + * the byte we're interested, we'll ACK it and it will go false. + */ + if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) { + timeout = 20000; + while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)); + + if (!timeout) + dprintk(NDEBUG_LAST_BYTE_SENT, ("scsi%d : timed out on last byte\n", instance->host_no)); + + if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) { + hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT; + if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) { + hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT; + dprintk(NDEBUG_LAST_WRITE_SENT, ("scsi%d : last bit sent works\n", instance->host_no)); + } } + } else { + dprintk(NDEBUG_C400_PWRITE, ("Waiting for LASTBYTE\n")); + while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)); + dprintk(NDEBUG_C400_PWRITE, ("Got LASTBYTE\n")); } - } else { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("Waiting for LASTBYTE\n"); -#endif - while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)); -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("Got LASTBYTE\n"); -#endif - } -#else - udelay(5); -#endif } #endif } @@ -2554,13 +2215,9 @@ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); if ((!(p & SR_IO)) && (hostdata->flags & FLAG_NCR53C400)) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: Checking for IRQ\n"); -#endif + dprintk(NDEBUG_C400_PWRITE, ("53C400w: Checking for IRQ\n")); if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: got it, reading reset interrupt reg\n"); -#endif + dprintk(NDEBUG_C400_PWRITE, ("53C400w: got it, reading reset interrupt reg\n")); NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else { printk("53C400w: IRQ NOT THERE!\n"); @@ -2569,11 +2226,8 @@ *data = d + c; *count = 0; *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; -#if 0 - NCR5380_print_phase(instance); -#endif -#if defined(PSEUDO_DMA) && !defined(UNSAFE) - restore_flags(flags); +#if defined(PSEUDO_DMA) && defined(UNSAFE) + spin_lock_irq(&io_request_lock); #endif /* defined(REAL_DMA_POLL) */ return foo; #endif /* def REAL_DMA */ @@ -2595,12 +2249,13 @@ * * XXX Note : we need to watch for bus free or a reset condition here * to recover from an unexpected bus free condition. + * + * Locks: io_request_lock held by caller */ static void NCR5380_information_transfer(struct Scsi_Host *instance) { NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)instance->hostdata; unsigned char msgout = NOP; int sink = 0; int len; @@ -2610,10 +2265,8 @@ unsigned char *data; unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; -#ifdef USLEEP /* RvC: we need to set the end of the polling time */ unsigned long poll_time = jiffies + USLEEP_POLL; -#endif NCR5380_setup(instance); @@ -2624,27 +2277,22 @@ phase = (tmp & PHASE_MASK); if (phase != old_phase) { old_phase = phase; -#if (NDEBUG & NDEBUG_INFORMATION) - NCR5380_print_phase(instance); -#endif + NCR5380_dprint_phase(NDEBUG_INFORMATION, instance); } if (sink && (phase != PHASE_MSGOUT)) { NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); while (NCR5380_read(STATUS_REG) & SR_REQ); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); sink = 0; continue; } switch (phase) { - case PHASE_DATAIN: - case PHASE_DATAOUT: + case PHASE_DATAIN: + case PHASE_DATAOUT: #if (NDEBUG & NDEBUG_NO_DATAOUT) - printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", - instance->host_no); + printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", instance->host_no); sink = 1; do_abort(instance); cmd->result = DID_ERROR << 16; @@ -2661,11 +2309,7 @@ --cmd->SCp.buffers_residual; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = cmd->SCp.buffer->address; -#if (NDEBUG & NDEBUG_INFORMATION) - printk("scsi%d : %d bytes and %d buffers left\n", - instance->host_no, cmd->SCp.this_residual, - cmd->SCp.buffers_residual); -#endif + dprintk(NDEBUG_INFORMATION, ("scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual)); } /* * The preferred transfer method is going to be @@ -2686,9 +2330,7 @@ * We supplement these 2 if's with the flag. */ #ifdef NCR5380_dma_xfer_len - if (!cmd->device->borken && - !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && - (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) { + if (!cmd->device->borken && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) { #else transfersize = cmd->transfersize; @@ -2697,27 +2339,21 @@ transfersize = 512; #endif /* LIMIT_TRANSFERSIZE */ - if (!cmd->device->borken && transfersize && - !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && - cmd->SCp.this_residual && !(cmd->SCp.this_residual % - transfersize)) { + if (!cmd->device->borken && transfersize && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && cmd->SCp.this_residual && !(cmd->SCp.this_residual % transfersize)) { /* Limit transfers to 32K, for xx400 & xx406 * pseudoDMA that transfers in 128 bytes blocks. */ if (transfersize > 32 * 1024) transfersize = 32 * 1024; #endif len = transfersize; - if (NCR5380_transfer_dma(instance, &phase, - &len, (unsigned char **) &cmd->SCp.ptr)) { + if (NCR5380_transfer_dma(instance, &phase, &len, (unsigned char **) &cmd->SCp.ptr)) { /* * If the watchdog timer fires, all future accesses to this * device will use the polled-IO. */ - printk("scsi%d : switching target %d lun %d to slow handshake\n", - instance->host_no, cmd->target, cmd->lun); + printk("scsi%d : switching target %d lun %d to slow handshake\n", instance->host_no, cmd->target, cmd->lun); cmd->device->borken = 1; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); sink = 1; do_abort(instance); cmd->result = DID_ERROR << 16; @@ -2727,12 +2363,11 @@ cmd->SCp.this_residual -= transfersize - len; } else #endif /* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */ - NCR5380_transfer_pio(instance, &phase, - (int *) &cmd->SCp.this_residual, (unsigned char **) - &cmd->SCp.ptr); + NCR5380_transfer_pio(instance, &phase, (int *) &cmd->SCp.this_residual, (unsigned char **) + &cmd->SCp.ptr); break; - case PHASE_MSGIN: - len = 1; + case PHASE_MSGIN: + len = 1; data = &tmp; NCR5380_transfer_pio(instance, &phase, &len, &data); cmd->SCp.Message = tmp; @@ -2749,24 +2384,18 @@ * next_link, done() is called as with unlinked commands. */ #ifdef LINKED - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: + case LINKED_CMD_COMPLETE: + case LINKED_FLG_CMD_COMPLETE: /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - -#if (NDEBUG & NDEBUG_LINKED) - printk("scsi%d : target %d lun %d linked command complete.\n", - instance->host_no, cmd->target, cmd->lun); -#endif + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked command complete.\n", instance->host_no, cmd->target, cmd->lun)); /* * Sanity check : A linked command should only terminate with * one of these messages if there are more linked commands * available. */ - if (!cmd->next_link) { - printk("scsi%d : target %d lun %d linked command complete, no next_link\n" - instance->host_no, cmd->target, cmd->lun); + printk("scsi%d : target %d lun %d linked command complete, no next_link\n" instance->host_no, cmd->target, cmd->lun); sink = 1; do_abort(instance); return; @@ -2775,27 +2404,19 @@ /* The next command is still part of this process */ cmd->next_link->tag = cmd->tag; cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); -#if (NDEBUG & NDEBUG_LINKED) - printk("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", - instance->host_no, cmd->target, cmd->lun); -#endif -#ifdef NCR5380_STATS + dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", instance->host_no, cmd->target, cmd->lun)); collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); cmd = hostdata->connected; break; #endif /* def LINKED */ - case ABORT: - case COMMAND_COMPLETE: + case ABORT: + case COMMAND_COMPLETE: /* Accept message by clearing ACK */ - sink = 1; + sink = 1; NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); hostdata->connected = NULL; -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command for target %d, lun %d completed\n", - instance->host_no, cmd->target, cmd->lun); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d, lun %d completed\n", instance->host_no, cmd->target, cmd->lun)); hostdata->busy[cmd->target] &= ~(1 << cmd->lun); /* @@ -2820,13 +2441,8 @@ cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); #ifdef AUTOSENSE - if ((cmd->cmnd[0] != REQUEST_SENSE) && - (cmd->SCp.Status == CHECK_CONDITION)) { - unsigned long flags; -#if (NDEBUG & NDEBUG_AUTOSENSE) - printk("scsi%d : performing request sense\n", - instance->host_no); -#endif + if ((cmd->cmnd[0] != REQUEST_SENSE) && (cmd->SCp.Status == CHECK_CONDITION)) { + dprintk(NDEBUG_AUTOSENSE, ("scsi%d : performing request sense\n", instance->host_no)); cmd->cmnd[0] = REQUEST_SENSE; cmd->cmnd[1] &= 0xe0; cmd->cmnd[2] = 0; @@ -2839,21 +2455,14 @@ cmd->SCp.ptr = (char *) cmd->sense_buffer; cmd->SCp.this_residual = sizeof(cmd->sense_buffer); - save_flags(flags); - cli(); LIST(cmd, hostdata->issue_queue); cmd->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = (Scsi_Cmnd *) cmd; - restore_flags(flags); -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no)); } else { #endif /* def AUTOSENSE */ -#ifdef NCR5380_STATS collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); } @@ -2867,37 +2476,29 @@ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) barrier(); return; - case MESSAGE_REJECT: + case MESSAGE_REJECT: /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); switch (hostdata->last_message) { - case HEAD_OF_QUEUE_TAG: - case ORDERED_QUEUE_TAG: - case SIMPLE_QUEUE_TAG: - cmd->device->tagged_queue = 0; + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: + case SIMPLE_QUEUE_TAG: + cmd->device->tagged_queue = 0; hostdata->busy[cmd->target] |= (1 << cmd->lun); break; - default: - break; + default: + break; } - case DISCONNECT: { - unsigned long flags; + case DISCONNECT:{ /* Accept message by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); cmd->device->disconnect = 1; - save_flags(flags); - cli(); LIST(cmd, hostdata->disconnected_queue); cmd->host_scribble = (unsigned char *) hostdata->disconnected_queue; hostdata->connected = NULL; hostdata->disconnected_queue = cmd; - restore_flags(flags); -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command for target %d lun %d was moved from connected to" - " the disconnected_queue\n", instance->host_no, - cmd->target, cmd->lun); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d lun %d was moved from connected to" " the disconnected_queue\n", instance->host_no, cmd->target, cmd->lun)); /* * Restore phase bits to 0 so an interrupted selection, * arbitration can resume. @@ -2909,9 +2510,6 @@ /* Wait for bus free to avoid nasty timeouts */ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) barrier(); -#if 0 - NCR5380_print_status(instance); -#endif return; } /* @@ -2924,12 +2522,12 @@ * disconnecting, and we have to break spec to remain * compatible. */ - case SAVE_POINTERS: - case RESTORE_POINTERS: + case SAVE_POINTERS: + case RESTORE_POINTERS: /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); break; - case EXTENDED_MESSAGE: + case EXTENDED_MESSAGE: /* * Extended messages are sent in the following format : * Byte @@ -2942,28 +2540,19 @@ * Start the extended message buffer with the EXTENDED_MESSAGE * byte, since print_msg() wants the whole thing. */ - extended_msg[0] = EXTENDED_MESSAGE; + extended_msg[0] = EXTENDED_MESSAGE; /* Accept first byte by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - -#if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : receiving extended message\n", - instance->host_no); -#endif + dprintk(NDEBUG_EXTENDED, ("scsi%d : receiving extended message\n", instance->host_no)); len = 2; data = extended_msg + 1; phase = PHASE_MSGIN; NCR5380_transfer_pio(instance, &phase, &len, &data); -#if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : length=%d, code=0x%02x\n", - instance->host_no, (int) extended_msg[1], - (int) extended_msg[2]); -#endif + dprintk(NDEBUG_EXTENDED, ("scsi%d : length=%d, code=0x%02x\n", instance->host_no, (int) extended_msg[1], (int) extended_msg[2])); - if (!len && extended_msg[1] <= - (sizeof(extended_msg) - 1)) { + if (!len && extended_msg[1] <= (sizeof(extended_msg) - 1)) { /* Accept third byte by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); len = extended_msg[1] - 1; @@ -2971,26 +2560,20 @@ phase = PHASE_MSGIN; NCR5380_transfer_pio(instance, &phase, &len, &data); - -#if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : message received, residual %d\n", - instance->host_no, len); -#endif + dprintk(NDEBUG_EXTENDED, ("scsi%d : message received, residual %d\n", instance->host_no, len)); switch (extended_msg[2]) { - case EXTENDED_SDTR: - case EXTENDED_WDTR: - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - tmp = 0; + case EXTENDED_SDTR: + case EXTENDED_WDTR: + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + tmp = 0; } } else if (len) { - printk("scsi%d: error receiving extended message\n", - instance->host_no); + printk("scsi%d: error receiving extended message\n", instance->host_no); tmp = 0; } else { - printk("scsi%d: extended message code %02x length %d is too long\n", - instance->host_no, extended_msg[2], extended_msg[1]); + printk("scsi%d: extended message code %02x length %d is too long\n", instance->host_no, extended_msg[2], extended_msg[1]); tmp = 0; } /* Fall through to reject message */ @@ -2999,26 +2582,23 @@ * If we get something weird that we aren't expecting, * reject it. */ - default: - if (!tmp) { + default: + if (!tmp) { printk("scsi%d: rejecting message ", instance->host_no); print_msg(extended_msg); printk("\n"); } else if (tmp != EXTENDED_MESSAGE) - printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n", - instance->host_no, tmp, cmd->target, cmd->lun); + printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n", instance->host_no, tmp, cmd->target, cmd->lun); else - printk("scsi%d: rejecting unknown extended message code %02x, length %d from target %d, lun %d\n", - instance->host_no, extended_msg[1], extended_msg[0], cmd->target, cmd->lun); + printk("scsi%d: rejecting unknown extended message code %02x, length %d from target %d, lun %d\n", instance->host_no, extended_msg[1], extended_msg[0], cmd->target, cmd->lun); msgout = MESSAGE_REJECT; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); break; } /* switch (tmp) */ break; - case PHASE_MSGOUT: - len = 1; + case PHASE_MSGOUT: + len = 1; data = &msgout; hostdata->last_message = msgout; NCR5380_transfer_pio(instance, &phase, &len, &data); @@ -3026,69 +2606,50 @@ hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->connected = NULL; cmd->result = DID_ERROR << 16; -#ifdef NCR5380_STATS collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return; } msgout = NOP; break; - case PHASE_CMDOUT: - len = cmd->cmd_len; + case PHASE_CMDOUT: + len = cmd->cmd_len; data = cmd->cmnd; /* * XXX for performance reasons, on machines with a * PSEUDO-DMA architecture we should probably * use the dma transfer function. */ - NCR5380_transfer_pio(instance, &phase, &len, - &data); -#ifdef USLEEP - if (!cmd->device->disconnect && - should_disconnect(cmd->cmnd[0])) - { + NCR5380_transfer_pio(instance, &phase, &len, &data); + if (!cmd->device->disconnect && should_disconnect(cmd->cmnd[0])) { hostdata->time_expires = jiffies + USLEEP_SLEEP; -#if (NDEBUG & NDEBUG_USLEEP) - printk("scsi%d : issued command, sleeping until %ul\n", instance->host_no, - hostdata->time_expires); -#endif + dprintk(NDEBUG_USLEEP, ("scsi%d : issued command, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); NCR5380_set_timer(instance); return; } -#endif /* def USLEEP */ break; - case PHASE_STATIN: - len = 1; + case PHASE_STATIN: + len = 1; data = &tmp; NCR5380_transfer_pio(instance, &phase, &len, &data); cmd->SCp.Status = tmp; break; - default: - printk("scsi%d : unknown phase\n", instance->host_no); -#ifdef NDEBUG - NCR5380_print(instance); -#endif + default: + printk("scsi%d : unknown phase\n", instance->host_no); + NCR5380_dprint(NDEBUG_ALL, instance); } /* switch(phase) */ } /* if (tmp * SR_REQ) */ -#ifdef USLEEP - else - { + else { /* RvC: go to sleep if polling time expired */ - if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) - { + if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) { hostdata->time_expires = jiffies + USLEEP_SLEEP; -#if (NDEBUG & NDEBUG_USLEEP) - printk("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, - hostdata->time_expires); -#endif + dprintk(NDEBUG_USLEEP, ("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); NCR5380_set_timer(instance); return; } } -#endif } /* while (1) */ } @@ -3101,9 +2662,9 @@ * * Inputs : instance - this instance of the NCR5380. * + * Locks: io_request_lock held by caller */ - static void NCR5380_reselect(struct Scsi_Host *instance) { NCR5380_local_declare(); struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) @@ -3111,28 +2672,22 @@ unsigned char target_mask; unsigned char lun, phase; int len; -#ifdef SCSI2 - unsigned char tag; -#endif unsigned char msg[3]; unsigned char *data; Scsi_Cmnd *tmp = NULL, *prev; int abort = 0; - NCR5380_setup(instance); + NCR5380_setup(instance); /* * Disable arbitration, etc. since the host adapter obviously * lost, and tell an interrupted NCR5380_select() to restart. */ - NCR5380_write(MODE_REG, MR_BASE); - hostdata->restart_select = 1; - - target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + NCR5380_write(MODE_REG, MR_BASE); + hostdata->restart_select = 1; -#if (NDEBUG & NDEBUG_RESELECTION) - printk("scsi%d : reselect\n", instance->host_no); -#endif + target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + dprintk(NDEBUG_SELECTION, ("scsi%d : reselect\n", instance->host_no)); /* * At this point, we have detected that our SCSI ID is on the bus, @@ -3143,10 +2698,10 @@ * signal. */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); while (NCR5380_read(STATUS_REG) & SR_SEL); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); /* * Wait for target to go into MSGIN. @@ -3154,15 +2709,13 @@ while (!(NCR5380_read(STATUS_REG) & SR_REQ)); - len = 1; - data = msg; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - + len = 1; + data = msg; + phase = PHASE_MSGIN; + NCR5380_transfer_pio(instance, &phase, &len, &data); if (!msg[0] & 0x80) { - printk("scsi%d : expecting IDENTIFY message, got ", - instance->host_no); + printk("scsi%d : expecting IDENTIFY message, got ", instance->host_no); print_msg(msg); abort = 1; } else { @@ -3176,22 +2729,14 @@ * nexuses so we can chose to do additional data transfer. */ -#ifdef SCSI2 -#error "SCSI-II tagged queueing is not supported yet" -#endif - /* * Find the command corresponding to the I_T_L or I_T_L_Q nexus we * just reestablished, and remove it from the disconnected queue. */ - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; - tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun) -#ifdef SCSI2 - && (tag == tmp->tag) -#endif ) { if (prev) { REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble); @@ -3204,13 +2749,7 @@ break; } if (!tmp) { -#ifdef SCSI2 - printk("scsi%d : warning : target bitmask %02x lun %d tag %d not in disconnect_queue.\n", - instance->host_no, target_mask, lun, tag); -#else - printk("scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", - instance->host_no, target_mask, lun); -#endif + printk("scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", instance->host_no, target_mask, lun); /* * Since we have an established nexus that we can't do anything with, * we must abort it. @@ -3223,10 +2762,7 @@ do_abort(instance); } else { hostdata->connected = tmp; -#if (NDEBUG & NDEBUG_RESELECTION) - printk("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n", - instance->host_no, tmp->target, tmp->lun, tmp->tag); -#endif + dprintk(NDEBUG_RESELECTION, ("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n", instance->host_no, tmp->target, tmp->lun, tmp->tag)); } } @@ -3245,8 +2781,7 @@ #ifdef REAL_DMA static void NCR5380_dma_complete(NCR5380_instance * instance) { NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata * - instance->hostdata); + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata * instance->hostdata); int transferred; NCR5380_setup(instance); @@ -3289,10 +2824,12 @@ * * Returns : 0 - success, -1 on failure. * - * XXX - there is no way to abort the command that is currently - * connected, you have to wait for it to complete. If this is - * a problem, we could implement longjmp() / setjmp(), setjmp() - * called where the loop started in NCR5380_main(). + * XXX - there is no way to abort the command that is currently + * connected, you have to wait for it to complete. If this is + * a problem, we could implement longjmp() / setjmp(), setjmp() + * called where the loop started in NCR5380_main(). + * + * Locks: io_request_lock held by caller */ #ifndef NCR5380_abort @@ -3300,10 +2837,8 @@ #endif int NCR5380_abort(Scsi_Cmnd * cmd) { NCR5380_local_declare(); - unsigned long flags; struct Scsi_Host *instance = cmd->host; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; Scsi_Cmnd *tmp, **prev; printk("scsi%d : aborting command\n", instance->host_no); @@ -3316,15 +2851,10 @@ NCR5380_print_status(instance); - save_flags(flags); - cli(); NCR5380_setup(instance); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort called\n", instance->host_no); - printk(" basr 0x%X, sr 0x%X\n", - NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG)); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : abort called\n", instance->host_no)); + dprintk(NDEBUG_ABORT, (" basr 0x%X, sr 0x%X\n", NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG))); #if 0 /* @@ -3334,9 +2864,7 @@ */ if (hostdata->connected == cmd) { -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : aborting connected command\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : aborting connected command\n", instance->host_no)); hostdata->aborted = 1; /* * We should perform BSY checking, and make sure we haven't slipped @@ -3363,24 +2891,15 @@ * Case 2 : If the command hasn't been issued yet, we simply remove it * from the issue queue. */ -#if (NDEBUG & NDEBUG_ABORT) /* KLL */ - printk("scsi%d : abort going into loop.\n", instance->host_no); -#endif - for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), - tmp = (Scsi_Cmnd *) hostdata->issue_queue; - tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = - (Scsi_Cmnd *) tmp->host_scribble) + dprintk(NDEBUG_ABORT, ("scsi%d : abort going into loop.\n", instance->host_no)); + for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble) if (cmd == tmp) { REMOVE(5, *prev, tmp, tmp->host_scribble); (*prev) = (Scsi_Cmnd *) tmp->host_scribble; tmp->host_scribble = NULL; tmp->result = DID_ABORT << 16; - restore_flags(flags); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort removed command from issue queue.\n", - instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no)); tmp->done(tmp); return SCSI_ABORT_SUCCESS; } @@ -3402,10 +2921,7 @@ */ if (hostdata->connected) { - restore_flags(flags); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort failed, command connected.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : abort failed, command connected.\n", instance->host_no)); return SCSI_ABORT_NOT_RUNNING; } /* @@ -3433,34 +2949,22 @@ * it from the disconnected queue. */ - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; - tmp = (Scsi_Cmnd *) tmp->host_scribble) + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble) if (cmd == tmp) { - restore_flags(flags); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : aborting disconnected command.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : aborting disconnected command.\n", instance->host_no)); if (NCR5380_select(instance, cmd, (int) cmd->tag)) return SCSI_ABORT_BUSY; - -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : nexus reestablished.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : nexus reestablished.\n", instance->host_no)); do_abort(instance); - cli(); - for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue), - tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; - tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = - (Scsi_Cmnd *) tmp->host_scribble) + for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue), tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble) if (cmd == tmp) { REMOVE(5, *prev, tmp, tmp->host_scribble); *prev = (Scsi_Cmnd *) tmp->host_scribble; tmp->host_scribble = NULL; tmp->result = DID_ABORT << 16; - restore_flags(flags); tmp->done(tmp); return SCSI_ABORT_SUCCESS; } @@ -3474,10 +2978,7 @@ * so we won't panic, but we will notify the user in case something really * broke. */ - - restore_flags(flags); - printk("scsi%d : warning : SCSI command probably completed successfully\n" - " before abortion\n", instance->host_no); + printk("scsi%d : warning : SCSI command probably completed successfully\n" " before abortion\n", instance->host_no); return SCSI_ABORT_NOT_RUNNING; } @@ -3489,6 +2990,7 @@ * * Returns : SCSI_RESET_WAKEUP * + * Locks: io_request_lock held by caller */ #ifndef NCR5380_reset diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/NCR5380.h linux-2.5/drivers/scsi/NCR5380.h --- linux-2.5.5/drivers/scsi/NCR5380.h Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/scsi/NCR5380.h Thu Dec 13 16:32:36 2001 @@ -55,6 +55,8 @@ #define NDEBUG_C400_PWRITE 0x200000 #define NDEBUG_LISTS 0x400000 +#define NDEBUG_ANY 0xFFFFFFFFUL + /* * The contents of the OUTPUT DATA register are asserted on the bus when * either arbitration is occurring or the phase-indicating signals ( @@ -62,8 +64,8 @@ * bit in the INITIATOR COMMAND register is set. */ -#define OUTPUT_DATA_REG 0 /* wo DATA lines on SCSI bus */ -#define CURRENT_SCSI_DATA_REG 0 /* ro same */ +#define OUTPUT_DATA_REG 0 /* wo DATA lines on SCSI bus */ +#define CURRENT_SCSI_DATA_REG 0 /* ro same */ #define INITIATOR_COMMAND_REG 1 /* rw */ #define ICR_ASSERT_RST 0x80 /* rw Set to assert RST */ @@ -91,10 +93,10 @@ */ #define MR_BLOCK_DMA_MODE 0x80 /* rw block mode DMA */ #define MR_TARGET 0x40 /* rw target mode */ -#define MR_ENABLE_PAR_CHECK 0x20 /* rw enable parity checking */ +#define MR_ENABLE_PAR_CHECK 0x20 /* rw enable parity checking */ #define MR_ENABLE_PAR_INTR 0x10 /* rw enable bad parity interrupt */ #define MR_ENABLE_EOP_INTR 0x08 /* rw enable eop interrupt */ -#define MR_MONITOR_BSY 0x04 /* rw enable int on unexpected bsy fail */ +#define MR_MONITOR_BSY 0x04 /* rw enable int on unexpected bsy fail */ #define MR_DMA_MODE 0x02 /* rw DMA / pseudo DMA mode */ #define MR_ARBITRATE 0x01 /* rw start arbitration */ @@ -116,7 +118,7 @@ * Note : a set bit indicates an active signal, driven by us or another * device. */ -#define SR_RST 0x80 +#define SR_RST 0x80 #define SR_BSY 0x40 #define SR_REQ 0x20 #define SR_MSG 0x10 @@ -159,17 +161,17 @@ /* Write any value to this register to start an ini mode DMA receive */ #define START_DMA_INITIATOR_RECEIVE_REG 7 /* wo */ -#define C400_CONTROL_STATUS_REG NCR53C400_register_offset-8 /* rw */ +#define C400_CONTROL_STATUS_REG NCR53C400_register_offset-8 /* rw */ -#define CSR_RESET 0x80 /* wo Resets 53c400 */ -#define CSR_53C80_REG 0x80 /* ro 5380 registers busy */ -#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ -#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ -#define CSR_53C80_INTR 0x10 /* rw Enable 53c80 interrupts */ -#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ -#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Is Host buffer ready */ -#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer read */ -#define CSR_GATED_53C80_IRQ 0x01 /* ro Last block xferred */ +#define CSR_RESET 0x80 /* wo Resets 53c400 */ +#define CSR_53C80_REG 0x80 /* ro 5380 registers busy */ +#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ +#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ +#define CSR_53C80_INTR 0x10 /* rw Enable 53c80 interrupts */ +#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ +#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Is Host buffer ready */ +#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer read */ +#define CSR_GATED_53C80_IRQ 0x01 /* ro Last block xferred */ #if 0 #define CSR_BASE CSR_SCSI_BUFF_INTR | CSR_53C80_INTR @@ -178,13 +180,13 @@ #endif /* Number of 128-byte blocks to be transferred */ -#define C400_BLOCK_COUNTER_REG NCR53C400_register_offset-7 /* rw */ +#define C400_BLOCK_COUNTER_REG NCR53C400_register_offset-7 /* rw */ /* Resume transfer after disconnect */ -#define C400_RESUME_TRANSFER_REG NCR53C400_register_offset-6 /* wo */ +#define C400_RESUME_TRANSFER_REG NCR53C400_register_offset-6 /* wo */ /* Access to host buffer stack */ -#define C400_HOST_BUFFER NCR53C400_register_offset-4 /* rw */ +#define C400_HOST_BUFFER NCR53C400_register_offset-4 /* rw */ /* Note : PHASE_* macros are based on the values of the STATUS register */ @@ -203,8 +205,8 @@ * the target register so we can get phase mismatch interrupts on DMA * transfers. */ - -#define PHASE_SR_TO_TCR(phase) ((phase) >> 2) + +#define PHASE_SR_TO_TCR(phase) ((phase) >> 2) /* * The internal should_disconnect() function returns these based on the @@ -220,7 +222,7 @@ * These are "special" values for the tag parameter passed to NCR5380_select. */ -#define TAG_NEXT -1 /* Use next free tag */ +#define TAG_NEXT -1 /* Use next free tag */ #define TAG_NONE -2 /* * Establish I_T_L nexus instead of I_T_L_Q * even on SCSI-II devices. @@ -235,7 +237,7 @@ #define DMA_NONE 255 #define IRQ_AUTO 254 #define DMA_AUTO 254 -#define PORT_AUTO 0xffff /* autoprobe io port for 53c400a */ +#define PORT_AUTO 0xffff /* autoprobe io port for 53c400a */ #define FLAG_HAS_LAST_BYTE_SENT 1 /* NCR53c81 or better */ #define FLAG_CHECK_LAST_BYTE_SENT 2 /* Only test once */ @@ -245,134 +247,188 @@ #ifndef ASM struct NCR5380_hostdata { - NCR5380_implementation_fields; /* implementation specific */ - unsigned char id_mask, id_higher_mask; /* 1 << id, all bits greater */ - unsigned char targets_present; /* targets we have connected + NCR5380_implementation_fields; /* implementation specific */ + unsigned char id_mask, id_higher_mask; /* 1 << id, all bits greater */ + unsigned char targets_present; /* targets we have connected to, so we can call a select failure a retryable condition */ - volatile unsigned char busy[8]; /* index = target, bit = lun */ + volatile unsigned char busy[8]; /* index = target, bit = lun */ #if defined(REAL_DMA) || defined(REAL_DMA_POLL) - volatile int dma_len; /* requested length of DMA */ + volatile int dma_len; /* requested length of DMA */ #endif - volatile unsigned char last_message; /* last message OUT */ - volatile Scsi_Cmnd *connected; /* currently connected command */ - volatile Scsi_Cmnd *issue_queue; /* waiting to be issued */ - volatile Scsi_Cmnd *disconnected_queue; /* waiting for reconnect */ - volatile int restart_select; /* we have disconnected, + volatile unsigned char last_message; /* last message OUT */ + volatile Scsi_Cmnd *connected; /* currently connected command */ + volatile Scsi_Cmnd *issue_queue; /* waiting to be issued */ + volatile Scsi_Cmnd *disconnected_queue; /* waiting for reconnect */ + volatile int restart_select; /* we have disconnected, used to restart NCR5380_select() */ - volatile unsigned aborted:1; /* flag, says aborted */ - int flags; -#ifdef USLEEP - unsigned long time_expires; /* in jiffies, set prior to sleeping */ - struct Scsi_Host *next_timer; - int select_time; /* timer in select for target response */ - volatile Scsi_Cmnd *selecting; -#endif + volatile unsigned aborted:1; /* flag, says aborted */ + int flags; + unsigned long time_expires; /* in jiffies, set prior to sleeping */ + struct Scsi_Host *next_timer; + int select_time; /* timer in select for target response */ + volatile Scsi_Cmnd *selecting; #ifdef NCR5380_STATS - unsigned timebase; /* Base for time calcs */ - long time_read[8]; /* time to do reads */ - long time_write[8]; /* time to do writes */ - unsigned long bytes_read[8]; /* bytes read */ - unsigned long bytes_write[8]; /* bytes written */ - unsigned pendingr; - unsigned pendingw; + unsigned timebase; /* Base for time calcs */ + long time_read[8]; /* time to do reads */ + long time_write[8]; /* time to do writes */ + unsigned long bytes_read[8]; /* bytes read */ + unsigned long bytes_write[8]; /* bytes written */ + unsigned pendingr; + unsigned pendingw; #endif }; #ifdef __KERNEL__ -static struct Scsi_Host *first_instance; /* linked list of 5380's */ +static struct Scsi_Host *first_instance; /* linked list of 5380's */ + +#define dprintk(a,b) do {} while(0) +#define NCR5380_dprint(a,b) do {} while(0) +#define NCR5380_dprint_phase(a,b) do {} while(0) #if defined(AUTOPROBE_IRQ) -static int NCR5380_probe_irq (struct Scsi_Host *instance, int possible); +static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible); #endif -static void NCR5380_init (struct Scsi_Host *instance, int flags); -static void NCR5380_information_transfer (struct Scsi_Host *instance); +static void NCR5380_init(struct Scsi_Host *instance, int flags); +static void NCR5380_information_transfer(struct Scsi_Host *instance); #ifndef DONT_USE_INTR -static void NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs); -static void do_NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs); +static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs); +static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs); #endif -static void NCR5380_main (void); -static void NCR5380_print_options (struct Scsi_Host *instance); -static void NCR5380_print_phase (struct Scsi_Host *instance); -static void NCR5380_print (struct Scsi_Host *instance); +static void NCR5380_main(void); +static void NCR5380_print_options(struct Scsi_Host *instance); +static void NCR5380_print_phase(struct Scsi_Host *instance); +static void NCR5380_print(struct Scsi_Host *instance); #ifndef NCR5380_abort static #endif -int NCR5380_abort (Scsi_Cmnd *cmd); +int NCR5380_abort(Scsi_Cmnd * cmd); #ifndef NCR5380_reset static #endif -int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags); +int NCR5380_reset(Scsi_Cmnd * cmd, unsigned int reset_flags); #ifndef NCR5380_queue_command -static +static #endif -int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); +int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); -static void NCR5380_reselect (struct Scsi_Host *instance); -static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag); +static void NCR5380_reselect(struct Scsi_Host *instance); +static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag); #if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL) -static int NCR5380_transfer_dma (struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data); +static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); #endif -static int NCR5380_transfer_pio (struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data); +static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); #if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) #if defined(i386) || defined(__alpha__) -static __inline__ int NCR5380_pc_dma_setup (struct Scsi_Host *instance, - unsigned char *ptr, unsigned int count, unsigned char mode) { - unsigned limit; - unsigned long bus_addr = virt_to_bus(ptr); - - if (instance->dma_channel <=3) { - if (count > 65536) - count = 65536; - limit = 65536 - (bus_addr & 0xFFFF); - } else { - if (count > 65536 * 2) - count = 65536 * 2; - limit = 65536* 2 - (bus_addr & 0x1FFFF); - } - - if (count > limit) count = limit; - - if ((count & 1) || (bus_addr & 1)) - panic ("scsi%d : attempted unaligned DMA transfer\n", instance->host_no); - cli(); - disable_dma(instance->dma_channel); - clear_dma_ff(instance->dma_channel); - set_dma_addr(instance->dma_channel, bus_addr); - set_dma_count(instance->dma_channel, count); - set_dma_mode(instance->dma_channel, mode); - enable_dma(instance->dma_channel); - sti(); - return count; +/** + * NCR5380_pc_dma_setup - setup ISA DMA + * @instance: adapter to set up + * @ptr: block to transfer (virtual address) + * @count: number of bytes to transfer + * @mode: DMA controller mode to use + * + * Program the DMA controller ready to perform an ISA DMA transfer + * on this chip. + * + * Locks: takes and releases the ISA DMA lock. + */ + +static __inline__ int NCR5380_pc_dma_setup(struct Scsi_Host *instance, unsigned char *ptr, unsigned int count, unsigned char mode) +{ + unsigned limit; + unsigned long bus_addr = virt_to_bus(ptr); + unsigned long flags; + + if (instance->dma_channel <= 3) { + if (count > 65536) + count = 65536; + limit = 65536 - (bus_addr & 0xFFFF); + } else { + if (count > 65536 * 2) + count = 65536 * 2; + limit = 65536 * 2 - (bus_addr & 0x1FFFF); + } + + if (count > limit) + count = limit; + + if ((count & 1) || (bus_addr & 1)) + panic("scsi%d : attempted unaligned DMA transfer\n", instance->host_no); + + flags=claim_dma_lock(); + disable_dma(instance->dma_channel); + clear_dma_ff(instance->dma_channel); + set_dma_addr(instance->dma_channel, bus_addr); + set_dma_count(instance->dma_channel, count); + set_dma_mode(instance->dma_channel, mode); + enable_dma(instance->dma_channel); + release_dma_lock(flags); + + return count; } -static __inline__ int NCR5380_pc_dma_write_setup (struct Scsi_Host *instance, - unsigned char *src, unsigned int count) { - return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_WRITE); +/** + * NCR5380_pc_dma_write_setup - setup ISA DMA write + * @instance: adapter to set up + * @ptr: block to transfer (virtual address) + * @count: number of bytes to transfer + * + * Program the DMA controller ready to perform an ISA DMA write to the + * SCSI controller. + * + * Locks: called routines take and release the ISA DMA lock. + */ + +static __inline__ int NCR5380_pc_dma_write_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count) +{ + return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_WRITE); } -static __inline__ int NCR5380_pc_dma_read_setup (struct Scsi_Host *instance, - unsigned char *src, unsigned int count) { - return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_READ); +/** + * NCR5380_pc_dma_read_setup - setup ISA DMA read + * @instance: adapter to set up + * @ptr: block to transfer (virtual address) + * @count: number of bytes to transfer + * + * Program the DMA controller ready to perform an ISA DMA read from the + * SCSI controller. + * + * Locks: called routines take and release the ISA DMA lock. + */ + +static __inline__ int NCR5380_pc_dma_read_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count) +{ + return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_READ); } -static __inline__ int NCR5380_pc_dma_residual (struct Scsi_Host *instance) { - register int tmp; - cli(); - clear_dma_ff(instance->dma_channel); - tmp = get_dma_residue(instance->dma_channel); - sti(); - return tmp; +/** + * NCR5380_pc_dma_residual - return bytes left + * @instance: adapter + * + * Reports the number of bytes left over after the DMA was terminated. + * + * Locks: takes and releases the ISA DMA lock. + */ + +static __inline__ int NCR5380_pc_dma_residual(struct Scsi_Host *instance) +{ + unsigned long flags; + int tmp; + + flags = claim_dma_lock(); + clear_dma_ff(instance->dma_channel); + tmp = get_dma_residue(instance->dma_channel); + release_dma_lock(flags); + + return tmp; } -#endif /* defined(i386) || defined(__alpha__) */ -#endif /* defined(REAL_DMA) */ -#endif /* __KERNEL__ */ -#endif /* ndef ASM */ -#endif /* NCR5380_H */ +#endif /* defined(i386) || defined(__alpha__) */ +#endif /* defined(REAL_DMA) */ +#endif /* __KERNEL__ */ +#endif /* ndef ASM */ +#endif /* NCR5380_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/README.st linux-2.5/drivers/scsi/README.st --- linux-2.5.5/drivers/scsi/README.st Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/scsi/README.st Fri Feb 8 03:03:21 2002 @@ -1,8 +1,8 @@ This file contains brief information about the SCSI tape driver. -The driver is currently maintained by Kai M{kisara (email +The driver is currently maintained by Kai Mäkisara (email Kai.Makisara@metla.fi) -Last modified: Tue Jan 22 21:08:57 2002 by makisara +Last modified: Tue Feb 5 21:33:23 2002 by makisara BASICS diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aacraid/Makefile linux-2.5/drivers/scsi/aacraid/Makefile --- linux-2.5.5/drivers/scsi/aacraid/Makefile Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/Makefile Thu Dec 13 16:32:36 2001 @@ -0,0 +1,16 @@ + +EXTRA_CFLAGS += -I$(TOPDIR)/drivers/scsi + + +O_TARGET := dummy.o + +list-multi := aacraid.o +aacraid-objs := linit.o aachba.o commctrl.o comminit.o commsup.o \ + dpcsup.o rx.o sap1sup.o + +obj-$(CONFIG_SCSI_AACRAID) += aacraid.o + +include $(TOPDIR)/Rules.make + +aacraid.o: $(aacraid-objs) + $(LD) -r -o $@ $(aacraid-objs) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aacraid/README linux-2.5/drivers/scsi/aacraid/README --- linux-2.5.5/drivers/scsi/aacraid/README Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/README Mon Feb 4 22:15:17 2002 @@ -0,0 +1,41 @@ +AACRAID Driver for Linux (take two) + +Introduction +------------------------- +The aacraid driver adds support for Adaptec (http://www.adaptec.com) +OEM based RAID controllers. This is a major rewrite from the original +Adaptec supplied driver. It has signficantly cleaned up both the code +and the running binary size (the module is less than half the size of +the original). + +This driver is experimental. + +Supported Cards/Chipsets +------------------------- + Dell Computer Corporation PERC 2 Quad Channel + Dell Computer Corporation PERC 2/Si + Dell Computer Corporation PERC 3/Si + Dell Computer Corporation PERC 3/Di + HP NetRAID-4M + +Probably Supported Devices +------------------------- + Any and All Adaptec branded AAC964/5400 series raid controllers. + +People +------------------------- +Alan Cox +Christoph Hellwig (small cleanups/fixes) +Matt Domsch (revision ioctl, adapter messages) + +Original Driver +------------------------- +Adaptec Unix OEM Product Group + +Mailing List +------------------------- +None currently. Also note this is very different to Brian's original driver +so don't expect him to support it. + +Original by Brian Boerner February 2001 +Rewritten by Alan Cox, November 2001 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aacraid/TODO linux-2.5/drivers/scsi/aacraid/TODO --- linux-2.5.5/drivers/scsi/aacraid/TODO Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/TODO Thu Dec 13 16:32:36 2001 @@ -0,0 +1,4 @@ +o Testing +o More testing +o Feature request: display the firmware/bios/etc revisions in the + /proc info diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aacraid/aachba.c linux-2.5/drivers/scsi/aacraid/aachba.c --- linux-2.5.5/drivers/scsi/aacraid/aachba.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/aachba.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,1155 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define MAJOR_NR SCSI_DISK0_MAJOR /* For DEVICE_NR() */ +#include +#include "scsi.h" +#include "hosts.h" +#include "sd.h" + +#include "aacraid.h" + +/* SCSI Commands */ +#define SS_TEST 0x00 /* Test unit ready */ +#define SS_REZERO 0x01 /* Rezero unit */ +#define SS_REQSEN 0x03 /* Request Sense */ +#define SS_REASGN 0x07 /* Reassign blocks */ +#define SS_READ 0x08 /* Read 6 */ +#define SS_WRITE 0x0A /* Write 6 */ +#define SS_INQUIR 0x12 /* inquiry */ +#define SS_ST_SP 0x1B /* Start/Stop unit */ +#define SS_LOCK 0x1E /* prevent/allow medium removal */ +#define SS_RESERV 0x16 /* Reserve */ +#define SS_RELES 0x17 /* Release */ +#define SS_MODESEN 0x1A /* Mode Sense 6 */ +#define SS_RDCAP 0x25 /* Read Capacity */ +#define SM_READ 0x28 /* Read 10 */ +#define SM_WRITE 0x2A /* Write 10 */ +#define SS_SEEK 0x2B /* Seek */ + +/* values for inqd_pdt: Peripheral device type in plain English */ +#define INQD_PDT_DA 0x00 /* Direct-access (DISK) device */ +#define INQD_PDT_PROC 0x03 /* Processor device */ +#define INQD_PDT_CHNGR 0x08 /* Changer (jukebox, scsi2) */ +#define INQD_PDT_COMM 0x09 /* Communication device (scsi2) */ +#define INQD_PDT_NOLUN2 0x1f /* Unknown Device (scsi2) */ +#define INQD_PDT_NOLUN 0x7f /* Logical Unit Not Present */ + +#define INQD_PDT_DMASK 0x1F /* Peripheral Device Type Mask */ +#define INQD_PDT_QMASK 0xE0 /* Peripheral Device Qualifer Mask */ + +#define TARGET_LUN_TO_CONTAINER(target, lun) (((lun) << 4) | target) +#define CONTAINER_TO_TARGET(cont) ((cont) & 0xf) +#define CONTAINER_TO_LUN(cont) ((cont) >> 4) + +#define MAX_FIB_DATA (sizeof(struct hw_fib) - sizeof(FIB_HEADER)) + +#define MAX_DRIVER_SG_SEGMENT_COUNT 17 + +/* + * Sense keys + */ +#define SENKEY_NO_SENSE 0x00 +#define SENKEY_UNDEFINED 0x01 +#define SENKEY_NOT_READY 0x02 +#define SENKEY_MEDIUM_ERR 0x03 +#define SENKEY_HW_ERR 0x04 +#define SENKEY_ILLEGAL 0x05 +#define SENKEY_ATTENTION 0x06 +#define SENKEY_PROTECTED 0x07 +#define SENKEY_BLANK 0x08 +#define SENKEY_V_UNIQUE 0x09 +#define SENKEY_CPY_ABORT 0x0A +#define SENKEY_ABORT 0x0B +#define SENKEY_EQUAL 0x0C +#define SENKEY_VOL_OVERFLOW 0x0D +#define SENKEY_MISCOMP 0x0E +#define SENKEY_RESERVED 0x0F + +/* + * Sense codes + */ + +#define SENCODE_NO_SENSE 0x00 +#define SENCODE_END_OF_DATA 0x00 +#define SENCODE_BECOMING_READY 0x04 +#define SENCODE_INIT_CMD_REQUIRED 0x04 +#define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A +#define SENCODE_INVALID_COMMAND 0x20 +#define SENCODE_LBA_OUT_OF_RANGE 0x21 +#define SENCODE_INVALID_CDB_FIELD 0x24 +#define SENCODE_LUN_NOT_SUPPORTED 0x25 +#define SENCODE_INVALID_PARAM_FIELD 0x26 +#define SENCODE_PARAM_NOT_SUPPORTED 0x26 +#define SENCODE_PARAM_VALUE_INVALID 0x26 +#define SENCODE_RESET_OCCURRED 0x29 +#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E +#define SENCODE_INQUIRY_DATA_CHANGED 0x3F +#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39 +#define SENCODE_DIAGNOSTIC_FAILURE 0x40 +#define SENCODE_INTERNAL_TARGET_FAILURE 0x44 +#define SENCODE_INVALID_MESSAGE_ERROR 0x49 +#define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c +#define SENCODE_OVERLAPPED_COMMAND 0x4E + +/* + * Additional sense codes + */ + +#define ASENCODE_NO_SENSE 0x00 +#define ASENCODE_END_OF_DATA 0x05 +#define ASENCODE_BECOMING_READY 0x01 +#define ASENCODE_INIT_CMD_REQUIRED 0x02 +#define ASENCODE_PARAM_LIST_LENGTH_ERROR 0x00 +#define ASENCODE_INVALID_COMMAND 0x00 +#define ASENCODE_LBA_OUT_OF_RANGE 0x00 +#define ASENCODE_INVALID_CDB_FIELD 0x00 +#define ASENCODE_LUN_NOT_SUPPORTED 0x00 +#define ASENCODE_INVALID_PARAM_FIELD 0x00 +#define ASENCODE_PARAM_NOT_SUPPORTED 0x01 +#define ASENCODE_PARAM_VALUE_INVALID 0x02 +#define ASENCODE_RESET_OCCURRED 0x00 +#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x00 +#define ASENCODE_INQUIRY_DATA_CHANGED 0x03 +#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x00 +#define ASENCODE_DIAGNOSTIC_FAILURE 0x80 +#define ASENCODE_INTERNAL_TARGET_FAILURE 0x00 +#define ASENCODE_INVALID_MESSAGE_ERROR 0x00 +#define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00 +#define ASENCODE_OVERLAPPED_COMMAND 0x00 + +#define BYTE0(x) (unsigned char)(x) +#define BYTE1(x) (unsigned char)((x) >> 8) +#define BYTE2(x) (unsigned char)((x) >> 16) +#define BYTE3(x) (unsigned char)((x) >> 24) + +/*------------------------------------------------------------------------------ + * S T R U C T S / T Y P E D E F S + *----------------------------------------------------------------------------*/ +/* SCSI inquiry data */ +struct inquiry_data { + u8 inqd_pdt; /* Peripheral qualifier | Peripheral Device Type */ + u8 inqd_dtq; /* RMB | Device Type Qualifier */ + u8 inqd_ver; /* ISO version | ECMA version | ANSI-approved version */ + u8 inqd_rdf; /* AENC | TrmIOP | Response data format */ + u8 inqd_len; /* Additional length (n-4) */ + u8 inqd_pad1[2];/* Reserved - must be zero */ + u8 inqd_pad2; /* RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ + u8 inqd_vid[8]; /* Vendor ID */ + u8 inqd_pid[16];/* Product ID */ + u8 inqd_prl[4]; /* Product Revision Level */ +}; + +struct sense_data { + u8 error_code; /* 70h (current errors), 71h(deferred errors) */ + u8 valid:1; /* A valid bit of one indicates that the information */ + /* field contains valid information as defined in the + * SCSI-2 Standard. + */ + u8 segment_number; /* Only used for COPY, COMPARE, or COPY AND VERIFY Commands */ + u8 sense_key:4; /* Sense Key */ + u8 reserved:1; + u8 ILI:1; /* Incorrect Length Indicator */ + u8 EOM:1; /* End Of Medium - reserved for random access devices */ + u8 filemark:1; /* Filemark - reserved for random access devices */ + + u8 information[4]; /* for direct-access devices, contains the unsigned + * logical block address or residue associated with + * the sense key + */ + u8 add_sense_len; /* number of additional sense bytes to follow this field */ + u8 cmnd_info[4]; /* not used */ + u8 ASC; /* Additional Sense Code */ + u8 ASCQ; /* Additional Sense Code Qualifier */ + u8 FRUC; /* Field Replaceable Unit Code - not used */ + u8 bit_ptr:3; /* indicates which byte of the CDB or parameter data + * was in error + */ + u8 BPV:1; /* bit pointer valid (BPV): 1- indicates that + * the bit_ptr field has valid value + */ + u8 reserved2:2; + u8 CD:1; /* command data bit: 1- illegal parameter in CDB. + * 0- illegal parameter in data. + */ + u8 SKSV:1; + u8 field_ptr[2]; /* byte of the CDB or parameter data in error */ +}; + +/* + * M O D U L E G L O B A L S + */ + +static struct fsa_scsi_hba *fsa_dev[MAXIMUM_NUM_ADAPTERS]; /* SCSI Device Instance Pointers */ +static struct sense_data sense_data[MAXIMUM_NUM_CONTAINERS]; +static void get_sd_devname(int disknum, char *buffer); + +/** + * aac_get_containers - list containers + * @common: adapter to probe + * + * Make a list of all containers on this controller + */ +int aac_get_containers(struct aac_dev *dev) +{ + struct fsa_scsi_hba *fsa_dev_ptr; + int index, status = 0; + struct aac_query_mount *dinfo; + struct aac_mount *dresp; + struct fib * fibptr; + unsigned instance; + + fsa_dev_ptr = &(dev->fsa_dev); + instance = dev->scsi_host_ptr->unique_id; + + if (!(fibptr = fib_alloc(dev))) + return -ENOMEM; + + for (index = 0; index < MAXIMUM_NUM_CONTAINERS; index++) { + fib_init(fibptr); + dinfo = (struct aac_query_mount *) fib_data(fibptr); + + dinfo->command = cpu_to_le32(VM_NameServe); + dinfo->count = cpu_to_le32(index); + dinfo->type = cpu_to_le32(FT_FILESYS); + + status = fib_send(ContainerCommand, + fibptr, + sizeof (struct aac_query_mount), + FsaNormal, + 1, 1, + NULL, NULL); + if (status < 0 ) { + printk(KERN_WARNING "ProbeContainers: SendFIB failed.\n"); + break; + } + dresp = (struct aac_mount *)fib_data(fibptr); + + if ((le32_to_cpu(dresp->status) == ST_OK) && + (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) { + fsa_dev_ptr->valid[index] = 1; + fsa_dev_ptr->type[index] = le32_to_cpu(dresp->mnt[0].vol); + fsa_dev_ptr->size[index] = le32_to_cpu(dresp->mnt[0].capacity); + if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) + fsa_dev_ptr->ro[index] = 1; + } + fib_complete(fibptr); + /* + * If there are no more containers, then stop asking. + */ + if ((index + 1) >= le32_to_cpu(dresp->count)) + break; + } + fib_free(fibptr); + fsa_dev[instance] = fsa_dev_ptr; + return status; +} + +/** + * probe_container - query a logical volume + * @dev: device to query + * @cid: container identifier + * + * Queries the controller about the given volume. The volume information + * is updated in the struct fsa_scsi_hba structure rather than returned. + */ + +static int probe_container(struct aac_dev *dev, int cid) +{ + struct fsa_scsi_hba *fsa_dev_ptr; + int status; + struct aac_query_mount *dinfo; + struct aac_mount *dresp; + struct fib * fibptr; + unsigned instance; + + fsa_dev_ptr = &(dev->fsa_dev); + instance = dev->scsi_host_ptr->unique_id; + + if (!(fibptr = fib_alloc(dev))) + return -ENOMEM; + + fib_init(fibptr); + + dinfo = (struct aac_query_mount *)fib_data(fibptr); + + dinfo->command = cpu_to_le32(VM_NameServe); + dinfo->count = cpu_to_le32(cid); + dinfo->type = cpu_to_le32(FT_FILESYS); + + status = fib_send(ContainerCommand, + fibptr, + sizeof(struct aac_query_mount), + FsaNormal, + 1, 1, + NULL, NULL); + if (status < 0) { + printk(KERN_WARNING "aacraid: probe_containers query failed.\n"); + goto error; + } + + dresp = (struct aac_mount *) fib_data(fibptr); + + if ((le32_to_cpu(dresp->status) == ST_OK) && + (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) { + fsa_dev_ptr->valid[cid] = 1; + fsa_dev_ptr->type[cid] = le32_to_cpu(dresp->mnt[0].vol); + fsa_dev_ptr->size[cid] = le32_to_cpu(dresp->mnt[0].capacity); + if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) + fsa_dev_ptr->ro[cid] = 1; + } + +error: + fib_complete(fibptr); + fib_free(fibptr); + + return status; +} + +/* Local Structure to set SCSI inquiry data strings */ +struct scsi_inq { + char vid[8]; /* Vendor ID */ + char pid[16]; /* Product ID */ + char prl[4]; /* Product Revision Level */ +}; + +/** + * InqStrCopy - string merge + * @a: string to copy from + * @b: string to copy to + * + * Copy a String from one location to another + * without copying \0 + */ + +static void inqstrcpy(char *a, char *b) +{ + + while(*a != (char)0) + *b++ = *a++; +} + +static char *container_types[] = { + "None", + "Volume", + "Mirror", + "Stripe", + "RAID5", + "SSRW", + "SSRO", + "Morph", + "Legacy", + "RAID4", + "RAID10", + "RAID00", + "V-MIRRORS", + "PSEUDO R4", + "RAID50", + "Unknown" +}; + + + +/* Function: setinqstr + * + * Arguments: [1] pointer to void [1] int + * + * Purpose: Sets SCSI inquiry data strings for vendor, product + * and revision level. Allows strings to be set in platform dependant + * files instead of in OS dependant driver source. + */ + +static void setinqstr(int devtype, void *data, int tindex) +{ + struct scsi_inq *str; + char *findit; + struct aac_driver_ident *mp; + extern struct aac_driver_ident aac_drivers[]; /* HACK FIXME */ + + mp = &aac_drivers[devtype]; + + str = (struct scsi_inq *)(data); /* cast data to scsi inq block */ + + inqstrcpy (mp->vname, str->vid); + inqstrcpy (mp->model, str->pid); /* last six chars reserved for vol type */ + + findit = str->pid; + + for ( ; *findit != ' '; findit++); /* walk till we find a space then incr by 1 */ + findit++; + + if (tindex < (sizeof(container_types)/sizeof(char *))){ + inqstrcpy (container_types[tindex], findit); + } + inqstrcpy ("0001", str->prl); +} + +void set_sense(char *sense_buf, u8 sense_key, u8 sense_code, + u8 a_sense_code, u8 incorrect_length, + u8 bit_pointer, unsigned field_pointer, + unsigned long residue) +{ + sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */ + sense_buf[1] = 0; /* Segment number, always zero */ + + if (incorrect_length) { + sense_buf[2] = sense_key | 0x20; /* Set the ILI bit | sense key */ + sense_buf[3] = BYTE3(residue); + sense_buf[4] = BYTE2(residue); + sense_buf[5] = BYTE1(residue); + sense_buf[6] = BYTE0(residue); + } else + sense_buf[2] = sense_key; /* Sense key */ + + if (sense_key == SENKEY_ILLEGAL) + sense_buf[7] = 10; /* Additional sense length */ + else + sense_buf[7] = 6; /* Additional sense length */ + + sense_buf[12] = sense_code; /* Additional sense code */ + sense_buf[13] = a_sense_code; /* Additional sense code qualifier */ + if (sense_key == SENKEY_ILLEGAL) { + sense_buf[15] = 0; + + if (sense_code == SENCODE_INVALID_PARAM_FIELD) + sense_buf[15] = 0x80; /* Std sense key specific field */ + /* Illegal parameter is in the parameter block */ + + if (sense_code == SENCODE_INVALID_CDB_FIELD) + sense_buf[15] = 0xc0; /* Std sense key specific field */ + /* Illegal parameter is in the CDB block */ + sense_buf[15] |= bit_pointer; + sense_buf[16] = field_pointer >> 8; /* MSB */ + sense_buf[17] = field_pointer; /* LSB */ + } +} + +static void aac_io_done(Scsi_Cmnd * scsicmd) +{ + unsigned long cpu_flags; + spin_lock_irqsave(&io_request_lock, cpu_flags); + scsicmd->scsi_done(scsicmd); + spin_unlock_irqrestore(&io_request_lock, cpu_flags); +} + +static void __aac_io_done(Scsi_Cmnd * scsicmd) +{ + scsicmd->scsi_done(scsicmd); +} + +static void read_callback(void *context, struct fib * fibptr) +{ + struct aac_dev *dev; + struct aac_read_reply *readreply; + Scsi_Cmnd *scsicmd; + unsigned long lba; + int cid; + + scsicmd = (Scsi_Cmnd *) context; + + dev = (struct aac_dev *)scsicmd->host->hostdata; + cid =TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun); + + lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; + dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %ld, t = %ld.\n", smp_processor_id(), lba, jiffies)); + + if (fibptr == NULL) + BUG(); + + if(scsicmd->use_sg) + pci_unmap_sg(dev->pdev, + (struct scatterlist *)scsicmd->buffer, + scsicmd->use_sg, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + else if(scsicmd->request_bufflen) + pci_unmap_single(dev->pdev, (dma_addr_t)(long)scsicmd->SCp.ptr, + scsicmd->request_bufflen, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + readreply = (struct aac_read_reply *)fib_data(fibptr); + if (le32_to_cpu(readreply->status) == ST_OK) + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + else { + printk(KERN_WARNING "read_callback: read failed, status = %d\n", readreply->status); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + set_sense((char *) &sense_data[cid], + SENKEY_HW_ERR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); + } + fib_complete(fibptr); + fib_free(fibptr); + + aac_io_done(scsicmd); +} + +static void write_callback(void *context, struct fib * fibptr) +{ + struct aac_dev *dev; + struct aac_write_reply *writereply; + Scsi_Cmnd *scsicmd; + unsigned long lba; + int cid; + + scsicmd = (Scsi_Cmnd *) context; + dev = (struct aac_dev *)scsicmd->host->hostdata; + cid = TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun); + + lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; + dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %ld, t = %ld.\n", smp_processor_id(), lba, jiffies)); + if (fibptr == NULL) + BUG(); + + if(scsicmd->use_sg) + pci_unmap_sg(dev->pdev, + (struct scatterlist *)scsicmd->buffer, + scsicmd->use_sg, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + else if(scsicmd->request_bufflen) + pci_unmap_single(dev->pdev, (dma_addr_t)(long)scsicmd->SCp.ptr, + scsicmd->request_bufflen, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + + writereply = (struct aac_write_reply *) fib_data(fibptr); + if (le32_to_cpu(writereply->status) == ST_OK) + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + else { + printk(KERN_WARNING "write_callback: write failed, status = %d\n", writereply->status); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + set_sense((char *) &sense_data[cid], + SENKEY_HW_ERR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); + } + + fib_complete(fibptr); + fib_free(fibptr); + aac_io_done(scsicmd); +} + +int aac_read(Scsi_Cmnd * scsicmd, int cid) +{ + unsigned long lba; + unsigned long count; + unsigned long byte_count = 0; + int status; + + struct aac_read *readcmd; + u16 fibsize; + struct aac_dev *dev; + struct fib * cmd_fibcontext; + + dev = (struct aac_dev *)scsicmd->host->hostdata; + /* + * Get block address and transfer length + */ + if (scsicmd->cmnd[0] == SS_READ) /* 6 byte command */ + { + dprintk((KERN_DEBUG "aachba: received a read(6) command on target %d.\n", cid)); + + lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; + count = scsicmd->cmnd[4]; + + if (count == 0) + count = 256; + } else { + dprintk((KERN_DEBUG "aachba: received a read(10) command on target %d.\n", cid)); + + lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; + count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; + } + dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %lu, t = %ld.\n", smp_processor_id(), lba, jiffies)); + /* + * Alocate and initialize a Fib + */ + if (!(cmd_fibcontext = fib_alloc(dev))) { + scsicmd->result = DID_ERROR << 16; + aac_io_done(scsicmd); + return (-1); + } + + fib_init(cmd_fibcontext); + + readcmd = (struct aac_read *) fib_data(cmd_fibcontext); + readcmd->command = cpu_to_le32(VM_CtBlockRead); + readcmd->cid = cpu_to_le32(cid); + readcmd->block = cpu_to_le32(lba); + readcmd->count = cpu_to_le32(count * 512); + readcmd->sg.count = cpu_to_le32(1); + + if (count * 512 > (64 * 1024)) + BUG(); + /* + * Build Scatter/Gather list + */ + if (scsicmd->use_sg) /* use scatter/gather list */ + { + struct scatterlist *sg; + int i; + int sg_count; + + sg = (struct scatterlist *) scsicmd->request_buffer; + + sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + + byte_count = 0; + + for (i = 0; i < sg_count; i++) { + readcmd->sg.sg[i].addr = cpu_to_le32(sg_dma_address(sg)); + readcmd->sg.sg[i].count = cpu_to_le32(sg_dma_len(sg)); + byte_count += sg->length; + if (sg->length > (64 * 1024)) + BUG(); + sg++; + } + readcmd->sg.count = cpu_to_le32(sg_count); + + if (sg_count > MAX_DRIVER_SG_SEGMENT_COUNT) + BUG(); + } + else if(scsicmd->request_bufflen) + { + dma_addr_t addr; + addr = pci_map_single(dev->pdev, scsicmd->request_buffer, + scsicmd->request_bufflen, scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + scsicmd->SCp.ptr = (void *)(long)addr; + readcmd->sg.sg[0].addr = cpu_to_le32(addr); + readcmd->sg.sg[0].count = cpu_to_le32(scsicmd->request_bufflen); + + byte_count = scsicmd->request_bufflen; + + if (byte_count > (64 * 1024)) + BUG(); + } + if (byte_count != readcmd->count) + BUG(); + /* + * Now send the Fib to the adapter + */ + fibsize = sizeof(struct aac_read) + ((readcmd->sg.count - 1) * sizeof (struct sgentry)); + status = fib_send(ContainerCommand, + cmd_fibcontext, + fibsize, + FsaNormal, + 0, 1, + (fib_callback) read_callback, + (void *) scsicmd); + /* + * Check that the command queued to the controller + */ + if (status == -EINPROGRESS) + return 0; + + printk(KERN_WARNING "aac_read: fib_send failed with status: %d.\n", status); + /* + * For some reason, the Fib didn't queue, return QUEUE_FULL + */ + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL; + aac_io_done(scsicmd); + fib_complete(cmd_fibcontext); + fib_free(cmd_fibcontext); + return -1; +} + +static int aac_write(Scsi_Cmnd * scsicmd, int cid) +{ + unsigned long lba; + unsigned long count; + unsigned long byte_count = 0; + int status; + struct aac_write *writecmd; + u16 fibsize; + struct aac_dev *dev; + struct fib * cmd_fibcontext; + + dev = (struct aac_dev *)scsicmd->host->hostdata; + /* + * Get block address and transfer length + */ + if (scsicmd->cmnd[0] == SS_WRITE) /* 6 byte command */ + { + lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; + count = scsicmd->cmnd[4]; + if (count == 0) + count = 256; + } else { + dprintk((KERN_DEBUG "aachba: received a write(10) command on target %d.\n", cid)); + lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; + count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; + } + dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %lu, t = %ld.\n", smp_processor_id(), lba, jiffies)); + /* + * Allocate and initialize a Fib then setup a BlockWrite command + */ + if (!(cmd_fibcontext = fib_alloc(dev))) { + scsicmd->result = DID_ERROR << 16; + aac_io_done(scsicmd); + return -1; + } + fib_init(cmd_fibcontext); + + writecmd = (struct aac_write *) fib_data(cmd_fibcontext); + writecmd->command = cpu_to_le32(VM_CtBlockWrite); + writecmd->cid = cpu_to_le32(cid); + writecmd->block = cpu_to_le32(lba); + writecmd->count = cpu_to_le32(count * 512); + writecmd->sg.count = cpu_to_le32(1); + /* FIXME: why isnt ->stable setup */ + + if (count * 512 > (64 * 1024)) { + BUG(); + } + /* + * Build Scatter/Gather list + */ + if (scsicmd->use_sg) + { + struct scatterlist *sg; + int i; + int sg_count; + + sg = (struct scatterlist *) scsicmd->request_buffer; + + sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + + byte_count = 0; + + for (i = 0; i < scsicmd->use_sg; i++) { + writecmd->sg.sg[i].addr = cpu_to_le32(sg_dma_address(sg)); + writecmd->sg.sg[i].count = cpu_to_le32(sg_dma_len(sg)); + byte_count += sg->length; + + if (sg->length > (64 * 1024)) + BUG(); + sg++; + } + writecmd->sg.count = cpu_to_le32(sg_count); + + if (sg_count > MAX_DRIVER_SG_SEGMENT_COUNT) + BUG(); + } + else if(scsicmd->request_bufflen) + { + dma_addr_t addr; + addr = pci_map_single(dev->pdev, + scsicmd->request_buffer, + scsicmd->request_bufflen, + scsi_to_pci_dma_dir(scsicmd->sc_data_direction)); + writecmd->sg.sg[0].addr = cpu_to_le32(addr); + writecmd->sg.sg[0].count = cpu_to_le32(scsicmd->request_bufflen); + scsicmd->SCp.ptr = (void *)(long)addr; + byte_count = scsicmd->request_bufflen; + + if (byte_count > (64 * 1024)) + BUG(); + } + if (byte_count != writecmd->count) + BUG(); + /* + * Now send the Fib to the adapter + */ + fibsize = sizeof (struct aac_write) + ((writecmd->sg.count - 1) * sizeof (struct sgentry)); + + status = fib_send(ContainerCommand, + cmd_fibcontext, + fibsize, FsaNormal, + 0, 1, + (fib_callback) write_callback, + (void *) scsicmd); + /* + * Check that the command queued to the controller + */ + if (status == -EINPROGRESS) + return 0; + + printk(KERN_WARNING "aac_write: fib_send failed with status: %d\n", status); + /* + * For some reason, the Fib didn't queue, return QUEUE_FULL + */ + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | QUEUE_FULL; + aac_io_done(scsicmd); + + fib_complete(cmd_fibcontext); + fib_free(cmd_fibcontext); + return -1; +} + + +/** + * aac_scsi_cmd() - Process SCSI command + * @scsicmd: SCSI command block + * @wait: 1 if the user wants to await completion + * + * Emulate a SCSI command and queue the required request for the + * aacraid firmware. + */ + +int aac_scsi_cmd(Scsi_Cmnd * scsicmd) +{ + int cid = 0; + struct fsa_scsi_hba *fsa_dev_ptr; + int cardtype; + int ret; + struct aac_dev *dev = (struct aac_dev *)scsicmd->host->hostdata; + + cardtype = dev->cardtype; + + fsa_dev_ptr = fsa_dev[scsicmd->host->unique_id]; + + /* + * If the bus, target or lun is out of range, return fail + * Test does not apply to ID 16, the pseudo id for the controller + * itself. + */ + if (scsicmd->target != scsicmd->host->this_id) { + if ((scsicmd->channel > 0) ||(scsicmd->target > 15) || (scsicmd->lun > 7)) + { + dprintk((KERN_DEBUG "The bus, target or lun is out of range = %d, %d, %d.\n", + scsicmd->channel, scsicmd->target, scsicmd->lun)); + scsicmd->result = DID_BAD_TARGET << 16; + __aac_io_done(scsicmd); + return -1; + } + cid = TARGET_LUN_TO_CONTAINER(scsicmd->target, scsicmd->lun); + /* + * If the target container doesn't exist, it may have + * been newly created + */ + if (fsa_dev_ptr->valid[cid] == 0) { + switch (scsicmd->cmnd[0]) { + case SS_INQUIR: + case SS_RDCAP: + case SS_TEST: + spin_unlock_irq(&io_request_lock); + probe_container(dev, cid); + spin_lock_irq(&io_request_lock); + default: + break; + } + } + /* + * If the target container still doesn't exist, + * return failure + */ + if (fsa_dev_ptr->valid[cid] == 0) { + scsicmd->result = DID_BAD_TARGET << 16; + __aac_io_done(scsicmd); + return -1; + } + } + else if ((scsicmd->cmnd[0] != SS_INQUIR) && /* only INQUIRY & TUR cmnd supported for controller */ + (scsicmd->cmnd[0] != SS_TEST)) + { + /* + * Command aimed at the controller + */ + dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0])); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + set_sense((char *) &sense_data[cid], + SENKEY_ILLEGAL, + SENCODE_INVALID_COMMAND, + ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); + __aac_io_done(scsicmd); + return -1; + } + /* Handle commands here that don't really require going out to the adapter */ + switch (scsicmd->cmnd[0]) + { + case SS_INQUIR: + { + struct inquiry_data *inq_data_ptr; + + dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->target)); + inq_data_ptr = (struct inquiry_data *)scsicmd->request_buffer; + memset(inq_data_ptr, 0, sizeof (struct inquiry_data)); + + inq_data_ptr->inqd_ver = 2; /* claim compliance to SCSI-2 */ + inq_data_ptr->inqd_dtq = 0x80; /* set RMB bit to one indicating that the medium is removable */ + inq_data_ptr->inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */ + inq_data_ptr->inqd_len = 31; + + /* + * Set the Vendor, Product, and Revision Level + * see: .c i.e. aac.c + */ + setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr->type[cid]); + if (scsicmd->target == scsicmd->host->this_id) + inq_data_ptr->inqd_pdt = INQD_PDT_PROC; /* Processor device */ + else + inq_data_ptr->inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + return 0; + } + case SS_RDCAP: + { + int capacity; + char *cp; + + dprintk((KERN_DEBUG "READ CAPACITY command.\n")); + capacity = fsa_dev_ptr->size[cid] - 1; + cp = scsicmd->request_buffer; + cp[0] = (capacity >> 24) & 0xff; + cp[1] = (capacity >> 16) & 0xff; + cp[2] = (capacity >> 8) & 0xff; + cp[3] = (capacity >> 0) & 0xff; + cp[4] = 0; + cp[5] = 0; + cp[6] = 2; + cp[7] = 0; + + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + + return 0; + } + + case SS_MODESEN: + { + char *mode_buf; + + dprintk((KERN_DEBUG "MODE SENSE command.\n")); + mode_buf = scsicmd->request_buffer; + mode_buf[0] = 0; /* Mode data length (MSB) */ + mode_buf[1] = 6; /* Mode data length (LSB) */ + mode_buf[2] = 0; /* Medium type - default */ + mode_buf[3] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected */ + mode_buf[4] = 0; /* reserved */ + mode_buf[5] = 0; /* reserved */ + mode_buf[6] = 0; /* Block descriptor length (MSB) */ + mode_buf[7] = 0; /* Block descriptor length (LSB) */ + + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + + return 0; + } + case SS_REQSEN: + dprintk((KERN_DEBUG "REQUEST SENSE command.\n")); + memcpy(scsicmd->sense_buffer, &sense_data[cid], sizeof (struct sense_data)); + memset(&sense_data[cid], 0, sizeof (struct sense_data)); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + return (0); + + case SS_LOCK: + dprintk((KERN_DEBUG "LOCK command.\n")); + if (scsicmd->cmnd[4]) + fsa_dev_ptr->locked[cid] = 1; + else + fsa_dev_ptr->locked[cid] = 0; + + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + return 0; + /* + * These commands are all No-Ops + */ + case SS_TEST: + case SS_RESERV: + case SS_RELES: + case SS_REZERO: + case SS_REASGN: + case SS_SEEK: + case SS_ST_SP: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + __aac_io_done(scsicmd); + return (0); + } + + switch (scsicmd->cmnd[0]) + { + case SS_READ: + case SM_READ: + /* + * Hack to keep track of ordinal number of the device that + * corresponds to a container. Needed to convert + * containers to /dev/sd device names + */ + + spin_unlock_irq(&io_request_lock); + fsa_dev_ptr->devno[cid] = DEVICE_NR(scsicmd->request.rq_dev); + ret = aac_read(scsicmd, cid); + spin_lock_irq(&io_request_lock); + return ret; + + case SS_WRITE: + case SM_WRITE: + spin_unlock_irq(&io_request_lock); + ret = aac_write(scsicmd, cid); + spin_lock_irq(&io_request_lock); + return ret; + default: + /* + * Unhandled commands + */ + printk(KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + set_sense((char *) &sense_data[cid], + SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND, + ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); + __aac_io_done(scsicmd); + return -1; + } +} + +static int query_disk(struct aac_dev *dev, void *arg) +{ + struct aac_query_disk qd; + struct fsa_scsi_hba *fsa_dev_ptr; + + fsa_dev_ptr = &(dev->fsa_dev); + if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk))) + return -EFAULT; + if (qd.cnum == -1) + qd.cnum = TARGET_LUN_TO_CONTAINER(qd.target, qd.lun); + else if ((qd.bus == -1) && (qd.target == -1) && (qd.lun == -1)) + { + if (qd.cnum < 0 || qd.cnum > MAXIMUM_NUM_CONTAINERS) + return -EINVAL; + qd.instance = dev->scsi_host_ptr->host_no; + qd.bus = 0; + qd.target = CONTAINER_TO_TARGET(qd.cnum); + qd.lun = CONTAINER_TO_LUN(qd.cnum); + } + else return -EINVAL; + + qd.valid = fsa_dev_ptr->valid[qd.cnum]; + qd.locked = fsa_dev_ptr->locked[qd.cnum]; + qd.deleted = fsa_dev_ptr->deleted[qd.cnum]; + + if (fsa_dev_ptr->devno[qd.cnum] == -1) + qd.unmapped = 1; + else + qd.unmapped = 0; + + get_sd_devname(fsa_dev_ptr->devno[qd.cnum], qd.name); + + if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk))) + return -EFAULT; + return 0; +} + +static void get_sd_devname(int disknum, char *buffer) +{ + if (disknum < 0) { + sprintf(buffer, "%s", ""); + return; + } + + if (disknum < 26) + sprintf(buffer, "sd%c", 'a' + disknum); + else { + unsigned int min1; + unsigned int min2; + /* + * For larger numbers of disks, we need to go to a new + * naming scheme. + */ + min1 = disknum / 26; + min2 = disknum % 26; + sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2); + } +} + +static int force_delete_disk(struct aac_dev *dev, void *arg) +{ + struct aac_delete_disk dd; + struct fsa_scsi_hba *fsa_dev_ptr; + + fsa_dev_ptr = &(dev->fsa_dev); + + if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk))) + return -EFAULT; + + if (dd.cnum > MAXIMUM_NUM_CONTAINERS) + return -EINVAL; + /* + * Mark this container as being deleted. + */ + fsa_dev_ptr->deleted[dd.cnum] = 1; + /* + * Mark the container as no longer valid + */ + fsa_dev_ptr->valid[dd.cnum] = 0; + return 0; +} + +static int delete_disk(struct aac_dev *dev, void *arg) +{ + struct aac_delete_disk dd; + struct fsa_scsi_hba *fsa_dev_ptr; + + fsa_dev_ptr = &(dev->fsa_dev); + + if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk))) + return -EFAULT; + + if (dd.cnum > MAXIMUM_NUM_CONTAINERS) + return -EINVAL; + /* + * If the container is locked, it can not be deleted by the API. + */ + if (fsa_dev_ptr->locked[dd.cnum]) + return -EBUSY; + else { + /* + * Mark the container as no longer being valid. + */ + fsa_dev_ptr->valid[dd.cnum] = 0; + fsa_dev_ptr->devno[dd.cnum] = -1; + return 0; + } +} + +int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg) +{ + switch (cmd) { + case FSACTL_QUERY_DISK: + return query_disk(dev, arg); + case FSACTL_DELETE_DISK: + return delete_disk(dev, arg); + case FSACTL_FORCE_DELETE_DISK: + return force_delete_disk(dev, arg); + case 2131: + return aac_get_containers(dev); + default: + return -ENOTTY; + } +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aacraid/aacraid.h linux-2.5/drivers/scsi/aacraid/aacraid.h --- linux-2.5.5/drivers/scsi/aacraid/aacraid.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/aacraid.h Sun Mar 3 17:54:35 2002 @@ -0,0 +1,1208 @@ +#define dprintk(x) + +#define AAC_NUM_FIB 128 +#define AAC_NUM_IO_FIB 116 + +/*------------------------------------------------------------------------------ + * D E F I N E S + *----------------------------------------------------------------------------*/ + +struct diskparm +{ + int heads; + int sectors; + int cylinders; +}; + + +/* + * DON'T CHANGE THE ORDER, this is set by the firmware + */ + +#define CT_NONE 0 +#define CT_VOLUME 1 +#define CT_MIRROR 2 +#define CT_STRIPE 3 +#define CT_RAID5 4 +#define CT_SSRW 5 +#define CT_SSRO 6 +#define CT_MORPH 7 +#define CT_PASSTHRU 8 +#define CT_RAID4 9 +#define CT_RAID10 10 /* stripe of mirror */ +#define CT_RAID00 11 /* stripe of stripe */ +#define CT_VOLUME_OF_MIRRORS 12 /* volume of mirror */ +#define CT_PSEUDO_RAID 13 /* really raid4 */ +#define CT_LAST_VOLUME_TYPE 14 + +/* + * Types of objects addressable in some fashion by the client. + * This is a superset of those objects handled just by the filesystem + * and includes "raw" objects that an administrator would use to + * configure containers and filesystems. + */ + +#define FT_REG 1 /* regular file */ +#define FT_DIR 2 /* directory */ +#define FT_BLK 3 /* "block" device - reserved */ +#define FT_CHR 4 /* "character special" device - reserved */ +#define FT_LNK 5 /* symbolic link */ +#define FT_SOCK 6 /* socket */ +#define FT_FIFO 7 /* fifo */ +#define FT_FILESYS 8 /* ADAPTEC's "FSA"(tm) filesystem */ +#define FT_DRIVE 9 /* physical disk - addressable in scsi by bus/target/lun */ +#define FT_SLICE 10 /* virtual disk - raw volume - slice */ +#define FT_PARTITION 11 /* FSA partition - carved out of a slice - building block for containers */ +#define FT_VOLUME 12 /* Container - Volume Set */ +#define FT_STRIPE 13 /* Container - Stripe Set */ +#define FT_MIRROR 14 /* Container - Mirror Set */ +#define FT_RAID5 15 /* Container - Raid 5 Set */ +#define FT_DATABASE 16 /* Storage object with "foreign" content manager */ + +/* + * Host side memory scatter gather list + * Used by the adapter for read, write, and readdirplus operations + */ + +struct sgentry { + u32 addr; /* 32-bit Base address. */ + u32 count; /* Length. */ +}; + +/* + * SGMAP + * + * This is the SGMAP structure for all commands that use + * 32-bit addressing. + * + * Note that the upper 16 bits of SgCount are used as flags. + * Only the lower 16 bits of SgCount are actually used as the + * SG element count. + */ + +struct sgmap { + u32 count; + struct sgentry sg[1]; +}; + +struct creation_info +{ + u8 buildnum; /* e.g., 588 */ + u8 usec; /* e.g., 588 */ + u8 via; /* e.g., 1 = FSU, + * 2 = API + */ + u8 year; /* e.g., 1997 = 97 */ + u32 date; /* + * unsigned Month :4; // 1 - 12 + * unsigned Day :6; // 1 - 32 + * unsigned Hour :6; // 0 - 23 + * unsigned Minute :6; // 0 - 60 + * unsigned Second :6; // 0 - 60 + */ + u64 serial; /* e.g., 0x1DEADB0BFAFAF001 */ +}; + + +/* + * Define all the constants needed for the communication interface + */ + +/* + * Define how many queue entries each queue will have and the total + * number of entries for the entire communication interface. Also define + * how many queues we support. + * + * This has to match the controller + */ + +#define NUMBER_OF_COMM_QUEUES 8 // 4 command; 4 response +#define HOST_HIGH_CMD_ENTRIES 4 +#define HOST_NORM_CMD_ENTRIES 8 +#define ADAP_HIGH_CMD_ENTRIES 4 +#define ADAP_NORM_CMD_ENTRIES 512 +#define HOST_HIGH_RESP_ENTRIES 4 +#define HOST_NORM_RESP_ENTRIES 512 +#define ADAP_HIGH_RESP_ENTRIES 4 +#define ADAP_NORM_RESP_ENTRIES 8 + +#define TOTAL_QUEUE_ENTRIES \ + (HOST_NORM_CMD_ENTRIES + HOST_HIGH_CMD_ENTRIES + ADAP_NORM_CMD_ENTRIES + ADAP_HIGH_CMD_ENTRIES + \ + HOST_NORM_RESP_ENTRIES + HOST_HIGH_RESP_ENTRIES + ADAP_NORM_RESP_ENTRIES + ADAP_HIGH_RESP_ENTRIES) + + +/* + * Set the queues on a 16 byte alignment + */ + +#define QUEUE_ALIGNMENT 16 + +/* + * The queue headers define the Communication Region queues. These + * are physically contiguous and accessible by both the adapter and the + * host. Even though all queue headers are in the same contiguous block + * they will be represented as individual units in the data structures. + */ + +struct aac_entry { + u32 size; /* Size in bytes of the Fib which this QE points to */ + u32 addr; /* Receiver addressable address of the FIB (low 32 address bits) */ +}; + +/* + * The adapter assumes the ProducerIndex and ConsumerIndex are grouped + * adjacently and in that order. + */ + +struct aac_qhdr { + u64 header_addr; /* Address to hand the adapter to access to this queue head */ + u32 *producer; /* The producer index for this queue (host address) */ + u32 *consumer; /* The consumer index for this queue (host address) */ +}; + +/* + * Define all the events which the adapter would like to notify + * the host of. + */ + +#define HostNormCmdQue 1 /* Change in host normal priority command queue */ +#define HostHighCmdQue 2 /* Change in host high priority command queue */ +#define HostNormRespQue 3 /* Change in host normal priority response queue */ +#define HostHighRespQue 4 /* Change in host high priority response queue */ +#define AdapNormRespNotFull 5 +#define AdapHighRespNotFull 6 +#define AdapNormCmdNotFull 7 +#define AdapHighCmdNotFull 8 +#define SynchCommandComplete 9 +#define AdapInternalError 0xfe /* The adapter detected an internal error shutting down */ + +/* + * Define all the events the host wishes to notify the + * adapter of. The first four values much match the Qid the + * corresponding queue. + */ + +#define AdapNormCmdQue 2 +#define AdapHighCmdQue 3 +#define AdapNormRespQue 6 +#define AdapHighRespQue 7 +#define HostShutdown 8 +#define HostPowerFail 9 +#define FatalCommError 10 +#define HostNormRespNotFull 11 +#define HostHighRespNotFull 12 +#define HostNormCmdNotFull 13 +#define HostHighCmdNotFull 14 +#define FastIo 15 +#define AdapPrintfDone 16 + +/* + * Define all the queues that the adapter and host use to communicate + * Number them to match the physical queue layout. + */ + +enum aac_queue_types { + HostNormCmdQueue = 0, /* Adapter to host normal priority command traffic */ + HostHighCmdQueue, /* Adapter to host high priority command traffic */ + AdapNormCmdQueue, /* Host to adapter normal priority command traffic */ + AdapHighCmdQueue, /* Host to adapter high priority command traffic */ + HostNormRespQueue, /* Adapter to host normal priority response traffic */ + HostHighRespQueue, /* Adapter to host high priority response traffic */ + AdapNormRespQueue, /* Host to adapter normal priority response traffic */ + AdapHighRespQueue /* Host to adapter high priority response traffic */ +}; + +/* + * Assign type values to the FSA communication data structures + */ + +#define FIB_MAGIC 0x0001 + +/* + * Define the priority levels the FSA communication routines support. + */ + +#define FsaNormal 1 +#define FsaHigh 2 + +// +// Define the FIB. The FIB is the where all the requested data and +// command information are put to the application on the FSA adapter. +// + +struct aac_fibhdr { + u32 XferState; // Current transfer state for this CCB + u16 Command; // Routing information for the destination + u8 StructType; // Type FIB + u8 Flags; // Flags for FIB + u16 Size; // Size of this FIB in bytes + u16 SenderSize; // Size of the FIB in the sender (for response sizing) + u32 SenderFibAddress; // Host defined data in the FIB + u32 ReceiverFibAddress; // Logical address of this FIB for the adapter + u32 SenderData; // Place holder for the sender to store data + union { + struct { + u32 _ReceiverTimeStart; // Timestamp for receipt of fib + u32 _ReceiverTimeDone; // Timestamp for completion of fib + } _s; + struct list_head _FibLinks; // Used to link Adapter Initiated Fibs on the host + } _u; +}; + +#define FibLinks _u._FibLinks + +#define FIB_DATA_SIZE_IN_BYTES (512 - sizeof(struct aac_fibhdr)) + + +struct hw_fib { + struct aac_fibhdr header; + u8 data[FIB_DATA_SIZE_IN_BYTES]; // Command specific data +}; + +/* + * FIB commands + */ + +#define TestCommandResponse 1 +#define TestAdapterCommand 2 +/* + * Lowlevel and comm commands + */ +#define LastTestCommand 100 +#define ReinitHostNormCommandQueue 101 +#define ReinitHostHighCommandQueue 102 +#define ReinitHostHighRespQueue 103 +#define ReinitHostNormRespQueue 104 +#define ReinitAdapNormCommandQueue 105 +#define ReinitAdapHighCommandQueue 107 +#define ReinitAdapHighRespQueue 108 +#define ReinitAdapNormRespQueue 109 +#define InterfaceShutdown 110 +#define DmaCommandFib 120 +#define StartProfile 121 +#define TermProfile 122 +#define SpeedTest 123 +#define TakeABreakPt 124 +#define RequestPerfData 125 +#define SetInterruptDefTimer 126 +#define SetInterruptDefCount 127 +#define GetInterruptDefStatus 128 +#define LastCommCommand 129 +/* + * Filesystem commands + */ +#define NuFileSystem 300 +#define UFS 301 +#define HostFileSystem 302 +#define LastFileSystemCommand 303 +/* + * Container Commands + */ +#define ContainerCommand 500 +#define ContainerCommand64 501 +/* + * Cluster Commands + */ +#define ClusterCommand 550 +/* + * Scsi Port commands (scsi passthrough) + */ +#define ScsiPortCommand 600 +/* + * Misc house keeping and generic adapter initiated commands + */ +#define AifRequest 700 +#define CheckRevision 701 +#define FsaHostShutdown 702 +#define RequestAdapterInfo 703 +#define IsAdapterPaused 704 +#define SendHostTime 705 +#define LastMiscCommand 706 + +// +// Commands that will target the failover level on the FSA adapter +// + +enum fib_xfer_state { + HostOwned = (1<<0), + AdapterOwned = (1<<1), + FibInitialized = (1<<2), + FibEmpty = (1<<3), + AllocatedFromPool = (1<<4), + SentFromHost = (1<<5), + SentFromAdapter = (1<<6), + ResponseExpected = (1<<7), + NoResponseExpected = (1<<8), + AdapterProcessed = (1<<9), + HostProcessed = (1<<10), + HighPriority = (1<<11), + NormalPriority = (1<<12), + Async = (1<<13), + AsyncIo = (1<<13), // rpbfix: remove with new regime + PageFileIo = (1<<14), // rpbfix: remove with new regime + ShutdownRequest = (1<<15), + LazyWrite = (1<<16), // rpbfix: remove with new regime + AdapterMicroFib = (1<<17), + BIOSFibPath = (1<<18), + FastResponseCapable = (1<<19), + ApiFib = (1<<20) // Its an API Fib. +}; + +/* + * The following defines needs to be updated any time there is an + * incompatible change made to the aac_init structure. + */ + +#define ADAPTER_INIT_STRUCT_REVISION 3 + +struct aac_init +{ + u32 InitStructRevision; + u32 MiniPortRevision; + u32 fsrev; + u32 CommHeaderAddress; + u32 FastIoCommAreaAddress; + u32 AdapterFibsPhysicalAddress; + u32 AdapterFibsVirtualAddress; + u32 AdapterFibsSize; + u32 AdapterFibAlign; + u32 printfbuf; + u32 printfbufsiz; + u32 HostPhysMemPages; // number of 4k pages of host physical memory + u32 HostElapsedSeconds; // number of seconds since 1970. +}; + +enum aac_log_level { + LOG_INIT = 10, + LOG_INFORMATIONAL = 20, + LOG_WARNING = 30, + LOG_LOW_ERROR = 40, + LOG_MEDIUM_ERROR = 50, + LOG_HIGH_ERROR = 60, + LOG_PANIC = 70, + LOG_DEBUG = 80, + LOG_WINDBG_PRINT = 90 +}; + +#define FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT 0x030b +#define FSAFS_NTC_FIB_CONTEXT 0x030c + +struct aac_dev; + +struct adapter_ops +{ + void (*adapter_interrupt)(struct aac_dev *dev); + void (*adapter_notify)(struct aac_dev *dev, u32 event); + void (*adapter_enable_int)(struct aac_dev *dev, u32 event); + void (*adapter_disable_int)(struct aac_dev *dev, u32 event); +}; + +/* + * Define which interrupt handler needs to be installed + */ + +struct aac_driver_ident +{ + u16 vendor; + u16 device; + u16 subsystem_vendor; + u16 subsystem_device; + int (*init)(struct aac_dev *dev, unsigned long num); + char * name; + char * vname; + char * model; +}; + +/* + * The adapter interface specs all queues to be located in the same + * physically contigous block. The host structure that defines the + * commuication queues will assume they are each a seperate physically + * contigous memory region that will support them all being one big + * contigous block. + * There is a command and response queue for each level and direction of + * commuication. These regions are accessed by both the host and adapter. + */ + +struct aac_queue { + u64 logical; /* This is the address we give the adapter */ + struct aac_entry *base; /* This is the system virtual address */ + struct aac_qhdr headers; /* A pointer to the producer and consumer queue headers for this queue */ + u32 entries; /* Number of queue entries on this queue */ + wait_queue_head_t qfull; /* Event to wait on if the queue is full */ + wait_queue_head_t cmdready; /* Indicates there is a Command ready from the adapter on this queue. */ + /* This is only valid for adapter to host command queues. */ + spinlock_t *lock; /* Spinlock for this queue must take this lock before accessing the lock */ + spinlock_t lockdata; /* Actual lock (used only on one side of the lock) */ + unsigned long SavedIrql; /* Previous IRQL when the spin lock is taken */ + u32 padding; /* Padding - FIXME - can remove I believe */ + struct list_head cmdq; /* A queue of FIBs which need to be prcessed by the FS thread. This is */ + /* only valid for command queues which receive entries from the adapter. */ + struct list_head pendingq; /* A queue of outstanding fib's to the adapter. */ + unsigned long numpending; /* Number of entries on outstanding queue. */ + struct aac_dev * dev; /* Back pointer to adapter structure */ +}; + +/* + * Message queues. The order here is important, see also the + * queue type ordering + */ + +struct aac_queue_block +{ + struct aac_queue queue[8]; +}; + +/* + * SaP1 Message Unit Registers + */ + +struct sa_drawbridge_CSR { + // Offset | Name + u32 reserved[10]; // 00h-27h | Reserved + u8 LUT_Offset; // 28h | Looup Table Offset + u8 reserved1[3]; // 29h-2bh | Reserved + u32 LUT_Data; // 2ch | Looup Table Data + u32 reserved2[26]; // 30h-97h | Reserved + u16 PRICLEARIRQ; // 98h | Primary Clear Irq + u16 SECCLEARIRQ; // 9ah | Secondary Clear Irq + u16 PRISETIRQ; // 9ch | Primary Set Irq + u16 SECSETIRQ; // 9eh | Secondary Set Irq + u16 PRICLEARIRQMASK; // a0h | Primary Clear Irq Mask + u16 SECCLEARIRQMASK; // a2h | Secondary Clear Irq Mask + u16 PRISETIRQMASK; // a4h | Primary Set Irq Mask + u16 SECSETIRQMASK; // a6h | Secondary Set Irq Mask + u32 MAILBOX0; // a8h | Scratchpad 0 + u32 MAILBOX1; // ach | Scratchpad 1 + u32 MAILBOX2; // b0h | Scratchpad 2 + u32 MAILBOX3; // b4h | Scratchpad 3 + u32 MAILBOX4; // b8h | Scratchpad 4 + u32 MAILBOX5; // bch | Scratchpad 5 + u32 MAILBOX6; // c0h | Scratchpad 6 + u32 MAILBOX7; // c4h | Scratchpad 7 + + u32 ROM_Setup_Data; // c8h | Rom Setup and Data + u32 ROM_Control_Addr; // cch | Rom Control and Address + + u32 reserved3[12]; // d0h-ffh | reserved + u32 LUT[64]; // 100h-1ffh| Lookup Table Entries + + // + // TO DO + // need to add DMA, I2O, UART, etc registers form 80h to 364h + // + +}; + +#define Mailbox0 SaDbCSR.MAILBOX0 +#define Mailbox1 SaDbCSR.MAILBOX1 +#define Mailbox2 SaDbCSR.MAILBOX2 +#define Mailbox3 SaDbCSR.MAILBOX3 +#define Mailbox4 SaDbCSR.MAILBOX4 +#define Mailbox5 SaDbCSR.MAILBOX5 +#define Mailbox7 SaDbCSR.MAILBOX7 + +#define DoorbellReg_p SaDbCSR.PRISETIRQ +#define DoorbellReg_s SaDbCSR.SECSETIRQ +#define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ + + +#define DOORBELL_0 cpu_to_le16(0x0001) +#define DOORBELL_1 cpu_to_le16(0x0002) +#define DOORBELL_2 cpu_to_le16(0x0004) +#define DOORBELL_3 cpu_to_le16(0x0008) +#define DOORBELL_4 cpu_to_le16(0x0010) +#define DOORBELL_5 cpu_to_le16(0x0020) +#define DOORBELL_6 cpu_to_le16(0x0040) + + +#define PrintfReady DOORBELL_5 +#define PrintfDone DOORBELL_5 + +struct sa_registers { + struct sa_drawbridge_CSR SaDbCSR; /* 98h - c4h */ +}; + + +#define Sa_MINIPORT_REVISION 1 + +#define sa_readw(AEP, CSR) readl(&((AEP)->regs.sa->CSR)) +#define sa_readl(AEP, CSR) readl(&((AEP)->regs.sa->CSR)) +#define sa_writew(AEP, CSR, value) writew(value, &((AEP)->regs.sa->CSR)) +#define sa_writel(AEP, CSR, value) writel(value, &((AEP)->regs.sa->CSR)) + +/* + * Rx Message Unit Registers + */ + +struct rx_mu_registers { + // Local | PCI* | Name + // | | + u32 ARSR; // 1300h | 00h | APIC Register Select Register + u32 reserved0; // 1304h | 04h | Reserved + u32 AWR; // 1308h | 08h | APIC Window Register + u32 reserved1; // 130Ch | 0Ch | Reserved + u32 IMRx[2]; // 1310h | 10h | Inbound Message Registers + u32 OMRx[2]; // 1318h | 18h | Outbound Message Registers + u32 IDR; // 1320h | 20h | Inbound Doorbell Register + u32 IISR; // 1324h | 24h | Inbound Interrupt Status Register + u32 IIMR; // 1328h | 28h | Inbound Interrupt Mask Register + u32 ODR; // 132Ch | 2Ch | Outbound Doorbell Register + u32 OISR; // 1330h | 30h | Outbound Interrupt Status Register + u32 OIMR; // 1334h | 34h | Outbound Interrupt Mask Register + // * Must access through ATU Inbound Translation Window +}; + +struct rx_inbound { + u32 Mailbox[8]; +}; + +#define InboundMailbox0 IndexRegs.Mailbox[0] +#define InboundMailbox1 IndexRegs.Mailbox[1] +#define InboundMailbox2 IndexRegs.Mailbox[2] +#define InboundMailbox3 IndexRegs.Mailbox[3] +#define InboundMailbox4 IndexRegs.Mailbox[4] + +#define INBOUNDDOORBELL_0 cpu_to_le32(0x00000001) +#define INBOUNDDOORBELL_1 cpu_to_le32(0x00000002) +#define INBOUNDDOORBELL_2 cpu_to_le32(0x00000004) +#define INBOUNDDOORBELL_3 cpu_to_le32(0x00000008) +#define INBOUNDDOORBELL_4 cpu_to_le32(0x00000010) +#define INBOUNDDOORBELL_5 cpu_to_le32(0x00000020) +#define INBOUNDDOORBELL_6 cpu_to_le32(0x00000040) + +#define OUTBOUNDDOORBELL_0 cpu_to_le32(0x00000001) +#define OUTBOUNDDOORBELL_1 cpu_to_le32(0x00000002) +#define OUTBOUNDDOORBELL_2 cpu_to_le32(0x00000004) +#define OUTBOUNDDOORBELL_3 cpu_to_le32(0x00000008) +#define OUTBOUNDDOORBELL_4 cpu_to_le32(0x00000010) + +#define InboundDoorbellReg MUnit.IDR +#define OutboundDoorbellReg MUnit.ODR + +struct rx_registers { + struct rx_mu_registers MUnit; // 1300h - 1334h + u32 reserved1[6]; // 1338h - 134ch + struct rx_inbound IndexRegs; +}; + +#define rx_readb(AEP, CSR) readb(&((AEP)->regs.rx->CSR)) +#define rx_readl(AEP, CSR) readl(&((AEP)->regs.rx->CSR)) +#define rx_writeb(AEP, CSR, value) writeb(value, &((AEP)->regs.rx->CSR)) +#define rx_writel(AEP, CSR, value) writel(value, &((AEP)->regs.rx->CSR)) + +struct fib; + +typedef void (*fib_callback)(void *ctxt, struct fib *fibctx); + +struct aac_fib_context { + s16 type; // used for verification of structure + s16 size; + u32 jiffies; // used for cleanup + struct list_head next; // used to link context's into a linked list + struct semaphore wait_sem; // this is used to wait for the next fib to arrive. + int wait; // Set to true when thread is in WaitForSingleObject + unsigned long count; // total number of FIBs on FibList + struct list_head fibs; +}; + +#define MAXIMUM_NUM_CONTAINERS 64 // 4 Luns * 16 Targets +#define MAXIMUM_NUM_ADAPTERS 8 + +struct fsa_scsi_hba { + unsigned long size[MAXIMUM_NUM_CONTAINERS]; + unsigned long type[MAXIMUM_NUM_CONTAINERS]; + unsigned char valid[MAXIMUM_NUM_CONTAINERS]; + unsigned char ro[MAXIMUM_NUM_CONTAINERS]; + unsigned char locked[MAXIMUM_NUM_CONTAINERS]; + unsigned char deleted[MAXIMUM_NUM_CONTAINERS]; + long devno[MAXIMUM_NUM_CONTAINERS]; +}; + +struct fib { + void *next; /* this is used by the allocator */ + s16 type; + s16 size; + /* + * The Adapter that this I/O is destined for. + */ + struct aac_dev *dev; + u64 logicaladdr; /* 64 bit */ + /* + * This is the event the sendfib routine will wait on if the + * caller did not pass one and this is synch io. + */ + struct semaphore event_wait; + spinlock_t event_lock; + + unsigned long done; /* gets set to 1 when fib is complete */ + fib_callback callback; + void *callback_data; + unsigned long flags; + /* + * The following is used to put this fib context onto the + * Outstanding I/O queue. + */ + struct list_head queue; + + void *data; + struct hw_fib *fib; /* Actual shared object */ +}; + +struct aac_dev +{ + struct aac_dev *next; + const char *name; + int id; + + u16 irq_mask; + /* + * Map for 128 fib objects (64k) + */ + dma_addr_t hw_fib_pa; + struct hw_fib *hw_fib_va; + /* + * Fib Headers + */ + struct fib fibs[AAC_NUM_FIB]; + struct fib *free_fib; + struct fib *timeout_fib; + spinlock_t fib_lock; + + struct aac_queue_block *queues; + /* + * The user API will use an IOCTL to register itself to receive + * FIBs from the adapter. The following list is used to keep + * track of all the threads that have requested these FIBs. The + * mutex is used to synchronize access to all data associated + * with the adapter fibs. + */ + struct list_head fib_list; + + struct adapter_ops a_ops; + unsigned long fsrev; /* Main driver's revision number */ + + struct aac_init *init; /* Holds initialization info to communicate with adapter */ + dma_addr_t init_pa; /* Holds physical address of the init struct */ + + struct pci_dev *pdev; /* Our PCI interface */ + void * printfbuf; /* pointer to buffer used for printf's from the adapter */ + void * comm_addr; /* Base address of Comm area */ + dma_addr_t comm_phys; /* Physical Address of Comm area */ + size_t comm_size; + + struct Scsi_Host *scsi_host_ptr; + struct fsa_scsi_hba fsa_dev; + int thread_pid; + int cardtype; + + /* + * The following is the device specific extension. + */ + union + { + struct sa_registers *sa; + struct rx_registers *rx; + } regs; + /* + * The following is the number of the individual adapter + */ + long devnum; + int aif_thread; + struct completion aif_completion; +}; + +#define AllocateAndMapFibSpace(dev, MapFibContext) \ + dev->a_ops.AllocateAndMapFibSpace(dev, MapFibContext) + +#define UnmapAndFreeFibSpace(dev, MapFibContext) \ + dev->a_ops.UnmapAndFreeFibSpace(dev, MapFibContext) + +#define aac_adapter_interrupt(dev) \ + dev->a_ops.adapter_interrupt(dev) + +#define aac_adapter_notify(dev, event) \ + dev->a_ops.adapter_notify(dev, event) + +#define aac_adapter_enable_int(dev, event) \ + dev->a_ops.adapter_enable_int(dev, event) + +#define aac_adapter_disable_int(dev, event) \ + dev->a_ops.adapter_disable_int(dev, event) + + + +#define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001) + +/* + * Define the command values + */ + +#define Null 0 +#define GetAttributes 1 +#define SetAttributes 2 +#define Lookup 3 +#define ReadLink 4 +#define Read 5 +#define Write 6 +#define Create 7 +#define MakeDirectory 8 +#define SymbolicLink 9 +#define MakeNode 10 +#define Removex 11 +#define RemoveDirectoryx 12 +#define Rename 13 +#define Link 14 +#define ReadDirectory 15 +#define ReadDirectoryPlus 16 +#define FileSystemStatus 17 +#define FileSystemInfo 18 +#define PathConfigure 19 +#define Commit 20 +#define Mount 21 +#define UnMount 22 +#define Newfs 23 +#define FsCheck 24 +#define FsSync 25 +#define SimReadWrite 26 +#define SetFileSystemStatus 27 +#define BlockRead 28 +#define BlockWrite 29 +#define NvramIoctl 30 +#define FsSyncWait 31 +#define ClearArchiveBit 32 +#define SetAcl 33 +#define GetAcl 34 +#define AssignAcl 35 +#define FaultInsertion 36 /* Fault Insertion Command */ +#define CrazyCache 37 /* Crazycache */ + +#define MAX_FSACOMMAND_NUM 38 + + +/* + * Define the status returns. These are very unixlike although + * most are not in fact used + */ + +#define ST_OK 0 +#define ST_PERM 1 +#define ST_NOENT 2 +#define ST_IO 5 +#define ST_NXIO 6 +#define ST_E2BIG 7 +#define ST_ACCES 13 +#define ST_EXIST 17 +#define ST_XDEV 18 +#define ST_NODEV 19 +#define ST_NOTDIR 20 +#define ST_ISDIR 21 +#define ST_INVAL 22 +#define ST_FBIG 27 +#define ST_NOSPC 28 +#define ST_ROFS 30 +#define ST_MLINK 31 +#define ST_WOULDBLOCK 35 +#define ST_NAMETOOLONG 63 +#define ST_NOTEMPTY 66 +#define ST_DQUOT 69 +#define ST_STALE 70 +#define ST_REMOTE 71 +#define ST_BADHANDLE 10001 +#define ST_NOT_SYNC 10002 +#define ST_BAD_COOKIE 10003 +#define ST_NOTSUPP 10004 +#define ST_TOOSMALL 10005 +#define ST_SERVERFAULT 10006 +#define ST_BADTYPE 10007 +#define ST_JUKEBOX 10008 +#define ST_NOTMOUNTED 10009 +#define ST_MAINTMODE 10010 +#define ST_STALEACL 10011 + +/* + * On writes how does the client want the data written. + */ + +#define CACHE_CSTABLE 1 +#define CACHE_UNSTABLE 2 + +/* + * Lets the client know at which level the data was commited on + * a write request + */ + +#define CMFILE_SYNCH_NVRAM 1 +#define CMDATA_SYNCH_NVRAM 2 +#define CMFILE_SYNCH 3 +#define CMDATA_SYNCH 4 +#define CMUNSTABLE 5 + +struct aac_read +{ + u32 command; + u32 cid; + u32 block; + u32 count; + struct sgmap sg; // Must be last in struct because it is variable +}; + +struct aac_read_reply +{ + u32 status; + u32 count; +}; + +struct aac_write +{ + u32 command; + u32 cid; + u32 block; + u32 count; + u32 stable; + struct sgmap sg; // Must be last in struct because it is variable +}; + +struct aac_write_reply +{ + u32 status; + u32 count; + u32 committed; +}; + + +/* + * Object-Server / Volume-Manager Dispatch Classes + */ + +#define VM_Null 0 +#define VM_NameServe 1 +#define VM_ContainerConfig 2 +#define VM_Ioctl 3 +#define VM_FilesystemIoctl 4 +#define VM_CloseAll 5 +#define VM_CtBlockRead 6 +#define VM_CtBlockWrite 7 +#define VM_SliceBlockRead 8 /* raw access to configured "storage objects" */ +#define VM_SliceBlockWrite 9 +#define VM_DriveBlockRead 10 /* raw access to physical devices */ +#define VM_DriveBlockWrite 11 +#define VM_EnclosureMgt 12 /* enclosure management */ +#define VM_Unused 13 /* used to be diskset management */ +#define VM_CtBlockVerify 14 +#define VM_CtPerf 15 /* performance test */ +#define VM_CtBlockRead64 16 +#define VM_CtBlockWrite64 17 +#define VM_CtBlockVerify64 18 + +#define MAX_VMCOMMAND_NUM 19 /* used for sizing stats array - leave last */ + +/* + * Descriptive information (eg, vital stats) + * that a content manager might report. The + * FileArray filesystem component is one example + * of a content manager. Raw mode might be + * another. + */ + +struct aac_fsinfo { + u32 fsTotalSize; /* Consumed by fs, incl. metadata */ + u32 fsBlockSize; + u32 fsFragSize; + u32 fsMaxExtendSize; + u32 fsSpaceUnits; + u32 fsMaxNumFiles; + u32 fsNumFreeFiles; + u32 fsInodeDensity; +}; /* valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) */ + +union aac_contentinfo { + struct aac_fsinfo filesys; /* valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) */ +}; + +/* + * Query for "mountable" objects, ie, objects that are typically + * associated with a drive letter on the client (host) side. + */ + +struct aac_mntent { + u32 oid; + char name[16]; // if applicable + struct creation_info create_info; // if applicable + u32 capacity; + u32 vol; // substrate structure + u32 obj; // FT_FILESYS, FT_DATABASE, etc. + u32 state; // unready for mounting, readonly, etc. + union aac_contentinfo fileinfo; // Info specific to content manager (eg, filesystem) + u32 altoid; // != oid <==> snapshot or broken mirror exists +}; + +#define FSCS_READONLY 0x0002 /* possible result of broken mirror */ + +struct aac_query_mount { + u32 command; + u32 type; + u32 count; +}; + +struct aac_mount { + u32 status; + u32 type; /* should be same as that requested */ + u32 count; + struct aac_mntent mnt[1]; +}; + +/* + * The following command is sent to shut down each container. + */ + +struct aac_close { + u32 command; + u32 cid; +}; + +struct aac_query_disk +{ + s32 cnum; + s32 bus; + s32 target; + s32 lun; + u32 valid; + u32 locked; + u32 deleted; + s32 instance; + s8 name[10]; + u32 unmapped; +}; + +struct aac_delete_disk { + u32 disknum; + u32 cnum; +}; + +struct fib_ioctl +{ + char *fibctx; + int wait; + char *fib; +}; + +struct revision +{ + int compat; + unsigned long version; + unsigned long build; +}; + +/* + * Ugly - non Linux like ioctl coding for back compat. + */ + +#define CTL_CODE(function, method) ( \ + (4<< 16) | ((function) << 2) | (method) \ +) + +/* + * Define the method codes for how buffers are passed for I/O and FS + * controls + */ + +#define METHOD_BUFFERED 0 +#define METHOD_NEITHER 3 + +/* + * Filesystem ioctls + */ + +#define FSACTL_SENDFIB CTL_CODE(2050, METHOD_BUFFERED) +#define FSACTL_DELETE_DISK 0x163 +#define FSACTL_QUERY_DISK 0x173 +#define FSACTL_OPEN_GET_ADAPTER_FIB CTL_CODE(2100, METHOD_BUFFERED) +#define FSACTL_GET_NEXT_ADAPTER_FIB CTL_CODE(2101, METHOD_BUFFERED) +#define FSACTL_CLOSE_GET_ADAPTER_FIB CTL_CODE(2102, METHOD_BUFFERED) +#define FSACTL_MINIPORT_REV_CHECK CTL_CODE(2107, METHOD_BUFFERED) +#define FSACTL_FORCE_DELETE_DISK CTL_CODE(2120, METHOD_NEITHER) + +struct aac_common +{ + /* + * If this value is set to 1 then interrupt moderation will occur + * in the base commuication support. + */ + unsigned long irq_mod; + int peak_fibs; + int zero_fibs; + unsigned long fib_timeouts; + /* + * Statistical counters in debug mode + */ +#ifdef DBG + unsigned long FibsSent; + unsigned long FibRecved; + unsigned long NoResponseSent; + unsigned long NoResponseRecved; + unsigned long AsyncSent; + unsigned long AsyncRecved; + unsigned long NormalSent; + unsigned long NormalRecved; +#endif +}; + +extern struct aac_common aac_config; + + +/* + * The following macro is used when sending and receiving FIBs. It is + * only used for debugging. + */ + +#if DBG +#define FIB_COUNTER_INCREMENT(counter) (counter)++ +#else +#define FIB_COUNTER_INCREMENT(counter) +#endif + +/* + * Adapter direct commands + */ + +#define BREAKPOINT_REQUEST 0x00000004 +#define INIT_STRUCT_BASE_ADDRESS 0x00000005 +#define SEND_SYNCHRONOUS_FIB 0x0000000c + +/* + * Adapter Status Register + * + * Phase Staus mailbox is 32bits: + * <31:16> = Phase Status + * <15:0> = Phase + * + * The adapter reports is present state through the phase. Only + * a single phase should be ever be set. Each phase can have multiple + * phase status bits to provide more detailed information about the + * state of the board. Care should be taken to ensure that any phase + * status bits that are set when changing the phase are also valid + * for the new phase or be cleared out. Adapter software (monitor, + * iflash, kernel) is responsible for properly maintining the phase + * status mailbox when it is running. + * + * MONKER_API Phases + * + * Phases are bit oriented. It is NOT valid to have multiple bits set + */ + +#define SELF_TEST_FAILED cpu_to_le32(0x00000004) +#define KERNEL_UP_AND_RUNNING cpu_to_le32(0x00000080) +#define KERNEL_PANIC cpu_to_le32(0x00000100) + +/* + * Doorbell bit defines + */ + +#define DoorBellPrintfDone cpu_to_le32(1<<5) // Host -> Adapter +#define DoorBellAdapterNormCmdReady cpu_to_le32(1<<1) // Adapter -> Host +#define DoorBellAdapterNormRespReady cpu_to_le32(1<<2) // Adapter -> Host +#define DoorBellAdapterNormCmdNotFull cpu_to_le32(1<<3) // Adapter -> Host +#define DoorBellAdapterNormRespNotFull cpu_to_le32(1<<4) // Adapter -> Host +#define DoorBellPrintfReady cpu_to_le32(1<<5) // Adapter -> Host + +/* + * For FIB communication, we need all of the following things + * to send back to the user. + */ + +#define AifCmdEventNotify 1 /* Notify of event */ +#define AifCmdJobProgress 2 /* Progress report */ +#define AifCmdAPIReport 3 /* Report from other user of API */ +#define AifCmdDriverNotify 4 /* Notify host driver of event */ +#define AifReqJobList 100 /* Gets back complete job list */ +#define AifReqJobsForCtr 101 /* Gets back jobs for specific container */ +#define AifReqJobsForScsi 102 /* Gets back jobs for specific SCSI device */ +#define AifReqJobReport 103 /* Gets back a specific job report or list of them */ +#define AifReqTerminateJob 104 /* Terminates job */ +#define AifReqSuspendJob 105 /* Suspends a job */ +#define AifReqResumeJob 106 /* Resumes a job */ +#define AifReqSendAPIReport 107 /* API generic report requests */ +#define AifReqAPIJobStart 108 /* Start a job from the API */ +#define AifReqAPIJobUpdate 109 /* Update a job report from the API */ +#define AifReqAPIJobFinish 110 /* Finish a job from the API */ + +/* + * Adapter Initiated FIB command structures. Start with the adapter + * initiated FIBs that really come from the adapter, and get responded + * to by the host. + */ + +struct aac_aifcmd { + u32 command; /* Tell host what type of notify this is */ + u32 seqnum; /* To allow ordering of reports (if necessary) */ + u8 data[1]; /* Undefined length (from kernel viewpoint) */ +}; + +/* + * Adapter Information Block + * + * This is returned by the RequestAdapterInfo block + */ + +struct aac_adapter_info +{ + u32 platform; + u32 cpu; + u32 subcpu; + u32 clock; + u32 execmem; + u32 buffermem; + u32 totalmem; + u32 kernelrev; + u32 kernelbuild; + u32 monitorrev; + u32 monitorbuild; + u32 hwrev; + u32 hwbuild; + u32 biosrev; + u32 biosbuild; + u32 clustering; + u32 clustermask; + u64 serial; + u32 battery; + u32 options; + u32 OEM; +}; + +static inline u32 fib2addr(struct hw_fib *hw) +{ + return (u32)hw; +} + +static inline struct hw_fib *addr2fib(u32 addr) +{ + return (struct hw_fib *)addr; +} + +const char *aac_driverinfo(struct Scsi_Host *); +struct fib *fib_alloc(struct aac_dev *dev); +int fib_setup(struct aac_dev *dev); +void fib_map_free(struct aac_dev *dev); +void fib_free(struct fib * context); +void fib_init(struct fib * context); +void fib_dealloc(struct fib * context); +void aac_printf(struct aac_dev *dev, u32 val); +int fib_send(u16 command, struct fib * context, unsigned long size, int priority, int wait, int reply, fib_callback callback, void *ctxt); +int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry); +int aac_consumer_avail(struct aac_dev * dev, struct aac_queue * q); +void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum); +int fib_complete(struct fib * context); +#define fib_data(fibctx) ((void *)(fibctx)->fib->data) +int aac_detach(struct aac_dev *dev); +struct aac_dev *aac_init_adapter(struct aac_dev *dev); +int aac_get_containers(struct aac_dev *dev); +int aac_scsi_cmd(Scsi_Cmnd *scsi_cmnd_ptr); +int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg); +int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg); +int aac_rx_init(struct aac_dev *dev, unsigned long devNumber); +int aac_sa_init(struct aac_dev *dev, unsigned long devNumber); +unsigned int aac_response_normal(struct aac_queue * q); +unsigned int aac_command_normal(struct aac_queue * q); +int aac_command_thread(struct aac_dev * dev); +int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx); +int fib_adapter_complete(struct fib * fibptr, unsigned short size); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aacraid/commctrl.c linux-2.5/drivers/scsi/aacraid/commctrl.c --- linux-2.5.5/drivers/scsi/aacraid/commctrl.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/commctrl.c Thu Dec 13 16:32:36 2001 @@ -0,0 +1,410 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commctrl.c + * + * Abstract: Contains all routines for control of the AFA comm layer + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +/** + * ioctl_send_fib - send a FIB from userspace + * @dev: adapter is being processed + * @arg: arguments to the ioctl call + * + * This routine sends a fib to the adapter on behalf of a user level + * program. + */ + +static int ioctl_send_fib(struct aac_dev * dev, void *arg) +{ + struct hw_fib * kfib; + struct fib *fibptr; + + fibptr = fib_alloc(dev); + if(fibptr == NULL) + return -ENOMEM; + + kfib = fibptr->fib; + /* + * First copy in the header so that we can check the size field. + */ + if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) { + fib_free(fibptr); + return -EFAULT; + } + /* + * Since we copy based on the fib header size, make sure that we + * will not overrun the buffer when we copy the memory. Return + * an error if we would. + */ + if(le32_to_cpu(kfib->header.Size) > sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)) { + fib_free(fibptr); + return -EINVAL; + } + + if (copy_from_user((void *) kfib, arg, le32_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr))) { + fib_free(fibptr); + return -EFAULT; + } + + if (kfib->header.Command == cpu_to_le32(TakeABreakPt)) { + aac_adapter_interrupt(dev); + /* + * Since we didn't really send a fib, zero out the state to allow + * cleanup code not to assert. + */ + kfib->header.XferState = 0; + } else { + if (fib_send(kfib->header.Command, fibptr, le32_to_cpu(kfib->header.Size) , FsaNormal, + 1, 1, NULL, NULL) != 0) + { + fib_free(fibptr); + return -EINVAL; + } + if (fib_complete(fibptr) != 0) { + fib_free(fibptr); + return -EINVAL; + } + } + /* + * Make sure that the size returned by the adapter (which includes + * the header) is less than or equal to the size of a fib, so we + * don't corrupt application data. Then copy that size to the user + * buffer. (Don't try to add the header information again, since it + * was already included by the adapter.) + */ + + if (copy_to_user(arg, (void *)kfib, kfib->header.Size)) { + fib_free(fibptr); + return -EFAULT; + } + fib_free(fibptr); + return 0; +} + +/** + * open_getadapter_fib - Get the next fib + * + * This routine will get the next Fib, if available, from the AdapterFibContext + * passed in from the user. + */ + +static int open_getadapter_fib(struct aac_dev * dev, void *arg) +{ + struct aac_fib_context * fibctx; + int status; + unsigned long flags; + + fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL); + if (fibctx == NULL) { + status = -ENOMEM; + } else { + fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; + fibctx->size = sizeof(struct aac_fib_context); + /* + * Initialize the mutex used to wait for the next AIF. + */ + init_MUTEX_LOCKED(&fibctx->wait_sem); + fibctx->wait = 0; + /* + * Initialize the fibs and set the count of fibs on + * the list to 0. + */ + fibctx->count = 0; + INIT_LIST_HEAD(&fibctx->fibs); + fibctx->jiffies = jiffies/HZ; + /* + * Now add this context onto the adapter's + * AdapterFibContext list. + */ + spin_lock_irqsave(&dev->fib_lock, flags); + list_add_tail(&fibctx->next, &dev->fib_list); + spin_unlock_irqrestore(&dev->fib_lock, flags); + if (copy_to_user(arg, &fibctx, sizeof(struct aac_fib_context *))) { + status = -EFAULT; + } else { + status = 0; + } + } + return status; +} + +/** + * next_getadapter_fib - get the next fib + * @dev: adapter to use + * @arg: ioctl argument + * + * This routine will get the next Fib, if available, from the AdapterFibContext + * passed in from the user. + */ + +static int next_getadapter_fib(struct aac_dev * dev, void *arg) +{ + struct fib_ioctl f; + struct aac_fib_context *fibctx, *aifcp; + struct hw_fib * fib; + int status; + struct list_head * entry; + int found; + unsigned long flags; + + if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl))) + return -EFAULT; + /* + * Extract the AdapterFibContext from the Input parameters. + */ + fibctx = (struct aac_fib_context *) f.fibctx; + + /* + * Verify that the HANDLE passed in was a valid AdapterFibContext + * + * Search the list of AdapterFibContext addresses on the adapter + * to be sure this is a valid address + */ + found = 0; + entry = dev->fib_list.next; + + while(entry != &dev->fib_list) { + aifcp = list_entry(entry, struct aac_fib_context, next); + if(fibctx == aifcp) { /* We found a winner */ + found = 1; + break; + } + entry = entry->next; + } + if (found == 0) + return -EINVAL; + + if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || + (fibctx->size != sizeof(struct aac_fib_context))) + return -EINVAL; + status = 0; + spin_lock_irqsave(&dev->fib_lock, flags); + /* + * If there are no fibs to send back, then either wait or return + * -EAGAIN + */ +return_fib: + if (!list_empty(&fibctx->fibs)) { + struct list_head * entry; + /* + * Pull the next fib from the fibs + */ + entry = fibctx->fibs.next; + list_del(entry); + + fib = list_entry(entry, struct hw_fib, header.FibLinks); + fibctx->count--; + spin_unlock_irqrestore(&dev->fib_lock, flags); + if (copy_to_user(f.fib, fib, sizeof(struct hw_fib))) { + kfree(fib); + return -EFAULT; + } + /* + * Free the space occupied by this copy of the fib. + */ + kfree(fib); + status = 0; + fibctx->jiffies = jiffies/HZ; + } else { + spin_unlock_irqrestore(&dev->fib_lock, flags); + if (f.wait) { + if(down_interruptible(&fibctx->wait_sem) < 0) { + status = -EINTR; + } else { + /* Lock again and retry */ + spin_lock_irqsave(&dev->fib_lock, flags); + goto return_fib; + } + } else { + status = -EAGAIN; + } + } + return status; +} + +int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx) +{ + struct hw_fib *fib; + + /* + * First free any FIBs that have not been consumed. + */ + while (!list_empty(&fibctx->fibs)) { + struct list_head * entry; + /* + * Pull the next fib from the fibs + */ + entry = fibctx->fibs.next; + list_del(entry); + fib = list_entry(entry, struct hw_fib, header.FibLinks); + fibctx->count--; + /* + * Free the space occupied by this copy of the fib. + */ + kfree(fib); + } + /* + * Remove the Context from the AdapterFibContext List + */ + list_del(&fibctx->next); + /* + * Invalidate context + */ + fibctx->type = 0; + /* + * Free the space occupied by the Context + */ + kfree(fibctx); + return 0; +} + +/** + * close_getadapter_fib - close down user fib context + * @dev: adapter + * @arg: ioctl arguments + * + * This routine will close down the fibctx passed in from the user. + */ + +static int close_getadapter_fib(struct aac_dev * dev, void *arg) +{ + struct aac_fib_context *fibctx, *aifcp; + int status; + unsigned long flags; + struct list_head * entry; + int found; + + /* + * Extract the fibctx from the input parameters + */ + fibctx = arg; + + /* + * Verify that the HANDLE passed in was a valid AdapterFibContext + * + * Search the list of AdapterFibContext addresses on the adapter + * to be sure this is a valid address + */ + + found = 0; + entry = dev->fib_list.next; + + while(entry != &dev->fib_list) { + aifcp = list_entry(entry, struct aac_fib_context, next); + if(fibctx == aifcp) { /* We found a winner */ + found = 1; + break; + } + entry = entry->next; + } + + if(found == 0) + return 0; /* Already gone */ + + if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || + (fibctx->size != sizeof(struct aac_fib_context))) + return -EINVAL; + spin_lock_irqsave(&dev->fib_lock, flags); + status = aac_close_fib_context(dev, fibctx); + spin_unlock_irqrestore(&dev->fib_lock, flags); + return status; +} + +/** + * check_revision - close down user fib context + * @dev: adapter + * @arg: ioctl arguments + * + * This routine returns the firmware version. + * Under Linux, there have been no version incompatibilities, so this is simple! + */ + +static int check_revision(struct aac_dev *dev, void *arg) +{ + struct revision response; + + response.compat = 1; + response.version = 0x03000400; + response.build = 0x5125; + + if (copy_to_user(arg, &response, sizeof(response))) + return -EFAULT; + return 0; +} + + +int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg) +{ + int status; + + /* + * HBA gets first crack + */ + + status = aac_dev_ioctl(dev, cmd, arg); + if(status != -ENOTTY) + return status; + + switch (cmd) { + case FSACTL_MINIPORT_REV_CHECK: + status = check_revision(dev, arg); + break; + case FSACTL_SENDFIB: + status = ioctl_send_fib(dev, arg); + break; + case FSACTL_OPEN_GET_ADAPTER_FIB: + status = open_getadapter_fib(dev, arg); + break; + case FSACTL_GET_NEXT_ADAPTER_FIB: + status = next_getadapter_fib(dev, arg); + break; + case FSACTL_CLOSE_GET_ADAPTER_FIB: + status = close_getadapter_fib(dev, arg); + break; + default: + status = -ENOTTY; + break; + } + return status; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aacraid/comminit.c linux-2.5/drivers/scsi/aacraid/comminit.c --- linux-2.5.5/drivers/scsi/aacraid/comminit.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/comminit.c Sun Mar 3 17:54:35 2002 @@ -0,0 +1,332 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comminit.c + * + * Abstract: This supports the initialization of the host adapter commuication interface. + * This is a platform dependent module for the pci cyclone board. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +struct aac_common aac_config; + +static struct aac_dev *devices; + +static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign) +{ + unsigned char *base; + unsigned long size, align; + unsigned long fibsize = 4096; + unsigned long printfbufsiz = 256; + struct aac_init *init; + dma_addr_t phys; + + size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz; + + base = pci_alloc_consistent(dev->pdev, size, &phys); + if(base == NULL) + { + printk(KERN_ERR "aacraid: unable to create mapping.\n"); + return 0; + } + dev->comm_addr = (void *)base; + dev->comm_phys = phys; + dev->comm_size = size; + + dev->init = (struct aac_init *)(base + fibsize); + dev->init_pa = phys + fibsize; + + init = dev->init; + + init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION); + init->MiniPortRevision = cpu_to_le32(Sa_MINIPORT_REVISION); + init->fsrev = cpu_to_le32(dev->fsrev); + + /* + * Adapter Fibs are the first thing allocated so that they + * start page aligned + */ + init->AdapterFibsVirtualAddress = cpu_to_le32((long)base); + init->AdapterFibsPhysicalAddress = cpu_to_le32(phys); + init->AdapterFibsSize = cpu_to_le32(fibsize); + init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib)); + + /* + * Increment the base address by the amount already used + */ + base = base + fibsize + sizeof(struct aac_init); + phys = phys + fibsize + sizeof(struct aac_init); + /* + * Align the beginning of Headers to commalign + */ + align = (commalign - ((unsigned long)(base) & (commalign - 1))); + base = base + align; + phys = phys + align; + /* + * Fill in addresses of the Comm Area Headers and Queues + */ + *commaddr = (unsigned long *)base; + init->CommHeaderAddress = cpu_to_le32(phys); + /* + * Increment the base address by the size of the CommArea + */ + base = base + commsize; + phys = phys + commsize; + /* + * Place the Printf buffer area after the Fast I/O comm area. + */ + dev->printfbuf = (void *)base; + init->printfbuf = cpu_to_le32(phys); + init->printfbufsiz = cpu_to_le32(printfbufsiz); + memset(base, 0, printfbufsiz); + return 1; +} + +static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem, int qsize) +{ + q->numpending = 0; + q->dev = dev; + INIT_LIST_HEAD(&q->pendingq); + init_waitqueue_head(&q->cmdready); + INIT_LIST_HEAD(&q->cmdq); + init_waitqueue_head(&q->qfull); + spin_lock_init(&q->lockdata); + q->lock = &q->lockdata; + q->headers.producer = mem; + q->headers.consumer = mem+1; + *q->headers.producer = cpu_to_le32(qsize); + *q->headers.consumer = cpu_to_le32(qsize); + q->entries = qsize; +} + +/** + * aac_send_shutdown - shutdown an adapter + * @dev: Adapter to shutdown + * + * This routine will send a VM_CloseAll (shutdown) request to the adapter. + */ + +static int aac_send_shutdown(struct aac_dev * dev) +{ + struct fib * fibctx; + struct aac_close *cmd; + int status; + + fibctx = fib_alloc(dev); + fib_init(fibctx); + + cmd = (struct aac_close *) fib_data(fibctx); + + cmd->command = cpu_to_le32(VM_CloseAll); + cmd->cid = cpu_to_le32(0xffffffff); + + status = fib_send(ContainerCommand, + fibctx, + sizeof(struct aac_close), + FsaNormal, + 1, 1, + NULL, NULL); + + if (status == 0) + fib_complete(fibctx); + fib_free(fibctx); + return status; +} + +/** + * aac_detach - detach adapter + * @detach: adapter to disconnect + * + * Disconnect and shutdown an AAC based adapter, freeing resources + * as we go. + */ + +int aac_detach(struct aac_dev *detach) +{ + struct aac_dev **dev = &devices; + + while(*dev) + { + if(*dev == detach) + { + *dev = detach->next; + aac_send_shutdown(detach); + fib_map_free(detach); + pci_free_consistent(detach->pdev, detach->comm_size, detach->comm_addr, detach->comm_phys); + kfree(detach->queues); + return 1; + } + dev=&((*dev)->next); + } + BUG(); + return 0; +} + +/** + * aac_comm_init - Initialise FSA data structures + * @dev: Adapter to intialise + * + * Initializes the data structures that are required for the FSA commuication + * interface to operate. + * Returns + * 1 - if we were able to init the commuication interface. + * 0 - If there were errors initing. This is a fatal error. + */ + +int aac_comm_init(struct aac_dev * dev) +{ + unsigned long hdrsize = (sizeof(u32) * NUMBER_OF_COMM_QUEUES) * 2; + unsigned long queuesize = sizeof(struct aac_entry) * TOTAL_QUEUE_ENTRIES; + u32 *headers; + struct aac_entry * queues; + unsigned long size; + struct aac_queue_block * comm = dev->queues; + + /* + * Now allocate and initialize the zone structures used as our + * pool of FIB context records. The size of the zone is based + * on the system memory size. We also initialize the mutex used + * to protect the zone. + */ + spin_lock_init(&dev->fib_lock); + + /* + * Allocate the physically contigous space for the commuication + * queue headers. + */ + + size = hdrsize + queuesize; + + if (!aac_alloc_comm(dev, (void * *)&headers, size, QUEUE_ALIGNMENT)) + return -ENOMEM; + + queues = (struct aac_entry *)((unsigned char *)headers + hdrsize); + + /* Adapter to Host normal priority Command queue */ + comm->queue[HostNormCmdQueue].base = queues; + aac_queue_init(dev, &comm->queue[HostNormCmdQueue], headers, HOST_NORM_CMD_ENTRIES); + queues += HOST_NORM_CMD_ENTRIES; + headers += 2; + + /* Adapter to Host high priority command queue */ + comm->queue[HostHighCmdQueue].base = queues; + aac_queue_init(dev, &comm->queue[HostHighCmdQueue], headers, HOST_HIGH_CMD_ENTRIES); + + queues += HOST_HIGH_CMD_ENTRIES; + headers +=2; + + /* Host to adapter normal priority command queue */ + comm->queue[AdapNormCmdQueue].base = queues; + aac_queue_init(dev, &comm->queue[AdapNormCmdQueue], headers, ADAP_NORM_CMD_ENTRIES); + + queues += ADAP_NORM_CMD_ENTRIES; + headers += 2; + + /* host to adapter high priority command queue */ + comm->queue[AdapHighCmdQueue].base = queues; + aac_queue_init(dev, &comm->queue[AdapHighCmdQueue], headers, ADAP_HIGH_CMD_ENTRIES); + + queues += ADAP_HIGH_CMD_ENTRIES; + headers += 2; + + /* adapter to host normal priority response queue */ + comm->queue[HostNormRespQueue].base = queues; + aac_queue_init(dev, &comm->queue[HostNormRespQueue], headers, HOST_NORM_RESP_ENTRIES); + + queues += HOST_NORM_RESP_ENTRIES; + headers += 2; + + /* adapter to host high priority response queue */ + comm->queue[HostHighRespQueue].base = queues; + aac_queue_init(dev, &comm->queue[HostHighRespQueue], headers, HOST_HIGH_RESP_ENTRIES); + + queues += HOST_HIGH_RESP_ENTRIES; + headers += 2; + + /* host to adapter normal priority response queue */ + comm->queue[AdapNormRespQueue].base = queues; + aac_queue_init(dev, &comm->queue[AdapNormRespQueue], headers, ADAP_NORM_RESP_ENTRIES); + + queues += ADAP_NORM_RESP_ENTRIES; + headers += 2; + + /* host to adapter high priority response queue */ + comm->queue[AdapHighRespQueue].base = queues; + aac_queue_init(dev, &comm->queue[AdapHighRespQueue], headers, ADAP_HIGH_RESP_ENTRIES); + + comm->queue[AdapNormCmdQueue].lock = comm->queue[HostNormRespQueue].lock; + comm->queue[AdapHighCmdQueue].lock = comm->queue[HostHighRespQueue].lock; + comm->queue[AdapNormRespQueue].lock = comm->queue[HostNormCmdQueue].lock; + comm->queue[AdapHighRespQueue].lock = comm->queue[HostHighCmdQueue].lock; + + return 0; +} + +struct aac_dev *aac_init_adapter(struct aac_dev *dev) +{ + /* + * Ok now init the communication subsystem + */ + dev->queues = (struct aac_queue_block *) kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL); + if (dev->queues == NULL) { + printk(KERN_ERR "Error could not allocate comm region.\n"); + return NULL; + } + memset(dev->queues, 0, sizeof(struct aac_queue_block)); + + if (aac_comm_init(dev)<0) + return NULL; + /* + * Initialize the list of fibs + */ + if(fib_setup(dev)<0) + return NULL; + + INIT_LIST_HEAD(&dev->fib_list); + spin_lock_init(&dev->fib_lock); + init_completion(&dev->aif_completion); + /* + * Add this adapter in to our dev List. + */ + dev->next = devices; + devices = dev; + return dev; +} + + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aacraid/commsup.c linux-2.5/drivers/scsi/aacraid/commsup.c --- linux-2.5.5/drivers/scsi/aacraid/commsup.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/commsup.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,949 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commsup.c + * + * Abstract: Contain all routines that are required for FSA host/adapter + * commuication. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +/** + * fib_map_alloc - allocate the fib objects + * @dev: Adapter to allocate for + * + * Allocate and map the shared PCI space for the FIB blocks used to + * talk to the Adaptec firmware. + */ + +static int fib_map_alloc(struct aac_dev *dev) +{ + if((dev->hw_fib_va = pci_alloc_consistent(dev->pdev, sizeof(struct hw_fib) * AAC_NUM_FIB, &dev->hw_fib_pa))==NULL) + return -ENOMEM; + return 0; +} + +/** + * fib_map_free - free the fib objects + * @dev: Adapter to free + * + * Free the PCI mappings and the memory allocated for FIB blocks + * on this adapter. + */ + +void fib_map_free(struct aac_dev *dev) +{ + pci_free_consistent(dev->pdev, sizeof(struct hw_fib) * AAC_NUM_FIB, dev->hw_fib_va, dev->hw_fib_pa); +} + +/** + * fib_setup - setup the fibs + * @dev: Adapter to set up + * + * Allocate the PCI space for the fibs, map it and then intialise the + * fib area, the unmapped fib data and also the free list + */ + +int fib_setup(struct aac_dev * dev) +{ + struct fib *fibptr; + struct hw_fib *fib; + dma_addr_t fibpa; + int i; + + if(fib_map_alloc(dev)<0) + return -ENOMEM; + + fib = dev->hw_fib_va; + fibpa = dev->hw_fib_pa; + memset(fib, 0, sizeof(struct hw_fib) * AAC_NUM_FIB); + /* + * Initialise the fibs + */ + for (i = 0, fibptr = &dev->fibs[i]; i < AAC_NUM_FIB; i++, fibptr++) + { + fibptr->dev = dev; + fibptr->fib = fib; + fibptr->data = (void *) fibptr->fib->data; + fibptr->next = fibptr+1; /* Forward chain the fibs */ + init_MUTEX_LOCKED(&fibptr->event_wait); + spin_lock_init(&fibptr->event_lock); + fib->header.XferState = cpu_to_le32(0xffffffff); + fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib)); + fibptr->logicaladdr = (unsigned long) fibpa; + fib = (struct hw_fib *)((unsigned char *)fib + sizeof(struct hw_fib)); + fibpa = fibpa + sizeof(struct hw_fib); + } + /* + * Add the fib chain to the free list + */ + dev->fibs[AAC_NUM_FIB-1].next = NULL; + /* + * Enable this to debug out of queue space + */ + dev->free_fib = &dev->fibs[0]; + return 0; +} + +/** + * fib_alloc - allocate a fib + * @dev: Adapter to allocate the fib for + * + * Allocate a fib from the adapter fib pool. If the pool is empty we + * wait for fibs to become free. + */ + +struct fib * fib_alloc(struct aac_dev *dev) +{ + struct fib * fibptr; + unsigned long flags; + + spin_lock_irqsave(&dev->fib_lock, flags); + fibptr = dev->free_fib; + if(!fibptr) + BUG(); + dev->free_fib = fibptr->next; + spin_unlock_irqrestore(&dev->fib_lock, flags); + /* + * Set the proper node type code and node byte size + */ + fibptr->type = FSAFS_NTC_FIB_CONTEXT; + fibptr->size = sizeof(struct fib); + /* + * Null out fields that depend on being zero at the start of + * each I/O + */ + fibptr->fib->header.XferState = cpu_to_le32(0); + fibptr->callback = NULL; + fibptr->callback_data = NULL; + + return fibptr; +} + +/** + * fib_free - free a fib + * @fibptr: fib to free up + * + * Frees up a fib and places it on the appropriate queue + * (either free or timed out) + */ + +void fib_free(struct fib * fibptr) +{ + unsigned long flags; + + spin_lock_irqsave(&fibptr->dev->fib_lock, flags); + + if (fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT) { + aac_config.fib_timeouts++; + fibptr->next = fibptr->dev->timeout_fib; + fibptr->dev->timeout_fib = fibptr; + } else { + if (fibptr->fib->header.XferState != 0) { + printk(KERN_WARNING "fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", + fibptr, fibptr->fib->header.XferState); + } + fibptr->next = fibptr->dev->free_fib; + fibptr->dev->free_fib = fibptr; + } + spin_unlock_irqrestore(&fibptr->dev->fib_lock, flags); +} + +/** + * fib_init - initialise a fib + * @fibptr: The fib to initialize + * + * Set up the generic fib fields ready for use + */ + +void fib_init(struct fib *fibptr) +{ + struct hw_fib *fib = fibptr->fib; + + fib->header.StructType = FIB_MAGIC; + fib->header.Size = cpu_to_le16(sizeof(struct hw_fib)); + fib->header.XferState = cpu_to_le32(HostOwned | FibInitialized | FibEmpty | FastResponseCapable); + fib->header.SenderFibAddress = cpu_to_le32(0); + fib->header.ReceiverFibAddress = cpu_to_le32(0); + fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib)); +} + +/** + * fib_deallocate - deallocate a fib + * @fibptr: fib to deallocate + * + * Will deallocate and return to the free pool the FIB pointed to by the + * caller. + */ + +void fib_dealloc(struct fib * fibptr) +{ + struct hw_fib *fib = fibptr->fib; + if(fib->header.StructType != FIB_MAGIC) + BUG(); + fib->header.XferState = cpu_to_le32(0); +} + +/* + * Commuication primitives define and support the queuing method we use to + * support host to adapter commuication. All queue accesses happen through + * these routines and are the only routines which have a knowledge of the + * how these queues are implemented. + */ + +/** + * aac_get_entry - get a queue entry + * @dev: Adapter + * @qid: Queue Number + * @entry: Entry return + * @index: Index return + * @nonotify: notification control + * + * With a priority the routine returns a queue entry if the queue has free entries. If the queue + * is full(no free entries) than no entry is returned and the function returns 0 otherwise 1 is + * returned. + */ + +static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify) +{ + struct aac_queue * q; + + /* + * All of the queues wrap when they reach the end, so we check + * to see if they have reached the end and if they have we just + * set the index back to zero. This is a wrap. You could or off + * the high bits in all updates but this is a bit faster I think. + */ + + q = &dev->queues->queue[qid]; + + *index = le32_to_cpu(*(q->headers.producer)); + if (*index - 2 == le32_to_cpu(*(q->headers.consumer))) + *nonotify = 1; + + if (qid == AdapHighCmdQueue) { + if (*index >= ADAP_HIGH_CMD_ENTRIES) + *index = 0; + } else if (qid == AdapNormCmdQueue) { + if (*index >= ADAP_NORM_CMD_ENTRIES) + *index = 0; /* Wrap to front of the Producer Queue. */ + } + else if (qid == AdapHighRespQueue) + { + if (*index >= ADAP_HIGH_RESP_ENTRIES) + *index = 0; + } + else if (qid == AdapNormRespQueue) + { + if (*index >= ADAP_NORM_RESP_ENTRIES) + *index = 0; /* Wrap to front of the Producer Queue. */ + } + else BUG(); + + if (*index + 1 == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */ + printk(KERN_WARNING "Queue %d full, %ld outstanding.\n", + qid, q->numpending); + return 0; + } else { + *entry = q->base + *index; + return 1; + } +} + +/** + * aac_queue_get - get the next free QE + * @dev: Adapter + * @index: Returned index + * @priority: Priority of fib + * @fib: Fib to associate with the queue entry + * @wait: Wait if queue full + * @fibptr: Driver fib object to go with fib + * @nonotify: Don't notify the adapter + * + * Gets the next free QE off the requested priorty adapter command + * queue and associates the Fib with the QE. The QE represented by + * index is ready to insert on the queue when this routine returns + * success. + */ + +static int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * fib, int wait, struct fib * fibptr, unsigned long *nonotify) +{ + struct aac_entry * entry = NULL; + int map = 0; + struct aac_queue * q = &dev->queues->queue[qid]; + + spin_lock_irqsave(q->lock, q->SavedIrql); + + if (qid == AdapHighCmdQueue || qid == AdapNormCmdQueue) + { + /* if no entries wait for some if caller wants to */ + while (!aac_get_entry(dev, qid, &entry, index, nonotify)) + { + printk(KERN_ERR "GetEntries failed\n"); + } + /* + * Setup queue entry with a command, status and fib mapped + */ + entry->size = cpu_to_le32(le16_to_cpu(fib->header.Size)); + map = 1; + } + else if (qid == AdapHighRespQueue || qid == AdapNormRespQueue) + { + while(!aac_get_entry(dev, qid, &entry, index, nonotify)) + { + /* if no entries wait for some if caller wants to */ + } + /* + * Setup queue entry with command, status and fib mapped + */ + entry->size = cpu_to_le32(le16_to_cpu(fib->header.Size)); + entry->addr = cpu_to_le32(fib->header.SenderFibAddress); /* Restore adapters pointer to the FIB */ + fib->header.ReceiverFibAddress = fib->header.SenderFibAddress; /* Let the adapter now where to find its data */ + map = 0; + } + /* + * If MapFib is true than we need to map the Fib and put pointers + * in the queue entry. + */ + if (map) + entry->addr = cpu_to_le32((unsigned long)(fibptr->logicaladdr)); + return 0; +} + + +/** + * aac_insert_entry - insert a queue entry + * @dev: Adapter + * @index: Index of entry to insert + * @qid: Queue number + * @nonotify: Suppress adapter notification + * + * Gets the next free QE off the requested priorty adapter command + * queue and associates the Fib with the QE. The QE represented by + * index is ready to insert on the queue when this routine returns + * success. + */ + +static int aac_insert_entry(struct aac_dev * dev, u32 index, u32 qid, unsigned long nonotify) +{ + struct aac_queue * q = &dev->queues->queue[qid]; + + if(q == NULL) + BUG(); + *(q->headers.producer) = cpu_to_le32(index + 1); + spin_unlock_irqrestore(q->lock, q->SavedIrql); + + if (qid == AdapHighCmdQueue || + qid == AdapNormCmdQueue || + qid == AdapHighRespQueue || + qid == AdapNormRespQueue) + { + if (!nonotify) + aac_adapter_notify(dev, qid); + } + else + printk("Suprise insert!\n"); + return 0; +} + +/* + * Define the highest level of host to adapter communication routines. + * These routines will support host to adapter FS commuication. These + * routines have no knowledge of the commuication method used. This level + * sends and receives FIBs. This level has no knowledge of how these FIBs + * get passed back and forth. + */ + +/** + * fib_send - send a fib to the adapter + * @command: Command to send + * @fibptr: The fib + * @size: Size of fib data area + * @priority: Priority of Fib + * @wait: Async/sync select + * @reply: True if a reply is wanted + * @callback: Called with reply + * @callback_data: Passed to callback + * + * Sends the requested FIB to the adapter and optionally will wait for a + * response FIB. If the caller does not wish to wait for a response than + * an event to wait on must be supplied. This event will be set when a + * response FIB is received from the adapter. + */ + +int fib_send(u16 command, struct fib * fibptr, unsigned long size, int priority, int wait, int reply, fib_callback callback, void * callback_data) +{ + u32 index; + u32 qid; + struct aac_dev * dev = fibptr->dev; + unsigned long nointr = 0; + struct hw_fib * fib = fibptr->fib; + struct aac_queue * q; + unsigned long flags = 0; + + if (!(le32_to_cpu(fib->header.XferState) & HostOwned)) + return -EBUSY; + /* + * There are 5 cases with the wait and reponse requested flags. + * The only invalid cases are if the caller requests to wait and + * does not request a response and if the caller does not want a + * response and the Fibis not allocated from pool. If a response + * is not requesed the Fib will just be deallocaed by the DPC + * routine when the response comes back from the adapter. No + * further processing will be done besides deleting the Fib. We + * will have a debug mode where the adapter can notify the host + * it had a problem and the host can log that fact. + */ + if (wait && !reply) { + return -EINVAL; + } else if (!wait && reply) { + fib->header.XferState |= cpu_to_le32(Async | ResponseExpected); + FIB_COUNTER_INCREMENT(aac_config.AsyncSent); + } else if (!wait && !reply) { + fib->header.XferState |= cpu_to_le32(NoResponseExpected); + FIB_COUNTER_INCREMENT(aac_config.NoResponseSent); + } else if (wait && reply) { + fib->header.XferState |= cpu_to_le32(ResponseExpected); + FIB_COUNTER_INCREMENT(aac_config.NormalSent); + } + /* + * Map the fib into 32bits by using the fib number + */ + fib->header.SenderData = fibptr-&dev->fibs[0]; /* for callback */ + /* + * Set FIB state to indicate where it came from and if we want a + * response from the adapter. Also load the command from the + * caller. + * + * Map the hw fib pointer as a 32bit value + */ + fib->header.SenderFibAddress = fib2addr(fib); + fib->header.Command = cpu_to_le16(command); + fib->header.XferState |= cpu_to_le32(SentFromHost); + fibptr->fib->header.Flags = 0; /* Zero the flags field - its internal only... */ + /* + * Set the size of the Fib we want to send to the adapter + */ + fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size); + if (le16_to_cpu(fib->header.Size) > le16_to_cpu(fib->header.SenderSize)) { + return -EMSGSIZE; + } + /* + * Get a queue entry connect the FIB to it and send an notify + * the adapter a command is ready. + */ + if (priority == FsaHigh) { + fib->header.XferState |= cpu_to_le32(HighPriority); + qid = AdapHighCmdQueue; + } else { + fib->header.XferState |= cpu_to_le32(NormalPriority); + qid = AdapNormCmdQueue; + } + q = &dev->queues->queue[qid]; + + if(wait) + spin_lock_irqsave(&fibptr->event_lock, flags); + if(aac_queue_get( dev, &index, qid, fib, 1, fibptr, &nointr)<0) + return -EWOULDBLOCK; + dprintk((KERN_DEBUG "fib_send: inserting a queue entry at index %d.\n",index)); + dprintk((KERN_DEBUG "Fib contents:.\n")); + dprintk((KERN_DEBUG " Command = %d.\n", fib->header.Command)); + dprintk((KERN_DEBUG " XferState = %x.\n", fib->header.XferState)); + /* + * Fill in the Callback and CallbackContext if we are not + * going to wait. + */ + if (!wait) { + fibptr->callback = callback; + fibptr->callback_data = callback_data; + } + FIB_COUNTER_INCREMENT(aac_config.FibsSent); + list_add_tail(&fibptr->queue, &q->pendingq); + q->numpending++; + + fibptr->done = 0; + + if(aac_insert_entry(dev, index, qid, (nointr & aac_config.irq_mod)) < 0) + return -EWOULDBLOCK; + /* + * If the caller wanted us to wait for response wait now. + */ + + if (wait) { + spin_unlock_irqrestore(&fibptr->event_lock, flags); + down(&fibptr->event_wait); + if(fibptr->done == 0) + BUG(); + + if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) + return -ETIMEDOUT; + else + return 0; + } + /* + * If the user does not want a response than return success otherwise + * return pending + */ + if (reply) + return -EINPROGRESS; + else + return 0; +} + +/** + * aac_consumer_get - get the top of the queue + * @dev: Adapter + * @q: Queue + * @entry: Return entry + * + * Will return a pointer to the entry on the top of the queue requested that + * we are a consumer of, and return the address of the queue entry. It does + * not change the state of the queue. + */ + +int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry) +{ + u32 index; + int status; + + if (*q->headers.producer == *q->headers.consumer) { + status = 0; + } else { + /* + * The consumer index must be wrapped if we have reached + * the end of the queue, else we just use the entry + * pointed to by the header index + */ + if (le32_to_cpu(*q->headers.consumer) >= q->entries) + index = 0; + else + index = le32_to_cpu(*q->headers.consumer); + *entry = q->base + index; + status = 1; + } + return(status); +} + +int aac_consumer_avail(struct aac_dev *dev, struct aac_queue * q) +{ + return (*q->headers.producer != *q->headers.consumer); +} + + +/** + * aac_consumer_free - free consumer entry + * @dev: Adapter + * @q: Queue + * @qid: Queue ident + * + * Frees up the current top of the queue we are a consumer of. If the + * queue was full notify the producer that the queue is no longer full. + */ + +void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid) +{ + int wasfull = 0; + u32 notify; + + if (*q->headers.producer+1 == *q->headers.consumer) + wasfull = 1; + + if (le32_to_cpu(*q->headers.consumer) >= q->entries) + *q->headers.consumer = cpu_to_le32(1); + else + *q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1); + + if (wasfull) { + switch (qid) { + + case HostNormCmdQueue: + notify = HostNormCmdNotFull; + break; + case HostHighCmdQueue: + notify = HostHighCmdNotFull; + break; + case HostNormRespQueue: + notify = HostNormRespNotFull; + break; + case HostHighRespQueue: + notify = HostHighRespNotFull; + break; + default: + BUG(); + return; + } + aac_adapter_notify(dev, notify); + } +} + +/** + * fib_adapter_complete - complete adapter issued fib + * @fibptr: fib to complete + * @size: size of fib + * + * Will do all necessary work to complete a FIB that was sent from + * the adapter. + */ + +int fib_adapter_complete(struct fib * fibptr, unsigned short size) +{ + struct hw_fib * fib = fibptr->fib; + struct aac_dev * dev = fibptr->dev; + unsigned long nointr = 0; + + if (le32_to_cpu(fib->header.XferState) == 0) + return 0; + /* + * If we plan to do anything check the structure type first. + */ + if ( fib->header.StructType != FIB_MAGIC ) { + return -EINVAL; + } + /* + * This block handles the case where the adapter had sent us a + * command and we have finished processing the command. We + * call completeFib when we are done processing the command + * and want to send a response back to the adapter. This will + * send the completed cdb to the adapter. + */ + if (fib->header.XferState & cpu_to_le32(SentFromAdapter)) { + fib->header.XferState |= cpu_to_le32(HostProcessed); + if (fib->header.XferState & cpu_to_le32(HighPriority)) { + u32 index; + if (size) + { + size += sizeof(struct aac_fibhdr); + if (size > le16_to_cpu(fib->header.SenderSize)) + return -EMSGSIZE; + fib->header.Size = cpu_to_le16(size); + } + if(aac_queue_get(dev, &index, AdapHighRespQueue, fib, 1, NULL, &nointr) < 0) { + return -EWOULDBLOCK; + } + if (aac_insert_entry(dev, index, AdapHighRespQueue, (nointr & (int)aac_config.irq_mod)) != 0) { + } + } + else if (fib->header.XferState & NormalPriority) + { + u32 index; + + if (size) { + size += sizeof(struct aac_fibhdr); + if (size > le16_to_cpu(fib->header.SenderSize)) + return -EMSGSIZE; + fib->header.Size = cpu_to_le16(size); + } + if (aac_queue_get(dev, &index, AdapNormRespQueue, fib, 1, NULL, &nointr) < 0) + return -EWOULDBLOCK; + if (aac_insert_entry(dev, index, AdapNormRespQueue, + (nointr & (int)aac_config.irq_mod)) != 0) + { + } + } + } + else + { + printk(KERN_WARNING "fib_complete: Unknown xferstate detected.\n"); + BUG(); + } + return 0; +} + +/** + * fib_complete - fib completion handler + * @fib: FIB to complete + * + * Will do all necessary work to complete a FIB. + */ + +int fib_complete(struct fib * fibptr) +{ + struct hw_fib * fib = fibptr->fib; + + /* + * Check for a fib which has already been completed + */ + + if (fib->header.XferState == cpu_to_le32(0)) + return 0; + /* + * If we plan to do anything check the structure type first. + */ + + if (fib->header.StructType != FIB_MAGIC) + return -EINVAL; + /* + * This block completes a cdb which orginated on the host and we + * just need to deallocate the cdb or reinit it. At this point the + * command is complete that we had sent to the adapter and this + * cdb could be reused. + */ + if((fib->header.XferState & cpu_to_le32(SentFromHost)) && + (fib->header.XferState & cpu_to_le32(AdapterProcessed))) + { + fib_dealloc(fibptr); + } + else if(fib->header.XferState & cpu_to_le32(SentFromHost)) + { + /* + * This handles the case when the host has aborted the I/O + * to the adapter because the adapter is not responding + */ + fib_dealloc(fibptr); + } else if(fib->header.XferState & cpu_to_le32(HostOwned)) { + fib_dealloc(fibptr); + } else { + BUG(); + } + return 0; +} + +/** + * aac_printf - handle printf from firmware + * @dev: Adapter + * @val: Message info + * + * Print a message passed to us by the controller firmware on the + * Adaptec board + */ + +void aac_printf(struct aac_dev *dev, u32 val) +{ + int length = val & 0xffff; + int level = (val >> 16) & 0xffff; + char *cp = dev->printfbuf; + + /* + * The size of the printfbuf is set in port.c + * There is no variable or define for it + */ + if (length > 255) + length = 255; + if (cp[length] != 0) + cp[length] = 0; + if (level == LOG_HIGH_ERROR) + printk(KERN_WARNING "aacraid:%s", cp); + else + printk(KERN_INFO "aacraid:%s", cp); + memset(cp, 0, 256); +} + + +/** + * aac_handle_aif - Handle a message from the firmware + * @dev: Which adapter this fib is from + * @fibptr: Pointer to fibptr from adapter + * + * This routine handles a driver notify fib from the adapter and + * dispatches it to the appropriate routine for handling. + */ + +static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) +{ + struct hw_fib * fib = fibptr->fib; + /* + * Set the status of this FIB to be Invalid parameter. + * + * *(u32 *)fib->data = ST_INVAL; + */ + *(u32 *)fib->data = cpu_to_le32(ST_OK); + fib_adapter_complete(fibptr, sizeof(u32)); +} + +/** + * aac_command_thread - command processing thread + * @dev: Adapter to monitor + * + * Waits on the commandready event in it's queue. When the event gets set + * it will pull FIBs off it's queue. It will continue to pull FIBs off + * until the queue is empty. When the queue is empty it will wait for + * more FIBs. + */ + +int aac_command_thread(struct aac_dev * dev) +{ + struct hw_fib *fib, *newfib; + struct fib fibptr; /* for error logging */ + struct aac_queue_block *queues = dev->queues; + struct aac_fib_context *fibctx; + unsigned long flags; + DECLARE_WAITQUEUE(wait, current); + + /* + * We can only have one thread per adapter for AIF's. + */ + if (dev->aif_thread) + return -EINVAL; + /* + * Set up the name that will appear in 'ps' + * stored in task_struct.comm[16]. + */ + sprintf(current->comm, "aacraid"); + daemonize(); + /* + * Let the DPC know it has a place to send the AIF's to. + */ + dev->aif_thread = 1; + memset(&fibptr, 0, sizeof(struct fib)); + add_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait); + set_current_state(TASK_INTERRUPTIBLE); + while(1) + { + spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags); + while(!list_empty(&(queues->queue[HostNormCmdQueue].cmdq))) { + struct list_head *entry; + struct aac_aifcmd * aifcmd; + + set_current_state(TASK_RUNNING); + + entry = queues->queue[HostNormCmdQueue].cmdq.next; + list_del(entry); + + spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags); + fib = list_entry(entry, struct hw_fib, header.FibLinks); + /* + * We will process the FIB here or pass it to a + * worker thread that is TBD. We Really can't + * do anything at this point since we don't have + * anything defined for this thread to do. + */ + memset(&fibptr, 0, sizeof(struct fib)); + fibptr.type = FSAFS_NTC_FIB_CONTEXT; + fibptr.size = sizeof( struct fib ); + fibptr.fib = fib; + fibptr.data = fib->data; + fibptr.dev = dev; + /* + * We only handle AifRequest fibs from the adapter. + */ + aifcmd = (struct aac_aifcmd *) fib->data; + if (aifcmd->command == le16_to_cpu(AifCmdDriverNotify)) { + aac_handle_aif(dev, &fibptr); + } else { + /* The u32 here is important and intended. We are using + 32bit wrapping time to fit the adapter field */ + + u32 time_now, time_last; + unsigned long flagv; + + time_now = jiffies/HZ; + + spin_lock_irqsave(&dev->fib_lock, flagv); + entry = dev->fib_list.next; + /* + * For each Context that is on the + * fibctxList, make a copy of the + * fib, and then set the event to wake up the + * thread that is waiting for it. + */ + while (entry != &dev->fib_list) { + /* + * Extract the fibctx + */ + fibctx = list_entry(entry, struct aac_fib_context, next); + /* + * Check if the queue is getting + * backlogged + */ + if (fibctx->count > 20) + { + time_last = fibctx->jiffies; + /* + * Has it been > 2 minutes + * since the last read off + * the queue? + */ + if ((time_now - time_last) > 120) { + entry = entry->next; + aac_close_fib_context(dev, fibctx); + continue; + } + } + /* + * Warning: no sleep allowed while + * holding spinlock + */ + newfib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC); + if (newfib) { + /* + * Make the copy of the FIB + */ + memcpy(newfib, fib, sizeof(struct hw_fib)); + /* + * Put the FIB onto the + * fibctx's fibs + */ + list_add_tail(&newfib->header.FibLinks, &fibctx->fibs); + fibctx->count++; + /* + * Set the event to wake up the + * thread that will waiting. + */ + up(&fibctx->wait_sem); + } else { + printk(KERN_WARNING "aifd: didn't allocate NewFib.\n"); + } + entry = entry->next; + } + /* + * Set the status of this FIB + */ + *(u32 *)fib->data = cpu_to_le32(ST_OK); + fib_adapter_complete(&fibptr, sizeof(u32)); + spin_unlock_irqrestore(&dev->fib_lock, flagv); + } + spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags); + } + /* + * There are no more AIF's + */ + spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags); + schedule(); + + if(signal_pending(current)) + break; + set_current_state(TASK_INTERRUPTIBLE); + } + remove_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait); + dev->aif_thread = 0; + complete_and_exit(&dev->aif_completion, 0); +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aacraid/dpcsup.c linux-2.5/drivers/scsi/aacraid/dpcsup.c --- linux-2.5.5/drivers/scsi/aacraid/dpcsup.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/dpcsup.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,201 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * dpcsup.c + * + * Abstract: All DPC processing routines for the cyclone board occur here. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +/** + * aac_response_normal - Handle command replies + * @q: Queue to read from + * + * This DPC routine will be run when the adapter interrupts us to let us + * know there is a response on our normal priority queue. We will pull off + * all QE there are and wake up all the waiters before exiting. We will + * take a spinlock out on the queue before operating on it. + */ + +unsigned int aac_response_normal(struct aac_queue * q) +{ + struct aac_dev * dev = q->dev; + struct aac_entry *entry; + struct hw_fib * fib; + struct fib * fibctx; + int consumed = 0; + unsigned long flags; + + spin_lock_irqsave(q->lock, flags); + + /* + * Keep pulling response QEs off the response queue and waking + * up the waiters until there are no more QEs. We then return + * back to the system. If no response was requesed we just + * deallocate the Fib here and continue. + */ + while(aac_consumer_get(dev, q, &entry)) + { + int fast; + + fast = (int) (entry->addr & 0x01); + fib = addr2fib(entry->addr & ~0x01); + aac_consumer_free(dev, q, HostNormRespQueue); + fibctx = &dev->fibs[fib->header.SenderData]; + /* + * Remove this fibctx from the Outstanding I/O queue. + * But only if it has not already been timed out. + * + * If the fib has been timed out already, then just + * continue. The caller has already been notified that + * the fib timed out. + */ + if (!(fibctx->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) { + list_del(&fibctx->queue); + dev->queues->queue[AdapNormCmdQueue].numpending--; + } else { + printk(KERN_WARNING "aacraid: FIB timeout.\n"); + continue; + } + spin_unlock_irqrestore(q->lock, flags); + + if (fast) { + /* + * Doctor the fib + */ + *(u32 *)fib->data = cpu_to_le32(ST_OK); + fib->header.XferState |= cpu_to_le32(AdapterProcessed); + } + + FIB_COUNTER_INCREMENT(aac_config.FibRecved); + + if (fib->header.Command == cpu_to_le16(NuFileSystem)) + { + u32 *pstatus = (u32 *)fib->data; + if (*pstatus & cpu_to_le32(0xffff0000)) + *pstatus = cpu_to_le32(ST_OK); + } + if (fib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) + { + if (fib->header.XferState & cpu_to_le32(NoResponseExpected)) + FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved); + else + FIB_COUNTER_INCREMENT(aac_config.AsyncRecved); + /* + * NOTE: we cannot touch the fibctx after this + * call, because it may have been deallocated. + */ + fibctx->callback(fibctx->callback_data, fibctx); + } else { + unsigned long flagv; + spin_lock_irqsave(&fibctx->event_lock, flagv); + fibctx->done = 1; + up(&fibctx->event_wait); + spin_unlock_irqrestore(&fibctx->event_lock, flagv); + FIB_COUNTER_INCREMENT(aac_config.NormalRecved); + } + consumed++; + spin_lock_irqsave(q->lock, flags); + } + + if (consumed > aac_config.peak_fibs) + aac_config.peak_fibs = consumed; + if (consumed == 0) + aac_config.zero_fibs++; + + spin_unlock_irqrestore(q->lock, flags); + return 0; +} + + +/** + * aac_command_normal - handle commands + * @q: queue to process + * + * This DPC routine will be queued when the adapter interrupts us to + * let us know there is a command on our normal priority queue. We will + * pull off all QE there are and wake up all the waiters before exiting. + * We will take a spinlock out on the queue before operating on it. + */ + +unsigned int aac_command_normal(struct aac_queue *q) +{ + struct aac_dev * dev = q->dev; + struct aac_entry *entry; + unsigned long flags; + + spin_lock_irqsave(q->lock, flags); + + /* + * Keep pulling response QEs off the response queue and waking + * up the waiters until there are no more QEs. We then return + * back to the system. + */ + while(aac_consumer_get(dev, q, &entry)) + { + struct hw_fib * fib; + fib = addr2fib(entry->addr); + + if (dev->aif_thread) { + list_add_tail(&fib->header.FibLinks, &q->cmdq); + aac_consumer_free(dev, q, HostNormCmdQueue); + wake_up_interruptible(&q->cmdready); + } else { + struct fib fibctx; + aac_consumer_free(dev, q, HostNormCmdQueue); + spin_unlock_irqrestore(q->lock, flags); + memset(&fibctx, 0, sizeof(struct fib)); + fibctx.type = FSAFS_NTC_FIB_CONTEXT; + fibctx.size = sizeof(struct fib); + fibctx.fib = fib; + fibctx.data = fib->data; + fibctx.dev = dev; + /* + * Set the status of this FIB + */ + *(u32 *)fib->data = cpu_to_le32(ST_OK); + fib_adapter_complete(&fibctx, sizeof(u32)); + spin_lock_irqsave(q->lock, flags); + } + } + spin_unlock_irqrestore(q->lock, flags); + return 0; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aacraid/linit.c linux-2.5/drivers/scsi/aacraid/linit.c --- linux-2.5.5/drivers/scsi/aacraid/linit.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/linit.c Mon Jan 14 22:39:45 2002 @@ -0,0 +1,691 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * linit.c + * + * Abstract: Linux Driver entry module for Adaptec RAID Array Controller + * + * Provides the following driver entry points: + * aac_detect() + * aac_release() + * aac_queuecommand() + * aac_resetcommand() + * aac_biosparm() + * + */ + +#define AAC_DRIVER_VERSION "0.9.9ac4-rel" +#define AAC_DRIVER_BUILD_DATE __DATE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" +#include "sd.h" + +#define AAC_DRIVERNAME "aacraid" + +MODULE_AUTHOR("Red Hat Inc and Adaptec OEM RAID Solutions"); +MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, and HP NetRAID-4M devices. http://domsch.com/linux/"); +MODULE_LICENSE("GPL"); + +struct aac_dev *aac_devices[MAXIMUM_NUM_ADAPTERS]; + +static unsigned aac_count = 0; +static int aac_cfg_major = -1; +static int single_command_done = 0; + +/* + * Because of the way Linux names scsi devices, the order in this table has + * become important. Check for on-board Raid first, add-in cards second. + */ + +/* FIXME static */struct aac_driver_ident aac_drivers[] = { + { 0x1028, 0x0001, 0x1028, 0x0001, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 2/Si */ + { 0x1028, 0x0002, 0x1028, 0x0002, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x0003, 0x1028, 0x0003, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Si */ + { 0x1028, 0x0004, 0x1028, 0x00d0, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Si */ + { 0x1028, 0x0002, 0x1028, 0x00d1, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x0002, 0x1028, 0x00d9, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x000a, 0x1028, 0x0106, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x000a, 0x1028, 0x011b, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1028, 0x000a, 0x1028, 0x0121, aac_rx_init, "percraid", "DELL ", "PERCRAID " }, /* PERC 3/Di */ + { 0x1011, 0x0046, 0x9005, 0x1364, aac_sa_init, "percraid", "DELL ", "PERCRAID " }, /* Dell PERC2 "Quad Channel" */ + { 0x1011, 0x0046, 0x9005, 0x0365, aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S " }, /* Adaptec 5400S */ + { 0x1011, 0x0046, 0x103c, 0x10c2, aac_sa_init, "hpnraid", "HP ", "NetRAID-4M " } /* HP NetRAID-4M */ +}; + +#define NUM_AACTYPES (sizeof(aac_drivers) / sizeof(struct aac_driver_ident)) +static int num_aacdrivers = NUM_AACTYPES; + +static int aac_cfg_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); +static int aac_cfg_open(struct inode * inode, struct file * file); +static int aac_cfg_release(struct inode * inode,struct file * file); + +static struct file_operations aac_cfg_fops = { + owner: THIS_MODULE, + ioctl: aac_cfg_ioctl, + open: aac_cfg_open, + release: aac_cfg_release +}; + +static int aac_detect(Scsi_Host_Template *); +static int aac_release(struct Scsi_Host *); +static int aac_queuecommand(Scsi_Cmnd *, void (*CompletionRoutine)(Scsi_Cmnd *)); +static int aac_command(Scsi_Cmnd *); +static int aac_abortcommand(Scsi_Cmnd *scsi_cmnd_ptr); +static int aac_resetcommand(Scsi_Cmnd *, unsigned int); +static int aac_biosparm(Scsi_Disk *, kdev_t, int *); +static int aac_procinfo(char *, char **, off_t, int, int, int); +static int aac_ioctl(Scsi_Device *, int, void *); + +static void aac_queuedepth(struct Scsi_Host *, Scsi_Device *); + +/** + * aac_detect - Probe for aacraid cards + * @template: SCSI driver template + * + * Probe for AAC Host Adapters initialize, register, and report the + * configuration of each AAC Host Adapter found. + * Returns the number of adapters successfully initialized and + * registered. + * Initializes all data necessary for this particular SCSI driver. + * Notes: + * The detect routine must not call any of the mid level functions + * to queue commands because things are not guaranteed to be set + * up yet. The detect routine can send commands to the host adapter + * as long as the program control will not be passed to scsi.c in + * the processing of the command. Note especially that + * scsi_malloc/scsi_free must not be called. + * + */ + +static int aac_detect(Scsi_Host_Template *template) +{ + int index; + int container; + u16 vendor_id, device_id; + struct Scsi_Host *host_ptr; + struct pci_dev *dev = NULL; + struct aac_dev *aac; + struct fsa_scsi_hba *fsa_dev_ptr; + char *name = NULL; + + printk(KERN_INFO "Red Hat/Adaptec aacraid driver, %s\n", AAC_DRIVER_BUILD_DATE); + + /* setting up the proc directory structure */ + template->proc_name = "aacraid"; + + for( index = 0; index != num_aacdrivers; index++ ) + { + device_id = aac_drivers[index].device; + vendor_id = aac_drivers[index].vendor; + name = aac_drivers[index].name; + dprintk((KERN_DEBUG "Checking %s %x/%x/%x/%x.\n", + name, vendor_id, device_id, + aac_drivers[index].subsystem_vendor, + aac_drivers[index].subsystem_device)); + + dev = NULL; + while((dev = pci_find_device(vendor_id, device_id, dev))) + { + if (pci_enable_device(dev)) + continue; + pci_set_master(dev); + pci_set_dma_mask(dev, 0xFFFFFFFFULL); + + if((dev->subsystem_vendor != aac_drivers[index].subsystem_vendor) || + (dev->subsystem_device != aac_drivers[index].subsystem_device)) + continue; + + dprintk((KERN_DEBUG "%s device detected.\n", name)); + dprintk((KERN_DEBUG "%x/%x/%x/%x.\n", vendor_id, device_id, + aac_drivers[index].subsystem_vendor, aac_drivers[index].subsystem_device)); + /* Increment the host adapter count */ + aac_count++; + /* + * scsi_register() allocates memory for a Scsi_Hosts structure and + * links it into the linked list of host adapters. This linked list + * contains the data for all possible scsi hosts. + * This is similar to the Scsi_Host_Template, except that we have + * one entry for each actual physical host adapter on the system, + * stored as a linked list. If there are two AAC boards, then we + * will need to make two Scsi_Host entries, but there will be only + * one Scsi_Host_Template entry. The second argument to scsi_register() + * specifies the size of the extra memory we want to hold any device + * specific information. + */ + host_ptr = scsi_register( template, sizeof(struct aac_dev) ); + /* + * These three parameters can be used to allow for wide SCSI + * and for host adapters that support multiple buses. + */ + host_ptr->max_id = 17; + host_ptr->max_lun = 8; + host_ptr->max_channel = 1; + host_ptr->irq = dev->irq; /* Adapter IRQ number */ + /* host_ptr->base = ( char * )(dev->resource[0].start & ~0xff); */ + host_ptr->base = dev->resource[0].start; + scsi_set_pci_device(host_ptr, dev); + dprintk((KERN_DEBUG "Device base address = 0x%lx [0x%lx].\n", host_ptr->base, dev->resource[0].start)); + dprintk((KERN_DEBUG "Device irq = 0x%x.\n", dev->irq)); + /* + * The unique_id field is a unique identifier that must + * be assigned so that we have some way of identifying + * each host adapter properly and uniquely. For hosts + * that do not support more than one card in the + * system, this does not need to be set. It is + * initialized to zero in scsi_register(). This is the + * value returned as aac->id. + */ + host_ptr->unique_id = aac_count - 1; + /* + * This function is called after the device list has + * been built to find the tagged queueing depth + * supported for each device. + */ + host_ptr->select_queue_depths = aac_queuedepth; + aac = (struct aac_dev *)host_ptr->hostdata; + /* attach a pointer back to Scsi_Host */ + aac->scsi_host_ptr = host_ptr; + aac->pdev = dev; + aac->cardtype = index; + aac->name = aac->scsi_host_ptr->hostt->name; + aac->id = aac->scsi_host_ptr->unique_id; + /* Initialize the ordinal number of the device to -1 */ + fsa_dev_ptr = &(aac->fsa_dev); + for( container = 0; container < MAXIMUM_NUM_CONTAINERS; container++ ) + fsa_dev_ptr->devno[container] = -1; + + dprintk((KERN_DEBUG "Initializing Hardware...\n")); + if((*aac_drivers[index].init)(aac , host_ptr->unique_id) != 0) + { + /* device initialization failed */ + printk(KERN_WARNING "aacraid: device initialization failed.\n"); + scsi_unregister(host_ptr); + aac_count--; + } + else + { + dprintk((KERN_DEBUG "%s:%d device initialization successful.\n", name, host_ptr->unique_id)); + aac_get_containers(aac); + aac_devices[aac_count-1] = aac; + } + } + } + + if( aac_count ){ + if((aac_cfg_major = register_chrdev( 0, "aac", &aac_cfg_fops))<0) + printk(KERN_WARNING "aacraid: unable to register \"aac\" device.\n"); + } + + template->present = aac_count; /* # of cards of this type found */ + return aac_count; +} + +/** + * aac_release - release SCSI host resources + * @host_ptr: SCSI host to clean up + * + * Release all resources previously acquired to support a specific Host + * Adapter and unregister the AAC Host Adapter. + * + * BUGS: Does not wait for the thread it kills to die. + */ + +static int aac_release(struct Scsi_Host *host_ptr) +{ + struct aac_dev *dev; + dprintk((KERN_DEBUG "aac_release.\n")); + dev = (struct aac_dev *)host_ptr->hostdata; + /* + * kill any threads we started + */ + kill_proc(dev->thread_pid, SIGKILL, 0); + wait_for_completion(&dev->aif_completion); + /* + * Call the comm layer to detach from this adapter + */ + aac_detach(dev); + /* Check free orderings... */ + /* remove interrupt binding */ + free_irq(host_ptr->irq, dev); + iounmap((void * )dev->regs.sa); + /* unregister adapter */ + scsi_unregister(host_ptr); + /* + * FIXME: This assumes no hot plugging is going on... + */ + if( aac_cfg_major >= 0 ) + { + unregister_chrdev(aac_cfg_major, "aac"); + aac_cfg_major = -1; + } + return 0; +} + +/** + * aac_queuecommand - queue a SCSI command + * @scsi_cmnd_ptr: SCSI command to queue + * @CompletionRoutine: Function to call on command completion + * + * Queues a command for execution by the associated Host Adapter. + */ + +static int aac_queuecommand(Scsi_Cmnd *scsi_cmnd_ptr, void (*CompletionRoutine)(Scsi_Cmnd *)) +{ + int ret; + + scsi_cmnd_ptr->scsi_done = CompletionRoutine; + /* + * aac_scsi_cmd() handles command processing, setting the + * result code and calling completion routine. + */ + if((ret = aac_scsi_cmd(scsi_cmnd_ptr)) != 0) + dprintk((KERN_DEBUG "aac_scsi_cmd failed.\n")); + return ret; +} + + +/** + * aac_done - Callback function for a non-queued command. + * @scsi_cmnd_ptr: SCSI command block to wait for + * + * Sets single_command done to 1. This lets aac_command complete. + * This function is obsolete. + * + * Bugs: Doesn't actually work properly with multiple controllers + */ + +static void aac_done(Scsi_Cmnd * scsi_cmnd_ptr) +{ + single_command_done = 1; +} + +/** + * aac_command - synchronous SCSI command execution + * @scsi_cmnd_ptr: SCSI command to issue + * + * Accepts a single command for execution by the associated Host Adapter. + * Waits until it completes an then returns an int where: + * Byte 0 = SCSI status code + * Byte 1 = SCSI 1 byte message + * Byte 2 = host error return + * Byte 3 = mid level error return + */ + +static int aac_command(Scsi_Cmnd *scsi_cmnd_ptr ) +{ + scsi_cmnd_ptr->scsi_done = aac_done; + dprintk((KERN_DEBUG "aac_command.\n")); + + /* + * aac_scsi_cmd() handles command processing, setting the + * result code and calling completion routine. + */ + single_command_done = 0; + aac_scsi_cmd(scsi_cmnd_ptr); + while(!single_command_done) + rmb(); + return scsi_cmnd_ptr->result; +} + +/** + * aac_abortcommand - Abort command if possible. + * @scsi_cmnd_ptr: SCSI command block to abort + * + * Called when the midlayer wishes to abort a command. We don't support + * this facility, and our firmware looks after life for us. We just + * report the command as busy. + */ + +static int aac_abortcommand(Scsi_Cmnd *scsi_cmnd_ptr ) +{ + return SCSI_ABORT_BUSY; +} + +/** + * aac_resetcommand - Reset command handling + * @scsi_cmnd_ptr: SCSI command block causing the reset + * @reset_flags: Reset hints from the midlayer code + * + * Issue a reset of a SCSI command. We are ourselves not truely a SCSI + * controller and our firmware will do the work for us anyway. Thus this + * is a no-op. We just return SCSI_RESET_PUNT + */ + +static int aac_resetcommand(struct scsi_cmnd *scsi_cmnd_ptr, unsigned int reset_flags ) +{ + return SCSI_RESET_PUNT; +} + +/** + * aac_driverinfo - Returns the host adapter name + * @host_ptr: Scsi host to report on + * + * Returns a static string describing the device in question + */ + +const char *aac_driverinfo(struct Scsi_Host *host_ptr) +{ + struct aac_dev *dev = (struct aac_dev *)host_ptr->hostdata; + return aac_drivers[dev->cardtype].name; +} + +/** + * aac_biosparm - return BIOS parameters for disk + * @disk: SCSI disk object to process + * @device: kdev_t of the disk in question + * @geom: geometry block to fill in + * + * Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk. + * The default disk geometry is 64 heads, 32 sectors, and the appropriate + * number of cylinders so as not to exceed drive capacity. In order for + * disks equal to or larger than 1 GB to be addressable by the BIOS + * without exceeding the BIOS limitation of 1024 cylinders, Extended + * Translation should be enabled. With Extended Translation enabled, + * drives between 1 GB inclusive and 2 GB exclusive are given a disk + * geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive + * are given a disk geometry of 255 heads and 63 sectors. However, if + * the BIOS detects that the Extended Translation setting does not match + * the geometry in the partition table, then the translation inferred + * from the partition table will be used by the BIOS, and a warning may + * be displayed. + */ + +static int aac_biosparm(Scsi_Disk *disk, kdev_t dev, int *geom) +{ + struct diskparm *param = (struct diskparm *)geom; + struct buffer_head * buf; + + dprintk((KERN_DEBUG "aac_biosparm.\n")); + + /* + * Assuming extended translation is enabled - #REVISIT# + */ + if( disk->capacity >= 2 * 1024 * 1024 ) /* 1 GB in 512 byte sectors */ + { + if( disk->capacity >= 4 * 1024 * 1024 ) /* 2 GB in 512 byte sectors */ + { + param->heads = 255; + param->sectors = 63; + } + else + { + param->heads = 128; + param->sectors = 32; + } + } + else + { + param->heads = 64; + param->sectors = 32; + } + + param->cylinders = disk->capacity/(param->heads * param->sectors); + + /* + * Read the first 1024 bytes from the disk device + */ + + buf = bread(mk_kdev(major(dev), minor(dev)&~0xf), 0, block_size(dev)); + if(buf == NULL) + return 0; + /* + * If the boot sector partition table is valid, search for a partition + * table entry whose end_head matches one of the standard geometry + * translations ( 64/32, 128/32, 255/63 ). + */ + + if(*(unsigned short *)(buf->b_data + 0x1fe) == cpu_to_le16(0xaa55)) + { + struct partition *first = (struct partition * )(buf->b_data + 0x1be); + struct partition *entry = first; + int saved_cylinders = param->cylinders; + int num; + unsigned char end_head, end_sec; + + for(num = 0; num < 4; num++) + { + end_head = entry->end_head; + end_sec = entry->end_sector & 0x3f; + + if(end_head == 63) + { + param->heads = 64; + param->sectors = 32; + break; + } + else if(end_head == 127) + { + param->heads = 128; + param->sectors = 32; + break; + } + else if(end_head == 254) + { + param->heads = 255; + param->sectors = 63; + break; + } + entry++; + } + + if(num == 4) + { + end_head = first->end_head; + end_sec = first->end_sector & 0x3f; + } + + param->cylinders = disk->capacity / (param->heads * param->sectors); + + if(num < 4 && end_sec == param->sectors) + { + if(param->cylinders != saved_cylinders) + dprintk((KERN_DEBUG "Adopting geometry: heads=%d, sectors=%d from partition table %d.\n", + param->heads, param->sectors, num)); + } + else if(end_head > 0 || end_sec > 0) + { + dprintk((KERN_DEBUG "Strange geometry: heads=%d, sectors=%d in partition table %d.\n", + end_head + 1, end_sec, num)); + dprintk((KERN_DEBUG "Using geometry: heads=%d, sectors=%d.\n", + param->heads, param->sectors)); + } + } + brelse(buf); + return 0; +} + +/** + * aac_queuedepth - compute queue depths + * @host: SCSI host in question + * @dev: SCSI device we are considering + * + * Selects queue depths for each target device based on the host adapter's + * total capacity and the queue depth supported by the target device. + * A queue depth of one automatically disables tagged queueing. + */ + +static void aac_queuedepth(struct Scsi_Host * host, Scsi_Device * dev ) +{ + Scsi_Device * dptr; + + dprintk((KERN_DEBUG "aac_queuedepth.\n")); + dprintk((KERN_DEBUG "Device # Q Depth Online\n")); + dprintk((KERN_DEBUG "---------------------------\n")); + for(dptr = dev; dptr != NULL; dptr = dptr->next) + { + if(dptr->host == host) + { + dptr->queue_depth = 10; + dprintk((KERN_DEBUG " %2d %d %d\n", + dptr->id, dptr->queue_depth, dptr->online)); + } + } +} + +/*------------------------------------------------------------------------------ + aac_ioctl() + + Handle SCSI ioctls + *----------------------------------------------------------------------------*/ +static int aac_ioctl(Scsi_Device * scsi_dev_ptr, int cmd, void * arg) +/*----------------------------------------------------------------------------*/ +{ + struct aac_dev *dev; + dprintk((KERN_DEBUG "aac_ioctl.\n")); + dev = (struct aac_dev *)scsi_dev_ptr->host->hostdata; + return aac_do_ioctl(dev, cmd, arg); +} + +/** + * aac_cfg_open - open a configuration file + * @inode: inode being opened + * @file: file handle attached + * + * Called when the configuration device is opened. Does the needed + * set up on the handle and then returns + * + * Bugs: This needs extending to check a given adapter is present + * so we can support hot plugging, and to ref count adapters. + */ + +static int aac_cfg_open(struct inode * inode, struct file * file ) +{ + unsigned minor_number = minor(inode->i_rdev); + if(minor_number >= aac_count) + return -ENODEV; + return 0; +} + +/** + * aac_cfg_release - close down an AAC config device + * @inode: inode of configuration file + * @file: file handle of configuration file + * + * Called when the last close of the configuration file handle + * is performed. + */ + +static int aac_cfg_release(struct inode * inode, struct file * file ) +{ + return 0; +} + +/** + * aac_cfg_ioctl - AAC configuration request + * @inode: inode of device + * @file: file handle + * @cmd: ioctl command code + * @arg: argument + * + * Handles a configuration ioctl. Currently this involves wrapping it + * up and feeding it into the nasty windowsalike glue layer. + * + * Bugs: Needs locking against parallel ioctls lower down + * Bugs: Needs to handle hot plugging + */ + +static int aac_cfg_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg ) +{ + struct aac_dev *dev = aac_devices[minor(inode->i_rdev)]; + return aac_do_ioctl(dev, cmd, (void *)arg); +} + +/* + * To use the low level SCSI driver support using the linux kernel loadable + * module interface we should initialize the global variable driver_interface + * (datatype Scsi_Host_Template) and then include the file scsi_module.c. + */ + +static Scsi_Host_Template driver_template = { + module: THIS_MODULE, + name: "AAC", + proc_info: aac_procinfo, + detect: aac_detect, + release: aac_release, + info: aac_driverinfo, + ioctl: aac_ioctl, + command: aac_command, + queuecommand: aac_queuecommand, + abort: aac_abortcommand, + reset: aac_resetcommand, + bios_param: aac_biosparm, + can_queue: AAC_NUM_IO_FIB, + this_id: 16, + sg_tablesize: 16, + max_sectors: 128, + cmd_per_lun: 1, + eh_abort_handler: aac_abortcommand, + use_clustering: ENABLE_CLUSTERING, +}; + +#include "scsi_module.c" + +/** + * aac_procinfo - Implement /proc/scsi// + * @proc_buffer: memory buffer for I/O + * @start_ptr: pointer to first valid data + * @offset: offset into file + * @bytes_available: space left + * @host_no: scsi host ident + * @write: direction of I/O + * + * Used to export driver statistics and other infos to the world outside + * the kernel using the proc file system. Also provides an interface to + * feed the driver with information. + * + * For reads + * - if offset > 0 return 0 + * - if offset == 0 write data to proc_buffer and set the start_ptr to + * beginning of proc_buffer, return the number of characters written. + * For writes + * - writes currently not supported, return 0 + * + * Bugs: Only offset zero is handled + */ + +static int aac_procinfo(char *proc_buffer, char **start_ptr,off_t offset, + int bytes_available, int host_no, int write) +{ + if(write || offset > 0) + return 0; + *start_ptr = proc_buffer; + return sprintf(proc_buffer, "%s %d\n", "Raid Controller, scsi hba number", host_no); +} + +EXPORT_NO_SYMBOLS; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aacraid/rx.c linux-2.5/drivers/scsi/aacraid/rx.c --- linux-2.5.5/drivers/scsi/aacraid/rx.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/rx.c Mon Feb 4 16:35:16 2002 @@ -0,0 +1,413 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * rx.c + * + * Abstract: Hardware miniport for Drawbridge specific hardware functions. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +static void aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct aac_dev *dev = dev_id; + unsigned long bellbits; + u8 intstat, mask; + + intstat = rx_readb(dev, MUnit.OISR); + /* + * Read mask and invert because drawbridge is reversed. + * This allows us to only service interrupts that have + * been enabled. + */ + mask = ~(rx_readb(dev, MUnit.OIMR)); + /* Check to see if this is our interrupt. If it isn't just return */ + if (intstat & mask) + { + bellbits = rx_readl(dev, OutboundDoorbellReg); + if (bellbits & DoorBellPrintfReady) + { + aac_printf(dev, le32_to_cpu(rx_readl (dev, IndexRegs.Mailbox[5]))); + rx_writel(dev, MUnit.ODR,DoorBellPrintfReady); + rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); + } + else if (bellbits & DoorBellAdapterNormCmdReady) + { + aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); + } + else if (bellbits & DoorBellAdapterNormRespReady) + { + aac_response_normal(&dev->queues->queue[HostNormRespQueue]); + rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); + } + else if (bellbits & DoorBellAdapterNormCmdNotFull) + { + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); + } + else if (bellbits & DoorBellAdapterNormRespNotFull) + { + rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); + } + } +} + +/** + * aac_rx_enable_interrupt - Enable event reporting + * @dev: Adapter + * @event: Event to enable + * + * Enable event reporting from the i960 for a given event. + */ + +static void aac_rx_enable_interrupt(struct aac_dev * dev, u32 event) +{ + switch (event) { + + case HostNormCmdQue: + dev->irq_mask &= ~(OUTBOUNDDOORBELL_1); + break; + + case HostNormRespQue: + dev->irq_mask &= ~(OUTBOUNDDOORBELL_2); + break; + + case AdapNormCmdNotFull: + dev->irq_mask &= ~(OUTBOUNDDOORBELL_3); + break; + + case AdapNormRespNotFull: + dev->irq_mask &= ~(OUTBOUNDDOORBELL_4); + break; + } +} + +/** + * aac_rx_disable_interrupt - Disable event reporting + * @dev: Adapter + * @event: Event to enable + * + * Disable event reporting from the i960 for a given event. + */ + +static void aac_rx_disable_interrupt(struct aac_dev *dev, u32 event) +{ + switch (event) { + + case HostNormCmdQue: + dev->irq_mask |= (OUTBOUNDDOORBELL_1); + break; + + case HostNormRespQue: + dev->irq_mask |= (OUTBOUNDDOORBELL_2); + break; + + case AdapNormCmdNotFull: + dev->irq_mask |= (OUTBOUNDDOORBELL_3); + break; + + case AdapNormRespNotFull: + dev->irq_mask |= (OUTBOUNDDOORBELL_4); + break; + } +} + +/** + * rx_sync_cmd - send a command and wait + * @dev: Adapter + * @command: Command to execute + * @p1: first parameter + * @ret: adapter status + * + * This routine will send a synchronous comamnd to the adapter and wait + * for its completion. + */ + +static int rx_sync_cmd(struct aac_dev *dev, unsigned long command, unsigned long p1, unsigned long *status) +{ + unsigned long start; + int ok; + /* + * Write the command into Mailbox 0 + */ + rx_writel(dev, InboundMailbox0, cpu_to_le32(command)); + /* + * Write the parameters into Mailboxes 1 - 4 + */ + rx_writel(dev, InboundMailbox1, cpu_to_le32(p1)); + rx_writel(dev, InboundMailbox2, 0); + rx_writel(dev, InboundMailbox3, 0); + rx_writel(dev, InboundMailbox4, 0); + /* + * Clear the synch command doorbell to start on a clean slate. + */ + rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + /* + * Disable doorbell interrupts + */ + rx_writeb(dev, MUnit.OIMR, rx_readb(dev, MUnit.OIMR) | 0x04); + /* + * Force the completion of the mask register write before issuing + * the interrupt. + */ + rx_readb (dev, MUnit.OIMR); + /* + * Signal that there is a new synch command + */ + rx_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0); + + ok = 0; + start = jiffies; + + /* + * Wait up to 30 seconds + */ + while (time_before(jiffies, start+30*HZ)) + { + udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ + /* + * Mon960 will set doorbell0 bit when it has completed the command. + */ + if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) { + /* + * Clear the doorbell. + */ + rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + ok = 1; + break; + } + /* + * Yield the processor in case we are slow + */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + if (ok != 1) { + /* + * Restore interrupt mask even though we timed out + */ + rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb); + return -ETIMEDOUT; + } + /* + * Pull the synch status from Mailbox 0. + */ + *status = le32_to_cpu(rx_readl(dev, IndexRegs.Mailbox[0])); + /* + * Clear the synch command doorbell. + */ + rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + /* + * Restore interrupt mask + */ + rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb); + return 0; + +} + +/** + * aac_rx_interrupt_adapter - interrupt adapter + * @dev: Adapter + * + * Send an interrupt to the i960 and breakpoint it. + */ + +static void aac_rx_interrupt_adapter(struct aac_dev *dev) +{ + unsigned long ret; + rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret); +} + +/** + * aac_rx_notify_adapter - send an event to the adapter + * @dev: Adapter + * @event: Event to send + * + * Notify the i960 that something it probably cares about has + * happened. + */ + +static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event) +{ + switch (event) { + + case AdapNormCmdQue: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1); + break; + case HostNormRespNotFull: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4); + break; + case AdapNormRespQue: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2); + break; + case HostNormCmdNotFull: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3); + break; + case HostShutdown: +// rx_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, &ret); + break; + case FastIo: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6); + break; + case AdapPrintfDone: + rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5); + break; + default: + BUG(); + break; + } +} + +/** + * aac_rx_start_adapter - activate adapter + * @dev: Adapter + * + * Start up processing on an i960 based AAC adapter + */ + +static void aac_rx_start_adapter(struct aac_dev *dev) +{ + unsigned long status; + struct aac_init *init; + + init = dev->init; + init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ); + /* + * Tell the adapter we are back and up and running so it will scan + * its command queues and enable our interrupts + */ + dev->irq_mask = (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4); + /* + * First clear out all interrupts. Then enable the one's that we + * can handle. + */ + rx_writeb(dev, MUnit.OIMR, 0xff); + rx_writel(dev, MUnit.ODR, 0xffffffff); +// rx_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK); + rx_writeb(dev, MUnit.OIMR, 0xfb); + + rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (unsigned long) dev->init_pa, &status); +} + +/** + * aac_rx_init - initialize an i960 based AAC card + * @dev: device to configure + * @devnum: adapter number + * + * Allocate and set up resources for the i960 based AAC variants. The + * device_interface in the commregion will be allocated and linked + * to the comm region. + */ + +int aac_rx_init(struct aac_dev *dev, unsigned long num) +{ + unsigned long start; + unsigned long status; + int instance; + const char * name; + + dev->devnum = num; + + instance = dev->id; + name = dev->name; + + /* + * Map in the registers from the adapter. + */ + if((dev->regs.rx = (struct rx_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL) + { + printk(KERN_WARNING "aacraid: unable to map i960.\n" ); + return -1; + } + /* + * Check to see if the board failed any self tests. + */ + if (rx_readl(dev, IndexRegs.Mailbox[7]) & SELF_TEST_FAILED) { + printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance); + return -1; + } + /* + * Check to see if the board panic'd while booting. + */ + if (rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_PANIC) { + printk(KERN_ERR "%s%d: adapter kernel panic'd.\n", dev->name, instance); + return -1; + } + start = jiffies; + /* + * Wait for the adapter to be up and running. Wait up to 30 seconds. + */ + while (!(rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING)) + { + if(time_after(jiffies, start+30*HZ)) + { + status = rx_readl(dev, IndexRegs.Mailbox[7]) >> 16; + printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %ld.\n", dev->name, instance, status); + return -1; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0) + { + printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance); + return -1; + } + /* + * Fill in the function dispatch table. + */ + dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter; + dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt; + dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt; + dev->a_ops.adapter_notify = aac_rx_notify_adapter; + + if (aac_init_adapter(dev) == NULL) + return -1; + /* + * Start any kernel threads needed + */ + dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0); + /* + * Tell the adapter that all is configured, and it can start + * accepting requests + */ + aac_rx_start_adapter(dev); + return 0; +} diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aacraid/sap1sup.c linux-2.5/drivers/scsi/aacraid/sap1sup.c --- linux-2.5.5/drivers/scsi/aacraid/sap1sup.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aacraid/sap1sup.c Thu Dec 13 16:32:36 2001 @@ -0,0 +1,394 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * sap1sup.c + * + * Abstract: Drawbridge specific support functions + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#include "aacraid.h" + +static void aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct aac_dev *dev = dev_id; + unsigned short intstat, mask; + + intstat = sa_readw(dev, DoorbellReg_p); + /* + * Read mask and invert because drawbridge is reversed. + * This allows us to only service interrupts that have been enabled. + */ + mask = ~(sa_readw(dev, SaDbCSR.PRISETIRQMASK)); + + /* Check to see if this is our interrupt. If it isn't just return */ + + if (intstat & mask) { + if (intstat & PrintfReady) { + aac_printf(dev, le32_to_cpu(sa_readl(dev, Mailbox5))); + sa_writew(dev, DoorbellClrReg_p, PrintfReady); /* clear PrintfReady */ + sa_writew(dev, DoorbellReg_s, PrintfDone); + } else if (intstat & DOORBELL_1) { // dev -> Host Normal Command Ready + aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); + sa_writew(dev, DoorbellClrReg_p, DOORBELL_1); + } else if (intstat & DOORBELL_2) { // dev -> Host Normal Response Ready + aac_response_normal(&dev->queues->queue[HostNormRespQueue]); + sa_writew(dev, DoorbellClrReg_p, DOORBELL_2); + } else if (intstat & DOORBELL_3) { // dev -> Host Normal Command Not Full + sa_writew(dev, DoorbellClrReg_p, DOORBELL_3); + } else if (intstat & DOORBELL_4) { // dev -> Host Normal Response Not Full + sa_writew(dev, DoorbellClrReg_p, DOORBELL_4); + } + } +} + +/** + * aac_sa_enable_interrupt - enable an interrupt event + * @dev: Which adapter to enable. + * @event: Which adapter event. + * + * This routine will enable the corresponding adapter event to cause an interrupt on + * the host. + */ + +void aac_sa_enable_interrupt(struct aac_dev *dev, u32 event) +{ + switch (event) { + + case HostNormCmdQue: + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_1); + break; + + case HostNormRespQue: + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_2); + break; + + case AdapNormCmdNotFull: + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_3); + break; + + case AdapNormRespNotFull: + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, DOORBELL_4); + break; + } +} + +/** + * aac_sa_disable_interrupt - disable an interrupt event + * @dev: Which adapter to enable. + * @event: Which adapter event. + * + * This routine will enable the corresponding adapter event to cause an interrupt on + * the host. + */ + +void aac_sa_disable_interrupt (struct aac_dev *dev, u32 event) +{ + switch (event) { + + case HostNormCmdQue: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_1); + break; + + case HostNormRespQue: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_2); + break; + + case AdapNormCmdNotFull: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_3); + break; + + case AdapNormRespNotFull: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, DOORBELL_4); + break; + } +} + +/** + * aac_sa_notify_adapter - handle adapter notification + * @dev: Adapter that notification is for + * @event: Event to notidy + * + * Notify the adapter of an event + */ + +void aac_sa_notify_adapter(struct aac_dev *dev, u32 event) +{ + switch (event) { + + case AdapNormCmdQue: + sa_writew(dev, DoorbellReg_s,DOORBELL_1); + break; + case HostNormRespNotFull: + sa_writew(dev, DoorbellReg_s,DOORBELL_4); + break; + case AdapNormRespQue: + sa_writew(dev, DoorbellReg_s,DOORBELL_2); + break; + case HostNormCmdNotFull: + sa_writew(dev, DoorbellReg_s,DOORBELL_3); + break; + case HostShutdown: + //sa_sync_cmd(dev, HOST_CRASHING, 0, &ret); + break; + case FastIo: + sa_writew(dev, DoorbellReg_s,DOORBELL_6); + break; + case AdapPrintfDone: + sa_writew(dev, DoorbellReg_s,DOORBELL_5); + break; + default: + BUG(); + break; + } +} + + +/** + * sa_sync_cmd - send a command and wait + * @dev: Adapter + * @command: Command to execute + * @p1: first parameter + * @ret: adapter status + * + * This routine will send a synchronous comamnd to the adapter and wait + * for its completion. + */ + +static int sa_sync_cmd(struct aac_dev *dev, unsigned long command, unsigned long p1, unsigned long *ret) +{ + unsigned long start; + int ok; + /* + * Write the Command into Mailbox 0 + */ + sa_writel(dev, Mailbox0, cpu_to_le32(command)); + /* + * Write the parameters into Mailboxes 1 - 4 + */ + sa_writel(dev, Mailbox1, cpu_to_le32(p1)); + sa_writel(dev, Mailbox2, 0); + sa_writel(dev, Mailbox3, 0); + sa_writel(dev, Mailbox4, 0); + /* + * Clear the synch command doorbell to start on a clean slate. + */ + sa_writew(dev, DoorbellClrReg_p, DOORBELL_0); + /* + * Signal that there is a new synch command + */ + sa_writew(dev, DoorbellReg_s, DOORBELL_0); + + ok = 0; + start = jiffies; + + while(time_before(jiffies, start+30*HZ)) + { + /* + * Delay 5uS so that the monitor gets access + */ + udelay(5); + /* + * Mon110 will set doorbell0 bit when it has + * completed the command. + */ + if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0) { + ok = 1; + break; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + + if (ok != 1) + return -ETIMEDOUT; + /* + * Clear the synch command doorbell. + */ + sa_writew(dev, DoorbellClrReg_p, DOORBELL_0); + /* + * Pull the synch status from Mailbox 0. + */ + *ret = le32_to_cpu(sa_readl(dev, Mailbox0)); + return 0; +} + +/** + * aac_sa_interrupt_adapter - interrupt an adapter + * @dev: Which adapter to enable. + * + * Breakpoint an adapter. + */ + +static void aac_sa_interrupt_adapter (struct aac_dev *dev) +{ + unsigned long ret; + sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret); +} + +/** + * aac_sa_start_adapter - activate adapter + * @dev: Adapter + * + * Start up processing on an ARM based AAC adapter + */ + +static void aac_sa_start_adapter(struct aac_dev *dev) +{ + unsigned long ret; + struct aac_init *init; + /* + * Fill in the remaining pieces of the init. + */ + init = dev->init; + init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ); + + dprintk(("INIT\n")); + /* + * Tell the adapter we are back and up and running so it will scan its command + * queues and enable our interrupts + */ + dev->irq_mask = (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4); + /* + * First clear out all interrupts. Then enable the one's that + * we can handle. + */ + dprintk(("MASK\n")); + sa_writew(dev, SaDbCSR.PRISETIRQMASK, cpu_to_le16(0xffff)); + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4)); + dprintk(("SYNCCMD\n")); + sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (unsigned long) dev->init_pa, &ret); +} + +/** + * aac_sa_init - initialize an ARM based AAC card + * @dev: device to configure + * @devnum: adapter number + * + * Allocate and set up resources for the ARM based AAC variants. The + * device_interface in the commregion will be allocated and linked + * to the comm region. + */ + +int aac_sa_init(struct aac_dev *dev, unsigned long devnum) +{ + unsigned long start; + unsigned long status; + int instance; + const char *name; + + dev->devnum = devnum; + + dprintk(("PREINST\n")); + instance = dev->id; + name = dev->name; + + /* + * Map in the registers from the adapter. + */ + dprintk(("PREMAP\n")); + + if((dev->regs.sa = (struct sa_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL) + { + printk(KERN_WARNING "aacraid: unable to map ARM.\n" ); + return -1; + } + /* + * Check to see if the board failed any self tests. + */ + if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) { + printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance); + return -1; + } + /* + * Check to see if the board panic'd while booting. + */ + if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) { + printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance); + return -1; + } + start = jiffies; + /* + * Wait for the adapter to be up and running. Wait up to 3 minutes. + */ + while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) { + if (time_after(start+180*HZ, jiffies)) { + status = sa_readl(dev, Mailbox7) >> 16; + printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %d.\n", name, instance, le32_to_cpu(status)); + return -1; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + + dprintk(("ATIRQ\n")); + if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev ) < 0) { + printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", name, instance); + return -1; + } + + /* + * Fill in the function dispatch table. + */ + + dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter; + dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt; + dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt; + dev->a_ops.adapter_notify = aac_sa_notify_adapter; + + dprintk(("FUNCDONE\n")); + + if(aac_init_adapter(dev) == NULL) + return -1; + + dprintk(("NEWADAPTDONE\n")); + /* + * Start any kernel threads needed + */ + dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0); + /* + * Tell the adapter that all is configure, and it can start + * accepting requests + */ + dprintk(("STARTING\n")); + aac_sa_start_adapter(dev); + dprintk(("STARTED\n")); + return 0; +} + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/advansys.c linux-2.5/drivers/scsi/advansys.c --- linux-2.5.5/drivers/scsi/advansys.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/scsi/advansys.c Fri Feb 15 15:57:07 2002 @@ -1,4 +1,4 @@ -#define ASC_VERSION "3.3GG" /* AdvanSys Driver Version */ +#define ASC_VERSION "3.3GI" /* AdvanSys Driver Version */ /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters @@ -670,7 +670,7 @@ 1. Return an error from narrow boards if passed a 16 byte CDB. The wide board can already handle 16 byte CDBs. - 3.3GG (01/02/02): + 3.3GI (2/07/02): 1. hacks for lk 2.5 series (D. Gilbert) I. Known Problems/Fix List (XXX) @@ -752,7 +752,6 @@ */ -#error Please convert me to Documentation/DMA-mapping.txt /* * --- Linux Version @@ -869,8 +868,8 @@ * will give us time to change the HW and FW to handle 64-bit * addresses. */ -#define ASC_VADDR_TO_U32 virt_to_bus -#define ASC_U32_TO_VADDR bus_to_virt +#define ASC_VADDR_TO_U32 __pa +#define ASC_U32_TO_VADDR __va typedef unsigned char uchar; @@ -2151,8 +2150,8 @@ * will give us time to change the HW and FW to handle 64-bit * addresses. */ -#define ADV_VADDR_TO_U32 virt_to_bus -#define ADV_U32_TO_VADDR bus_to_virt +#define ADV_VADDR_TO_U32 __pa +#define ADV_U32_TO_VADDR __va #define AdvPortAddr ulong /* Virtual memory address size */ @@ -3614,23 +3613,6 @@ #define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif /* CONFIG_PROC_FS */ -/* - * XXX - Release and acquire the io_request_lock. These macros are needed - * because the 2.4 kernel SCSI mid-level driver holds the 'io_request_lock' - * on entry to SCSI low-level drivers. - * - * These definitions and all code that uses code should be removed when the - * SCSI mid-level driver no longer holds the 'io_request_lock' on entry to - * SCSI low-level driver detect, queuecommand, and reset entrypoints. - * - * The interrupt flags values doesn't matter in the macros because the - * SCSI mid-level will save and restore the flags values before and after - * calling advansys_detect, advansys_queuecommand, and advansys_reset where - * these macros are used. We do want interrupts enabled after the lock is - * released so an explicit sti() is done. The driver only needs interrupts - * disabled when it acquires the per board lock. - */ - /* Asc Library return codes */ #define ASC_TRUE 1 #define ASC_FALSE 0 @@ -4822,7 +4804,7 @@ boardp->id = asc_board_count - 1; /* Initialize spinlock. */ - boardp->lock = SPIN_LOCK_UNLOCKED; /* replaced by host_lock dpg */ + boardp->lock = SPIN_LOCK_UNLOCKED; /* * Handle both narrow and wide boards. @@ -5872,7 +5854,7 @@ /* host_lock taken by mid-level prior to call but need to protect */ /* against own ISR */ - spin_lock_irqsave(boardp->lock, flags); + spin_lock_irqsave(&boardp->lock, flags); /* * Block new commands while handling a reset or abort request. @@ -6676,7 +6658,7 @@ asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target); asc_scsi_q.q1.target_lun = scp->lun; asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun); - asc_scsi_q.q1.sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); + asc_scsi_q.q1.sense_addr = cpu_to_le32(__pa(&scp->sense_buffer[0])); asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer); /* @@ -6707,7 +6689,7 @@ */ ASC_STATS(scp->host, cont_cnt); asc_scsi_q.q1.data_addr = - cpu_to_le32(virt_to_bus(scp->request_buffer)); + cpu_to_le32(__pa(scp->request_buffer)); asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen); ASC_STATS_ADD(scp->host, cont_xfer, ASC_CEILING(scp->request_bufflen, 512)); @@ -6751,8 +6733,7 @@ slp = (struct scatterlist *) scp->request_buffer; for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) { asc_sg_head.sg_list[sgcnt].addr = - cpu_to_le32(virt_to_bus(slp->address ? - (unsigned char *)slp->address : + cpu_to_le32(__pa( (unsigned char *)page_address(slp->page) + slp->offset)); asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length); ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); @@ -6848,7 +6829,7 @@ scsiqp->target_id = scp->target; scsiqp->target_lun = scp->lun; - scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); + scsiqp->sense_addr = cpu_to_le32(__pa(&scp->sense_buffer[0])); scsiqp->sense_len = sizeof(scp->sense_buffer); /* @@ -6857,7 +6838,7 @@ */ scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen); scsiqp->vdata_addr = scp->request_buffer; - scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer)); + scsiqp->data_addr = cpu_to_le32(__pa(scp->request_buffer)); if (scp->use_sg == 0) { /* @@ -6977,7 +6958,7 @@ * the allocated ADV_SG_BLOCK structure. */ sg_block = (ADV_SG_BLOCK *) ADV_8BALIGN(&sgblkp->sg_block); - sg_block_paddr = virt_to_bus(sg_block); + sg_block_paddr = __pa(sg_block); /* * Check if this is the first 'adv_sgblk_t' for the request. @@ -7011,9 +6992,8 @@ for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) { sg_block->sg_list[i].sg_addr = - cpu_to_le32(virt_to_bus(slp->address ? - (unsigned char *)slp->address : - (unsigned char *)page_address(slp->page) + slp->offset)); + cpu_to_le32(__pa( + (unsigned char *)page_address(slp->page) + slp->offset)); sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length); ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); @@ -9162,7 +9142,7 @@ { ADV_PADDR paddr; - paddr = virt_to_bus(vaddr); + paddr = __pa(vaddr); ASC_DBG4(4, "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n", @@ -9415,8 +9395,8 @@ printk("Scsi_Host at addr 0x%lx\n", (ulong) s); printk( -" next 0x%lx, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n", - (ulong) s->next, s->extra_bytes, s->host_busy, s->host_no, +" next 0x%lx, host_busy %u, host_no %d, last_reset %d,\n", + (ulong) s->next, s->host_busy, s->host_no, (unsigned) s->last_reset); #if ASC_LINUX_KERNEL24 @@ -12764,7 +12744,7 @@ ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id)); /* Align overrun buffer on an 8 byte boundary. */ - phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf); + phy_addr = __pa(asc_dvc->cfg->overrun_buf); phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7); AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D, (uchar *) &phy_addr, 1); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aha1542.c linux-2.5/drivers/scsi/aha1542.c --- linux-2.5.5/drivers/scsi/aha1542.c Wed Feb 20 02:10:52 2002 +++ linux-2.5/drivers/scsi/aha1542.c Wed Feb 20 01:10:06 2002 @@ -168,6 +168,7 @@ static struct Scsi_Host *aha_host[7]; /* One for each IRQ level (9-15) */ +static spinlock_t aha1542_lock = SPIN_LOCK_UNLOCKED; @@ -218,31 +219,34 @@ static int aha1542_out(unsigned int base, unchar * cmdp, int len) { unsigned long flags = 0; + int got_lock; - save_flags(flags); if (len == 1) { + got_lock = 0; while (1 == 1) { WAIT(STATUS(base), CDF, 0, CDF); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); if (inb(STATUS(base)) & CDF) { - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); continue; } outb(*cmdp, DATA(base)); - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); return 0; } } else { - cli(); + spin_lock_irqsave(&aha1542_lock, flags); + got_lock = 1; while (len--) { WAIT(STATUS(base), CDF, 0, CDF); outb(*cmdp++, DATA(base)); } - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); } return 0; fail: - restore_flags(flags); + if (got_lock) + spin_unlock_irqrestore(&aha1542_lock, flags); printk(KERN_ERR "aha1542_out failed(%d): ", len + 1); aha1542_stat(); return 1; @@ -255,16 +259,15 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); while (len--) { WAIT(STATUS(base), DF, DF, 0); *cmdp++ = inb(DATA(base)); } - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); return 0; fail: - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); printk(KERN_ERR "aha1542_in failed(%d): ", len + 1); aha1542_stat(); return 1; @@ -277,16 +280,15 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); while (len--) { WAITd(STATUS(base), DF, DF, 0, 100); *cmdp++ = inb(DATA(base)); } - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); return 0; fail: - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); return 1; } @@ -484,8 +486,7 @@ } aha1542_intr_reset(shost->io_port); - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); mbi = HOSTDATA(shost)->aha1542_last_mbi_used + 1; if (mbi >= 2 * AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES; @@ -499,7 +500,7 @@ } while (mbi != HOSTDATA(shost)->aha1542_last_mbi_used); if (mb[mbi].status == 0) { - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); /* Hmm, no mail. Must have read it the last time around */ if (!number_serviced && !needs_restart) printk(KERN_WARNING "aha1542.c: interrupt received, but no mail.\n"); @@ -514,7 +515,7 @@ mbistatus = mb[mbi].status; mb[mbi].status = 0; HOSTDATA(shost)->aha1542_last_mbi_used = mbi; - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); #ifdef DEBUG { @@ -653,8 +654,7 @@ /* Use the outgoing mailboxes in a round-robin fashion, because this is how the host adapter will scan for them */ - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1; if (mbo >= AHA1542_MAILBOXES) mbo = 0; @@ -674,7 +674,7 @@ screwing with this cdb. */ HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo; - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); #ifdef DEBUG printk(KERN_DEBUG "Sending command (%d %x)...", mbo, done); @@ -1242,18 +1242,17 @@ DEB(aha1542_stat()); DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level)); - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); if (request_irq(irq_level, do_aha1542_intr_handle, 0, "aha1542", NULL)) { printk(KERN_ERR "Unable to allocate IRQ for adaptec controller.\n"); - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); goto unregister; } if (dma_chan != 0xFF) { if (request_dma(dma_chan, "aha1542")) { printk(KERN_ERR "Unable to allocate DMA channel for Adaptec.\n"); free_irq(irq_level, NULL); - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); goto unregister; } if (dma_chan == 0 || dma_chan >= 5) { @@ -1274,7 +1273,7 @@ HOSTDATA(shpnt)->aha1542_last_mbi_used = (2 * AHA1542_MAILBOXES - 1); HOSTDATA(shpnt)->aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1); memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint)); - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); #if 0 DEB(printk(" *** READ CAPACITY ***\n")); @@ -1376,8 +1375,7 @@ ccb = HOSTDATA(SCpnt->host)->ccb; mb = HOSTDATA(SCpnt->host)->mb; - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1; if (mbo >= AHA1542_MAILBOXES) mbo = 0; @@ -1398,7 +1396,7 @@ screwing with this cdb. */ HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo; - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); any2scsi(mb[mbo].ccbptr, SCSI_BUF_PA(&ccb[mbo])); /* This gets trashed for some reason */ @@ -1606,8 +1604,7 @@ inb(STATUS(SCpnt->host->io_port)), inb(INTRFLAGS(SCpnt->host->io_port))); - save_flags(flags); - cli(); + spin_lock_irqsave(&aha1542_lock, flags); mb = HOSTDATA(SCpnt->host)->mb; mbi = HOSTDATA(SCpnt->host)->aha1542_last_mbi_used + 1; if (mbi >= 2 * AHA1542_MAILBOXES) @@ -1620,7 +1617,7 @@ if (mbi >= 2 * AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES; } while (mbi != HOSTDATA(SCpnt->host)->aha1542_last_mbi_used); - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); if (mb[mbi].status) { printk(KERN_ERR "Lost interrupt discovered on irq %d - attempting to recover\n", @@ -1648,15 +1645,17 @@ DEB(printk("aha1542_abort\n")); #if 0 - save_flags(flags); - cli(); - for (mbo = 0; mbo < AHA1542_MAILBOXES; mbo++) + spin_lock_irqsave(&aha1542_lock, flags); + for (mbo = 0; mbo < AHA1542_MAILBOXES; mbo++) { if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]) { mb[mbo].status = 2; /* Abort command */ aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* start scsi command */ - restore_flags(flags); + spin_unlock_irqrestore(&aha1542_lock, flags); break; - }; + } + } + if (AHA1542_MAILBOXES == mbo) + spin_unlock_irqrestore(&aha1542_lock, flags); #endif return SCSI_ABORT_SNOOZE; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aic7xxx/aic7xxx.c linux-2.5/drivers/scsi/aic7xxx/aic7xxx.c --- linux-2.5.5/drivers/scsi/aic7xxx/aic7xxx.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aic7xxx.c Sun Mar 3 17:54:35 2002 @@ -2584,7 +2584,7 @@ /* * Read the latched byte, but turn off SPIOEN first - * so that we don't inadvertantly cause a REQ for the + * so that we don't inadvertently cause a REQ for the * next byte. */ ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aic7xxx/aic7xxx_linux.c linux-2.5/drivers/scsi/aic7xxx/aic7xxx_linux.c --- linux-2.5.5/drivers/scsi/aic7xxx/aic7xxx_linux.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/scsi/aic7xxx/aic7xxx_linux.c Mon Feb 18 23:08:02 2002 @@ -445,7 +445,7 @@ struct ahc_linux_device*); static void ahc_linux_run_device_queue(struct ahc_softc*, struct ahc_linux_device*); -static void ahc_linux_setup_tag_info(char *p, char *end); +static void ahc_linux_setup_tag_info(char *p, char *end, char *s); static int ahc_linux_next_unit(void); static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf); @@ -906,7 +906,7 @@ } static void -ahc_linux_setup_tag_info(char *p, char *end) +ahc_linux_setup_tag_info(char *p, char *end, char *s) { char *base; char *tok; @@ -986,7 +986,7 @@ } } while ((p != base) && (p != NULL)) - p = strtok(NULL, ",."); + p = strsep(&s, ",."); } /* @@ -1018,7 +1018,8 @@ end = strchr(s, '\0'); - for (p = strtok(s, ",."); p; p = strtok(NULL, ",.")) { + while ((p = strsep(&s, ",.")) != NULL) { + if (!*p) continue; for (i = 0; i < NUM_ELEMENTS(options); i++) { n = strlen(options[i].name); @@ -1026,7 +1027,7 @@ continue; if (strncmp(p, "tag_info", n) == 0) { - ahc_linux_setup_tag_info(p + n, end); + ahc_linux_setup_tag_info(p + n, end, s); } else if (p[n] == ':') { *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aic7xxx/aicasm/aicdb.h linux-2.5/drivers/scsi/aic7xxx/aicasm/aicdb.h --- linux-2.5.5/drivers/scsi/aic7xxx/aicasm/aicdb.h Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/scsi/aic7xxx/aicasm/aicdb.h Mon Jan 7 21:43:21 2002 @@ -0,0 +1 @@ +#include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/aic7xxx_old.c linux-2.5/drivers/scsi/aic7xxx_old.c --- linux-2.5.5/drivers/scsi/aic7xxx_old.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/scsi/aic7xxx_old.c Mon Feb 18 20:50:38 2002 @@ -1443,7 +1443,7 @@ end = strchr(s, '\0'); - for (p = strtok(s, ",."); p; p = strtok(NULL, ",.")) + while ((p = strsep(&s, ",.")) != NULL) { for (i = 0; i < NUMBER(options); i++) { @@ -1525,7 +1525,7 @@ } } while((p != base) && (p != NULL)) - p = strtok(NULL, ",."); + p = strsep(&s, ",."); } } else if (p[n] == ':') diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/dtc.c linux-2.5/drivers/scsi/dtc.c --- linux-2.5.5/drivers/scsi/dtc.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/scsi/dtc.c Thu Dec 13 16:32:36 2001 @@ -1,13 +1,11 @@ - #define AUTOSENSE #define PSEUDO_DMA #define DONT_USE_INTR -#define UNSAFE /* Leave interrupts enabled during pseudo-dma I/O */ +#define UNSAFE /* Leave interrupts enabled during pseudo-dma I/O */ #define xNDEBUG (NDEBUG_INTR+NDEBUG_RESELECTION+\ NDEBUG_SELECTION+NDEBUG_ARBITRATION) #define DMA_WORKS_RIGHT - /* * DTC 3180/3280 driver, by * Ray Van Tassle rayvt@comm.mot.com @@ -65,6 +63,7 @@ 6 = yellow 7 = white */ + #if 0 #define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);} #else @@ -102,336 +101,318 @@ */ /* - */ + */ /* Offset from DTC_5380_OFFSET */ #define DTC_CONTROL_REG 0x100 /* rw */ #define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ #define CSR_DIR_READ 0x40 /* rw direction, 1 = read 0 = write */ -#define CSR_RESET 0x80 /* wo Resets 53c400 */ -#define CSR_5380_REG 0x80 /* ro 5380 registers can be accessed */ -#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ -#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ -#define CSR_5380_INTR 0x10 /* rw Enable 5380 interrupts */ -#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ -#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Host buffer not ready */ -#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer ready */ -#define CSR_GATED_5380_IRQ 0x01 /* ro Last block xferred */ +#define CSR_RESET 0x80 /* wo Resets 53c400 */ +#define CSR_5380_REG 0x80 /* ro 5380 registers can be accessed */ +#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ +#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ +#define CSR_5380_INTR 0x10 /* rw Enable 5380 interrupts */ +#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ +#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Host buffer not ready */ +#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer ready */ +#define CSR_GATED_5380_IRQ 0x01 /* ro Last block xferred */ #define CSR_INT_BASE (CSR_SCSI_BUFF_INTR | CSR_5380_INTR) -#define DTC_BLK_CNT 0x101 /* rw +#define DTC_BLK_CNT 0x101 /* rw * # of 128-byte blocks to transfer */ -#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ +#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ #define DTC_SWITCH_REG 0x3982 /* ro - DIP switches */ #define DTC_RESUME_XFER 0x3982 /* wo - resume data xfer - * after disconnect/reconnect*/ + * after disconnect/reconnect */ #define DTC_5380_OFFSET 0x3880 /* 8 registers here, see NCR5380.h */ /*!!!! for dtc, it's a 128 byte buffer at 3900 !!! */ -#define DTC_DATA_BUF 0x3900 /* rw 128 bytes long */ +#define DTC_DATA_BUF 0x3900 /* rw 128 bytes long */ static struct override { - unsigned int address; - int irq; + unsigned int address; + int irq; } overrides #ifdef OVERRIDE [] __initdata = OVERRIDE; #else -[4] __initdata = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, {0, IRQ_AUTO}, {0, IRQ_AUTO}}; +[4] __initdata = { + {0, IRQ_AUTO}, + {0, IRQ_AUTO}, + {0, IRQ_AUTO}, + {0, IRQ_AUTO} +}; #endif #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) static struct base { - unsigned long address; - int noauto; -} bases[] __initdata = {{0xcc000, 0}, {0xc8000, 0}, {0xdc000, 0}, {0xd8000, 0}}; + unsigned long address; + int noauto; +} bases[] __initdata = { + {0xcc000, 0}, + {0xc8000, 0}, + {0xdc000, 0}, + {0xd8000, 0} +}; #define NO_BASES (sizeof (bases) / sizeof (struct base)) static const struct signature { - const char *string; - int offset; -} signatures[] = { {"DATA TECHNOLOGY CORPORATION BIOS", 0x25}, }; + const char *string; + int offset; +} signatures[] = { + {"DATA TECHNOLOGY CORPORATION BIOS", 0x25}, +}; #define NO_SIGNATURES (sizeof (signatures) / sizeof (struct signature)) -/* - * Function : dtc_setup(char *str, int *ints) - * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. +/** + * dtc_setup - option setup for dtc3x80 * -*/ + * LILO command line initialization of the overrides array, + */ -void __init dtc_setup(char *str, int *ints){ - static int commandline_current = 0; - int i; - if (ints[0] != 2) - printk("dtc_setup: usage dtc=address,irq\n"); - else - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].address = ints[1]; - overrides[commandline_current].irq = ints[2]; - for (i = 0; i < NO_BASES; ++i) - if (bases[i].address == ints[1]) { - bases[i].noauto = 1; - break; - } - ++commandline_current; - } +static int __init dtc_setup(char *str) +{ + static int commandline_current = 0; + int i; + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + + if (ints[0] != 2) + printk(KERN_ERR "dtc_setup: usage dtc=address,irq\n"); + else if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].address = ints[1]; + overrides[commandline_current].irq = ints[2]; + for (i = 0; i < NO_BASES; ++i) + if (bases[i].address == ints[1]) { + bases[i].noauto = 1; + break; + } + ++commandline_current; + } + return 1; } -/* - * Function : int dtc_detect(Scsi_Host_Template * tpnt) +__setup("dtc=", dtc_setup); + +/** + * dtc_detect - detect DTC 3x80 controllers + * @tpnt: controller template * - * Purpose : detects and initializes DTC 3180/3280 controllers + * Detects and initializes DTC 3180/3280 controllers * that were autoprobed, overridden on the LILO command line, * or specified at compile time. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. - * -*/ - -int __init dtc_detect(Scsi_Host_Template * tpnt){ - static int current_override = 0, current_base = 0; - struct Scsi_Host *instance; - unsigned int base; - int sig, count; - - tpnt->proc_name = "dtc3x80"; - tpnt->proc_info = &dtc_proc_info; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - base = 0; - - if (overrides[current_override].address) - base = overrides[current_override].address; - else - for (; !base && (current_base < NO_BASES); ++current_base) { -#if (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi-dtc : probing address %08x\n", bases[current_base].address); -#endif - for (sig = 0; sig < NO_SIGNATURES; ++sig) - if (!bases[current_base].noauto && - isa_check_signature(bases[current_base].address + - signatures[sig].offset, - signatures[sig].string, strlen(signatures[sig].string))) { - base = bases[current_base].address; -#if (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi-dtc : detected board.\n"); -#endif - break; - } - } - -#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi-dtc : base = %08x\n", base); -#endif - - if (!base) - break; + */ - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - break; - - instance->base = base; - - NCR5380_init(instance, 0); - - NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); /* Enable int's */ - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, DTC_IRQS); +int __init dtc_detect(Scsi_Host_Template * tpnt) +{ + static int current_override = 0, current_base = 0; + struct Scsi_Host *instance; + unsigned int base; + int sig, count; + + tpnt->proc_name = "dtc3x80"; + tpnt->proc_info = &dtc_proc_info; + + for (count = 0; current_override < NO_OVERRIDES; ++current_override) + { + base = 0; + + if (overrides[current_override].address) + base = overrides[current_override].address; + else + { + for (; !base && (current_base < NO_BASES); ++current_base) { + for (sig = 0; sig < NO_SIGNATURES; ++sig) + { + if (!bases[current_base].noauto && isa_check_signature(bases[current_base].address + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) { + base = bases[current_base].address; + break; + } + } + } + } + + if (!base) + break; + + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) + break; + + instance->base = base; + + NCR5380_init(instance, 0); + + NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); /* Enable int's */ + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, DTC_IRQS); #ifndef DONT_USE_INTR -/* With interrupts enabled, it will sometimes hang when doing heavy - * reads. So better not enable them until I finger it out. */ - if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_dtc_intr, SA_INTERRUPT, "dtc", instance)) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = IRQ_NONE; - } - - if (instance->irq == IRQ_NONE) { - printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - } + /* With interrupts enabled, it will sometimes hang when doing heavy + * reads. So better not enable them until I figure it out. */ + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, do_dtc_intr, SA_INTERRUPT, "dtc")) + { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq == IRQ_NONE) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + } #else - if (instance->irq != IRQ_NONE) - printk("scsi%d : interrupts not used. Might as well not jumper it.\n", - instance->host_no); - instance->irq = IRQ_NONE; + if (instance->irq != IRQ_NONE) + printk(KERN_INFO "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no); + instance->irq = IRQ_NONE; #endif -#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi%d : irq = %d\n", instance->host_no, instance->irq); -#endif - - printk("scsi%d : at 0x%05X", instance->host_no, (int)instance->base); - if (instance->irq == IRQ_NONE) - printk (" interrupts disabled"); - else - printk (" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; + printk(KERN_INFO "scsi%d : at 0x%05X", instance->host_no, (int) instance->base); + if (instance->irq == IRQ_NONE) + printk(" interrupts disabled"); + else + printk(" irq %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); + + ++current_override; + ++count; + } + return count; } -/* - * Function : int dtc_biosparam(Disk * disk, kdev_t dev, int *ip) +/** + * dtc_biosparam - compute disk geometry + * @disk: disk to generate for + * @dev: major/minor of device + * @ip: returned geometry * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for + * Generates a BIOS / DOS compatible H-C-S mapping for * the specified device / size. - * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} - * - * Returns : always 0 (success), initializes ip - * -*/ - -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. -*/ + */ -int dtc_biosparam(Disk * disk, kdev_t dev, int * ip) +int dtc_biosparam(Disk * disk, kdev_t dev, int *ip) { - int size = disk->capacity; + int size = disk->capacity; - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - return 0; + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + return 0; } -/**************************************************************** - * Function : int NCR5380_pread (struct Scsi_Host *instance, - * unsigned char *dst, int len) - * - * Purpose : Fast 5380 pseudo-dma read function, reads len bytes to - * dst - * - * Inputs : dst = destination, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. -*/ - static int dtc_maxi = 0; static int dtc_wmaxi = 0; -static inline int NCR5380_pread (struct Scsi_Host *instance, - unsigned char *dst, int len) - { - unsigned char *d = dst; - int i; /* For counting time spent in the poll-loop */ - NCR5380_local_declare(); - NCR5380_setup(instance); - - i = 0; - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); - if (instance->irq == IRQ_NONE) - NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ); - else - NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE); - NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ - rtrc(1); - while (len > 0) { - rtrc(2); - while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) - ++i; - rtrc(3); - isa_memcpy_fromio(d, base + DTC_DATA_BUF, 128); - d += 128; - len -= 128; - rtrc(7); /*** with int's on, it sometimes hangs after here. +/** + * NCR5380_pread - fast pseudo DMA read + * @instance: controller + * @dst: destination buffer + * @len: expected/max size + * + * Fast 5380 pseudo-dma read function, reads len bytes from the controller + * mmio area into dst. + */ + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) +{ + unsigned char *d = dst; + int i; /* For counting time spent in the poll-loop */ + NCR5380_local_declare(); + NCR5380_setup(instance); + + i = 0; + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); + if (instance->irq == IRQ_NONE) + NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ); + else + NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE); + NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ + rtrc(1); + while (len > 0) { + rtrc(2); + while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) + ++i; + rtrc(3); + isa_memcpy_fromio(d, base + DTC_DATA_BUF, 128); + d += 128; + len -= 128; + rtrc(7); + /*** with int's on, it sometimes hangs after here. * Looks like something makes HBNR go away. */ - } - rtrc(4); - while ( !(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) - ++i; - NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ - rtrc(0); - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - if (i > dtc_maxi) - dtc_maxi = i; - return(0); + } + rtrc(4); + while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) + ++i; + NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ + rtrc(0); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + if (i > dtc_maxi) + dtc_maxi = i; + return (0); } -/**************************************************************** - * Function : int NCR5380_pwrite (struct Scsi_Host *instance, - * unsigned char *src, int len) +/** + * NCR5380_pwrite - fast pseudo DMA write + * @instance: controller + * @dst: destination buffer + * @len: expected/max size * - * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from - * src - * - * Inputs : src = source, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. -*/ + * Fast 5380 pseudo-dma write function, writes len bytes to the + * controller mmio area from src. + */ -static inline int NCR5380_pwrite (struct Scsi_Host *instance, - unsigned char *src, int len) { - int i; - NCR5380_local_declare(); - NCR5380_setup(instance); - - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); - /* set direction (write) */ - if (instance->irq == IRQ_NONE) - NCR5380_write(DTC_CONTROL_REG, 0); - else - NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); - NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ - for (i = 0; len > 0; ++i) { - rtrc(5); - /* Poll until the host buffer can accept data. */ - while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) - ++i; - rtrc(3); - isa_memcpy_toio(base + DTC_DATA_BUF, src, 128); - src += 128; - len -= 128; - } - rtrc(4); - while ( !(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) - ++i; - rtrc(6); - /* Wait until the last byte has been sent to the disk */ - while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) - ++i; - rtrc(7); - /* Check for parity error here. fixme. */ - NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ - rtrc(0); - if (i > dtc_wmaxi) - dtc_wmaxi = i; - return (0); +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) +{ + int i; + NCR5380_local_declare(); + NCR5380_setup(instance); + + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); + /* set direction (write) */ + if (instance->irq == IRQ_NONE) + NCR5380_write(DTC_CONTROL_REG, 0); + else + NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); + NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ + for (i = 0; len > 0; ++i) { + rtrc(5); + /* Poll until the host buffer can accept data. */ + while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) + ++i; + rtrc(3); + isa_memcpy_toio(base + DTC_DATA_BUF, src, 128); + src += 128; + len -= 128; + } + rtrc(4); + while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) + ++i; + rtrc(6); + /* Wait until the last byte has been sent to the disk */ + while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) + ++i; + rtrc(7); + /* Check for parity error here. fixme. */ + NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ + rtrc(0); + if (i > dtc_wmaxi) + dtc_wmaxi = i; + return (0); } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/eata.c linux-2.5/drivers/scsi/eata.c --- linux-2.5.5/drivers/scsi/eata.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/scsi/eata.c Tue Feb 26 21:24:49 2002 @@ -1,6 +1,13 @@ /* * eata.c - Low-level driver for EATA/DMA SCSI host adapters. * + * 20 Feb 2002 Rev. 7.22 for linux 2.5.5 + * + Remove any reference to virt_to_bus(). + * + Fix pio hang while detecting multiple HBAs. + * + Fixed a board detection bug: in a system with + * multiple ISA/EISA boards, all but the first one + * were erroneously detected as PCI. + * * 01 Jan 2002 Rev. 7.20 for linux 2.5.1 * + Use the dynamic DMA mapping API. * @@ -29,7 +36,7 @@ * boot time. * + Improved boot messages: all tagged capable device are * indicated as "tagged" or "soft-tagged" : - * - "soft-tagged" means that the driver is trying to do its + * - "soft-tagged" means that the driver is trying to do its * own tagging (i.e. the tc:y option is in effect); * - "tagged" means that the device supports tagged commands, * but the driver lets the HBA be responsible for tagging @@ -40,7 +47,7 @@ * + When loaded as a module, accepts the new parameter boot_options * which value is a string with the same format of the kernel boot * command line options. A valid example is: - * modprobe eata boot_options=\"0x7410,0x230,lc:y,tc:n,mq:4\" + * modprobe eata 'boot_options="0x7410,0x230,lc:y,tc:n,mq:4"' * * 9 Sep 1999 Rev. 5.10 for linux 2.2.12 and 2.3.17 * + 64bit cleanup for Linux/Alpha platform support @@ -304,7 +311,7 @@ * include in the list of i/o ports to be probed all the PCI SCSI controllers. * * Due to a DPT BIOS "feature", it might not be possible to force an EISA - * address on more then a single DPT PCI board, so in this case you have to + * address on more than a single DPT PCI board, so in this case you have to * let the PCI BIOS assign the addresses. * * The sequence of detection probes is: @@ -401,8 +408,6 @@ * the driver sets host->wish_block = TRUE for all ISA boards. */ -#error Please convert me to Documentation/DMA-mapping.txt - #include #ifndef LinuxVersionCode @@ -454,7 +459,7 @@ #define ISA 0 #define ESA 1 -#undef FORCE_CONFIG +#undef FORCE_CONFIG #undef DEBUG_LINKED_COMMANDS #undef DEBUG_DETECT @@ -645,11 +650,18 @@ u_int32_t data_address; /* If sg=0 Data Address, if sg=1 sglist address */ u_int32_t sp_dma_addr; /* Address where sp is DMA'ed when cp completes */ u_int32_t sense_addr; /* Address where Sense Data is DMA'ed on error */ + /* Additional fields begin here. */ Scsi_Cmnd *SCpnt; - struct sg_list *sglist; + + /* All the cp structure is zero filled by queuecommand except the + following CP_TAIL_SIZE bytes, initialized by detect */ + dma_addr_t cp_dma_addr; /* dma handle for this cp structure */ + struct sg_list *sglist; /* pointer to the allocated SG list */ }; +#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t)) + struct hostdata { struct mscp cp[MAX_MAILBOXES]; /* Mailboxes for this board */ unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */ @@ -657,7 +669,6 @@ unsigned int iocount; /* Total i/o done for this board */ int board_number; /* Number of this board */ char board_name[16]; /* Name of this board */ - char board_id[256]; /* data from INQUIRY on this board */ int in_reset; /* True if board is doing a reset */ int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */ int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */ @@ -675,6 +686,7 @@ static struct Scsi_Host *sh[MAX_BOARDS + 1]; static const char *driver_name = "EATA"; static char sha[MAX_BOARDS]; +static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; /* Initialize num_boards so that ihdlr can work while detect is in progress */ static unsigned int num_boards = MAX_BOARDS; @@ -710,8 +722,6 @@ #define H2DEV(x) cpu_to_be32(x) #define DEV2H(x) be32_to_cpu(x) -#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0) - static void do_interrupt_handler(int, void *, struct pt_regs *); static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int); static int do_trace = FALSE; @@ -813,7 +823,7 @@ if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) return TRUE; - if ((addr = V2DEV(addr))) { + if ((addr = H2DEV(addr))) { outb((char) (addr >> 24), iobase + REG_LOW); outb((char) (addr >> 16), iobase + REG_LM); outb((char) (addr >> 8), iobase + REG_MID); @@ -919,7 +929,8 @@ else protocol_rev = 'C'; - if (!setup_done && j > 0 && j <= MAX_PCI) { + if (protocol_rev != 'A' && info.forcaddr) { + printk("%s: warning, port address has been forced.\n", name); bus_type = "PCI"; is_pci = TRUE; subversion = ESA; @@ -982,7 +993,7 @@ if (is_pci) { pdev = get_pci_dev(port_base); - if (!pdev) + if (!pdev) printk("%s: warning, failed to get pci_dev structure.\n", name); } else @@ -1012,18 +1023,29 @@ #if defined(FORCE_CONFIG) { - struct eata_config config; + struct eata_config *cf; + dma_addr_t cf_dma_addr; + + cf = pci_alloc_consistent(pdev, sizeof(struct eata_config), &cf_dma_addr); + + if (!cf) { + printk("%s: config, pci_alloc_consistent failed, detaching.\n", name); + release_region(port_base, REGION_SIZE); + return FALSE; + } /* Set board configuration */ - memset((char *)&config, 0, sizeof(struct eata_config)); - config.len = (ushort) cpu_to_be16((ushort)510); - config.ocena = TRUE; + memset((char *)cf, 0, sizeof(struct eata_config)); + cf->len = (ushort) cpu_to_be16((ushort)510); + cf->ocena = TRUE; - if (do_dma(port_base, (unsigned long)&config, SET_CONFIG_DMA)) { + if (do_dma(port_base, cf_dma_addr, SET_CONFIG_DMA)) { printk("%s: busy timeout sending configuration, detaching.\n", name); + pci_free_consistent(pdev, sizeof(struct eata_config), cf, cf_dma_addr); release_region(port_base, REGION_SIZE); return FALSE; } + } #endif @@ -1111,6 +1133,10 @@ else sprintf(dma_name, "DMA %u", dma_channel); for (i = 0; i < sh[j]->can_queue; i++) + HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev, + &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); + + for (i = 0; i < sh[j]->can_queue; i++) if (! ((&HD(j)->cp[i])->sglist = kmalloc( sh[j]->sg_tablesize * sizeof(struct sg_list), (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) { @@ -1119,7 +1145,7 @@ return FALSE; } - if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev, + if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev, sizeof(struct mssp), &HD(j)->sp_dma_addr))) { printk("%s: pci_alloc_consistent failed, detaching.\n", BN(j)); eata2x_release(sh[j]); @@ -1279,6 +1305,9 @@ int eata2x_detect(Scsi_Host_Template *tpnt) { unsigned int j = 0, k; + unsigned long spin_flags; + + spin_lock_irqsave(&driver_lock, spin_flags); tpnt->proc_name = "eata2x"; @@ -1304,6 +1333,7 @@ } num_boards = j; + spin_unlock_irqrestore(&driver_lock, spin_flags); return j; } @@ -1324,10 +1354,10 @@ if (!SCpnt->use_sg) { - if (!SCpnt->request_bufflen) - cpp->data_address = V2DEV(SCpnt->request_buffer); + /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */ + if (!SCpnt->request_bufflen) pci_dir = PCI_DMA_BIDIRECTIONAL; - else if (SCpnt->request_buffer) + if (SCpnt->request_buffer) cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir)); @@ -1344,7 +1374,8 @@ } cpp->sg = TRUE; - cpp->data_address = V2DEV(cpp->sglist); + cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist, + SCpnt->use_sg * sizeof(struct sg_list), pci_dir)); cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list))); } @@ -1360,13 +1391,14 @@ pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr), DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - if (SCpnt->use_sg) + if (SCpnt->use_sg) pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); - else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) - pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); + if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; + if (DEV2H(cpp->data_address)) + pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); } static void sync_dma(unsigned int i, unsigned int j) { @@ -1381,14 +1413,15 @@ pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr), DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - if (SCpnt->use_sg) - pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, + if (SCpnt->use_sg) + pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); - else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) - pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); + if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; + if (DEV2H(cpp->data_address)) + pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); } static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) { @@ -1409,8 +1442,7 @@ struct mscp *cpp; Scsi_Cmnd *SCpnt; - cpp = &HD(j)->cp[i]; - SCpnt = cpp->SCpnt; + cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; if (SCpnt->sc_data_direction == SCSI_DATA_READ) { cpp->din = TRUE; @@ -1428,7 +1460,7 @@ return; } - if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) + if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j)); for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) @@ -1479,7 +1511,7 @@ /* Set pointer to control packet structure */ cpp = &HD(j)->cp[i]; - memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *)); + memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE); /* Set pointer to status packet structure, Big Endian format */ cpp->sp_dma_addr = H2DEV(HD(j)->sp_dma_addr); @@ -1536,7 +1568,7 @@ } /* Send control packet to the board */ - if (do_dma(sh[j]->io_port, (unsigned long) cpp, SEND_CP_DMA)) { + if (do_dma(sh[j]->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { unmap_dma(i, j); SCpnt->host_scribble = NULL; printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n", @@ -1935,7 +1967,7 @@ for (n = 0; n < n_ready; n++) { k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - if (do_dma(sh[j]->io_port, (unsigned long) cpp, SEND_CP_DMA)) { + if (do_dma(sh[j]->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { printk("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"\ " busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k); @@ -1985,7 +2017,7 @@ reg = inb(sh[j]->io_port + REG_STATUS); /* Reject any sp with supspect data */ - if (spp->eoc == FALSE) + if (spp->eoc == FALSE && HD(j)->iocount > 1) printk("%s: ihdlr, spp->eoc == FALSE, irq %d, reg 0x%x, count %d.\n", BN(j), irq, reg, HD(j)->iocount); if (spp->cpp_index < 0 || spp->cpp_index >= sh[j]->can_queue) @@ -2191,10 +2223,14 @@ for (i = 0; i < sh[j]->can_queue; i++) if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist); - if (HD(j)->sp_cpu_addr) + for (i = 0; i < sh[j]->can_queue; i++) + pci_unmap_single(HD(j)->pdev, HD(j)->cp[i].cp_dma_addr, + sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); + + if (HD(j)->sp_cpu_addr) pci_free_consistent(HD(j)->pdev, sizeof(struct mssp), HD(j)->sp_cpu_addr, HD(j)->sp_dma_addr); - + free_irq(sh[j]->irq, &sha[j]); if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/eata.h linux-2.5/drivers/scsi/eata.h --- linux-2.5.5/drivers/scsi/eata.h Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/scsi/eata.h Tue Feb 26 21:24:49 2002 @@ -13,7 +13,7 @@ int eata2x_reset(Scsi_Cmnd *); int eata2x_biosparam(Disk *, kdev_t, int *); -#define EATA_VERSION "7.20.00" +#define EATA_VERSION "7.22.00" #define EATA { \ name: "EATA/DMA 2.0x rev. " EATA_VERSION " ", \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/fdomain.c linux-2.5/drivers/scsi/fdomain.c --- linux-2.5.5/drivers/scsi/fdomain.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/scsi/fdomain.c Thu Jan 31 01:44:15 2002 @@ -78,7 +78,7 @@ Please note that the drive ordering that Future Domain implemented in BIOS versions 3.4 and 3.5 is the opposite of the order (currently) used by the rest of the SCSI industry. If you have BIOS version 3.4 or 3.5, and have - more then one drive, then the drive ordering will be the reverse of that + more than one drive, then the drive ordering will be the reverse of that which you see under DOS. For example, under DOS SCSI ID 0 will be D: and SCSI ID 1 will be C: (the boot device). Under Linux, SCSI ID 0 will be /dev/sda and SCSI ID 1 will be /dev/sdb. The Linux ordering is consistent @@ -730,13 +730,13 @@ switch (Quantum) { case 2: /* ISA_200S */ case 3: /* ISA_250MG */ - base = readb(bios_base + 0x1fa2) + (readb(bios_base + 0x1fa3) << 8); + base = isa_readb(bios_base + 0x1fa2) + (isa_readb(bios_base + 0x1fa3) << 8); break; case 4: /* ISA_200S (another one) */ - base = readb(bios_base + 0x1fa3) + (readb(bios_base + 0x1fa4) << 8); + base = isa_readb(bios_base + 0x1fa3) + (isa_readb(bios_base + 0x1fa4) << 8); break; default: - base = readb(bios_base + 0x1fcc) + (readb(bios_base + 0x1fcd) << 8); + base = isa_readb(bios_base + 0x1fcc) + (isa_readb(bios_base + 0x1fcd) << 8); break; } @@ -1956,7 +1956,7 @@ offset = bios_base + 0x1f31 + drive * 25; break; } - memcpy_fromio( &i, offset, sizeof( struct drive_info ) ); + isa_memcpy_fromio( &i, offset, sizeof( struct drive_info ) ); info_array[0] = i.heads; info_array[1] = i.sectors; info_array[2] = i.cylinders; @@ -2043,6 +2043,7 @@ if (shpnt->io_port && shpnt->n_io_port) release_region(shpnt->io_port, shpnt->n_io_port); + return 0; } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/g_NCR5380.c linux-2.5/drivers/scsi/g_NCR5380.c --- linux-2.5.5/drivers/scsi/g_NCR5380.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/scsi/g_NCR5380.c Tue Dec 18 15:31:05 2001 @@ -77,7 +77,7 @@ * IRQ line if overridden on the command line. * */ - + /* * $Log: generic_NCR5380.c,v $ */ @@ -124,787 +124,772 @@ #include #define NCR_NOT_SET 0 -static int ncr_irq=NCR_NOT_SET; -static int ncr_dma=NCR_NOT_SET; -static int ncr_addr=NCR_NOT_SET; -static int ncr_5380=NCR_NOT_SET; -static int ncr_53c400=NCR_NOT_SET; -static int ncr_53c400a=NCR_NOT_SET; -static int dtc_3181e=NCR_NOT_SET; +static int ncr_irq = NCR_NOT_SET; +static int ncr_dma = NCR_NOT_SET; +static int ncr_addr = NCR_NOT_SET; +static int ncr_5380 = NCR_NOT_SET; +static int ncr_53c400 = NCR_NOT_SET; +static int ncr_53c400a = NCR_NOT_SET; +static int dtc_3181e = NCR_NOT_SET; static struct override { NCR5380_implementation_fields; - int irq; - int dma; - int board; /* Use NCR53c400, Ricoh, etc. extensions ? */ -} overrides -#ifdef GENERIC_NCR5380_OVERRIDE - [] __initdata = GENERIC_NCR5380_OVERRIDE; + int irq; + int dma; + int board; /* Use NCR53c400, Ricoh, etc. extensions ? */ +} overrides +#ifdef GENERIC_NCR5380_OVERRIDE +[] __initdata = GENERIC_NCR5380_OVERRIDE; #else - [1] __initdata = {{0,},}; +[1] __initdata = { { 0,},}; #endif #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) -/* - * Function : static internal_setup(int board, char *str, int *ints) +/** + * internal_setup - handle lilo command string override + * @board: BOARD_* identifier for the board + * @str: unused + * @ints: numeric parameters * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : board - either BOARD_NCR5380 for a normal NCR5380 board, - * or BOARD_NCR53C400 for a NCR53C400 board. str - unused, ints - - * array of integer parameters with ints[0] equal to the number of ints. + * Do LILO command line initialization of the overrides array. Display + * errors when needed * + * Locks: none */ -static void __init internal_setup(int board, char *str, int *ints){ - static int commandline_current = 0; - switch (board) { - case BOARD_NCR5380: - if (ints[0] != 2 && ints[0] != 3) { - printk("generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n"); - return; - } - break; - case BOARD_NCR53C400: - if (ints[0] != 2) { - printk("generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - case BOARD_NCR53C400A: - if (ints[0] != 2) { - printk("generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - case BOARD_DTC3181E: - if (ints[0] != 2) { - printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - } - - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type)ints[1]; - overrides[commandline_current].irq = ints[2]; - if (ints[0] == 3) - overrides[commandline_current].dma = ints[3]; - else - overrides[commandline_current].dma = DMA_NONE; - overrides[commandline_current].board = board; - ++commandline_current; - } +static void __init internal_setup(int board, char *str, int *ints) +{ + static int commandline_current = 0; + switch (board) { + case BOARD_NCR5380: + if (ints[0] != 2 && ints[0] != 3) { + printk(KERN_ERR "generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n"); + return; + } + break; + case BOARD_NCR53C400: + if (ints[0] != 2) { + printk(KERN_ERR "generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + case BOARD_NCR53C400A: + if (ints[0] != 2) { + printk(KERN_ERR "generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + case BOARD_DTC3181E: + if (ints[0] != 2) { + printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n"); + return; + } + break; + } + + if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type) ints[1]; + overrides[commandline_current].irq = ints[2]; + if (ints[0] == 3) + overrides[commandline_current].dma = ints[3]; + else + overrides[commandline_current].dma = DMA_NONE; + overrides[commandline_current].board = board; + ++commandline_current; + } } -/* - * Function : generic_NCR5380_setup (char *str, int *ints) +/** + * do_NCR53C80_setup - set up entry point + * @str: unused * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. + * Setup function invoked at boot to parse the ncr5380= command + * line. */ -void __init generic_NCR5380_setup (char *str, int *ints){ - internal_setup (BOARD_NCR5380, str, ints); +static int __init do_NCR5380_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR5380, str, ints); + return 1; } -/* - * Function : generic_NCR53C400_setup (char *str, int *ints) +/** + * do_NCR53C400_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. + * Setup function invoked at boot to parse the ncr53c400= command + * line. */ -void __init generic_NCR53C400_setup (char *str, int *ints){ - internal_setup (BOARD_NCR53C400, str, ints); +static int __init do_NCR53C400_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR53C400, str, ints); + return 1; } -/* - * Function : generic_NCR53C400A_setup (char *str, int *ints) +/** + * do_NCR53C400A_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. + * Setup function invoked at boot to parse the ncr53c400a= command + * line. */ -void generic_NCR53C400A_setup (char *str, int *ints) { - internal_setup (BOARD_NCR53C400A, str, ints); +static int __init do_NCR53C400A_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_NCR53C400A, str, ints); + return 1; } -/* - * Function : generic_DTC3181E_setup (char *str, int *ints) +/** + * do_DTC3181E_setup - set up entry point + * @str: unused + * @ints: integer parameters from kernel setup code * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. + * Setup function invoked at boot to parse the dtc3181e= command + * line. */ -void generic_DTC3181E_setup (char *str, int *ints) { - internal_setup (BOARD_DTC3181E, str, ints); +static int __init do_DTC3181E_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + internal_setup(BOARD_DTC3181E, str, ints); + return 1; } -/* - * Function : int generic_NCR5380_detect(Scsi_Host_Template * tpnt) +/** + * generic_NCR5380_detect - look for NCR5380 controllers + * @tpnt: the scsi template * - * Purpose : initializes generic NCR5380 driver based on the - * command line / compile time port and irq definitions. + * Scan for the present of NCR5380, NCR53C400, NCR53C400A, DTC3181E + * and DTC436(ISAPnP) controllers. If overrides have been set we use + * them. * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. + * The caller supplied NCR5380_init function is invoked from here, before + * the interrupt line is taken. * + * Locks: none */ -int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt){ - static int current_override = 0; - int count, i; - u_int *ports; - u_int ncr_53c400a_ports[] = {0x280, 0x290, 0x300, 0x310, 0x330, - 0x340, 0x348, 0x350, 0}; - u_int dtc_3181e_ports[] = {0x220, 0x240, 0x280, 0x2a0, 0x2c0, - 0x300, 0x320, 0x340, 0}; - int flags = 0; - struct Scsi_Host *instance; - - if (ncr_irq != NCR_NOT_SET) - overrides[0].irq=ncr_irq; - if (ncr_dma != NCR_NOT_SET) - overrides[0].dma=ncr_dma; - if (ncr_addr != NCR_NOT_SET) - overrides[0].NCR5380_map_name=(NCR5380_map_type)ncr_addr; - if (ncr_5380 != NCR_NOT_SET) - overrides[0].board=BOARD_NCR5380; - else if (ncr_53c400 != NCR_NOT_SET) - overrides[0].board=BOARD_NCR53C400; - else if (ncr_53c400a != NCR_NOT_SET) - overrides[0].board=BOARD_NCR53C400A; - else if (dtc_3181e != NCR_NOT_SET) - overrides[0].board=BOARD_DTC3181E; - - if (!current_override && isapnp_present()) { - struct pci_dev *dev = NULL; - count = 0; - while ((dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('D','T','C'), ISAPNP_FUNCTION(0x436e), dev))) { - if (count >= NO_OVERRIDES) - break; - if (!dev->active && dev->prepare(dev) < 0) { - printk(KERN_ERR "dtc436e probe: prepare failed\n"); - continue; - } - if (!(dev->resource[0].flags & IORESOURCE_IO)) - continue; - if (!dev->active && dev->activate(dev) < 0) { - printk(KERN_ERR "dtc436e probe: activate failed\n"); - continue; - } - if (dev->irq_resource[0].flags & IORESOURCE_IRQ) - overrides[count].irq=dev->irq_resource[0].start; - else - overrides[count].irq=IRQ_NONE; - if (dev->dma_resource[0].flags & IORESOURCE_DMA) - overrides[count].dma=dev->dma_resource[0].start; - else - overrides[count].dma=DMA_NONE; - overrides[count].NCR5380_map_name=(NCR5380_map_type)dev->resource[0].start; - overrides[count].board=BOARD_DTC3181E; - count++; - } - } - - tpnt->proc_name = "g_NCR5380"; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - if (!(overrides[current_override].NCR5380_map_name)) - continue; - - ports = 0; - switch (overrides[current_override].board) { - case BOARD_NCR5380: - flags = FLAG_NO_PSEUDO_DMA; - break; - case BOARD_NCR53C400: - flags = FLAG_NCR53C400; - break; - case BOARD_NCR53C400A: - flags = FLAG_NO_PSEUDO_DMA; - ports = ncr_53c400a_ports; - break; - case BOARD_DTC3181E: - flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E; - ports = dtc_3181e_ports; - break; +int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt) +{ + static int current_override = 0; + int count, i; + unsigned int *ports; + static unsigned int __initdata ncr_53c400a_ports[] = { + 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 + }; + static unsigned int __initdata dtc_3181e_ports[] = { + 0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0 + }; + int flags = 0; + struct Scsi_Host *instance; + + if (ncr_irq != NCR_NOT_SET) + overrides[0].irq = ncr_irq; + if (ncr_dma != NCR_NOT_SET) + overrides[0].dma = ncr_dma; + if (ncr_addr != NCR_NOT_SET) + overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr; + if (ncr_5380 != NCR_NOT_SET) + overrides[0].board = BOARD_NCR5380; + else if (ncr_53c400 != NCR_NOT_SET) + overrides[0].board = BOARD_NCR53C400; + else if (ncr_53c400a != NCR_NOT_SET) + overrides[0].board = BOARD_NCR53C400A; + else if (dtc_3181e != NCR_NOT_SET) + overrides[0].board = BOARD_DTC3181E; + + if (!current_override && isapnp_present()) { + struct pci_dev *dev = NULL; + count = 0; + while ((dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) { + if (count >= NO_OVERRIDES) + break; + if (!dev->active && dev->prepare(dev) < 0) { + printk(KERN_ERR "dtc436e probe: prepare failed\n"); + continue; + } + if (!(dev->resource[0].flags & IORESOURCE_IO)) + continue; + if (!dev->active && dev->activate(dev) < 0) { + printk(KERN_ERR "dtc436e probe: activate failed\n"); + continue; + } + if (dev->irq_resource[0].flags & IORESOURCE_IRQ) + overrides[count].irq = dev->irq_resource[0].start; + else + overrides[count].irq = IRQ_NONE; + if (dev->dma_resource[0].flags & IORESOURCE_DMA) + overrides[count].dma = dev->dma_resource[0].start; + else + overrides[count].dma = DMA_NONE; + overrides[count].NCR5380_map_name = (NCR5380_map_type) dev->resource[0].start; + overrides[count].board = BOARD_DTC3181E; + count++; + } } + tpnt->proc_name = "g_NCR5380"; + + for (count = 0; current_override < NO_OVERRIDES; ++current_override) { + if (!(overrides[current_override].NCR5380_map_name)) + continue; + + ports = 0; + switch (overrides[current_override].board) { + case BOARD_NCR5380: + flags = FLAG_NO_PSEUDO_DMA; + break; + case BOARD_NCR53C400: + flags = FLAG_NCR53C400; + break; + case BOARD_NCR53C400A: + flags = FLAG_NO_PSEUDO_DMA; + ports = ncr_53c400a_ports; + break; + case BOARD_DTC3181E: + flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E; + ports = dtc_3181e_ports; + break; + } + #ifdef CONFIG_SCSI_G_NCR5380_PORT - if (ports) { - /* wakeup sequence for the NCR53C400A and DTC3181E*/ + if (ports) { + /* wakeup sequence for the NCR53C400A and DTC3181E */ - /* Disable the adapter and look for a free io port */ - outb(0x59, 0x779); - outb(0xb9, 0x379); - outb(0xc5, 0x379); - outb(0xae, 0x379); - outb(0xa6, 0x379); - outb(0x00, 0x379); - - if (overrides[current_override].NCR5380_map_name != PORT_AUTO) - for(i=0; ports[i]; i++) { - if (overrides[current_override].NCR5380_map_name == ports[i]) - break; - } - else - for(i=0; ports[i]; i++) { - if ((!check_region(ports[i], 16)) && (inb(ports[i]) == 0xff)) - break; - } - if (ports[i]) { - outb(0x59, 0x779); - outb(0xb9, 0x379); - outb(0xc5, 0x379); - outb(0xae, 0x379); - outb(0xa6, 0x379); - outb(0x80 | i, 0x379); /* set io port to be used */ - outb(0xc0, ports[i] + 9); - if (inb(ports[i] + 9) != 0x80) - continue; - else - overrides[current_override].NCR5380_map_name=ports[i]; - } else - continue; - } + /* Disable the adapter and look for a free io port */ + outb(0x59, 0x779); + outb(0xb9, 0x379); + outb(0xc5, 0x379); + outb(0xae, 0x379); + outb(0xa6, 0x379); + outb(0x00, 0x379); + + if (overrides[current_override].NCR5380_map_name != PORT_AUTO) + for (i = 0; ports[i]; i++) { + if (overrides[current_override].NCR5380_map_name == ports[i]) + break; + } else + for (i = 0; ports[i]; i++) { + if ((!check_region(ports[i], 16)) && (inb(ports[i]) == 0xff)) + break; + } + if (ports[i]) { + outb(0x59, 0x779); + outb(0xb9, 0x379); + outb(0xc5, 0x379); + outb(0xae, 0x379); + outb(0xa6, 0x379); + outb(0x80 | i, 0x379); /* set io port to be used */ + outb(0xc0, ports[i] + 9); + if (inb(ports[i] + 9) != 0x80) + continue; + else + overrides[current_override].NCR5380_map_name = ports[i]; + } else + continue; + } - request_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size, "ncr5380"); + request_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"); #else - if(check_mem_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size)) - continue; - request_mem_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size, "ncr5380"); + if (check_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size)) + continue; + request_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"); #endif - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - { + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) { #ifdef CONFIG_SCSI_G_NCR5380_PORT - release_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size); + release_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size); #else - release_mem_region(overrides[current_override].NCR5380_map_name, - NCR5380_region_size); + release_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size); #endif - continue; - } - - instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name; - - NCR5380_init(instance, flags); - - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, 0xffff); + continue; + } - if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = IRQ_NONE; - } + instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name; - if (instance->irq == IRQ_NONE) { - printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - } + NCR5380_init(instance, flags); - printk("scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int)instance->NCR5380_instance_name); - if (instance->irq == IRQ_NONE) - printk (" interrupts disabled"); - else - printk (" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; -} + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, 0xffff); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, do_generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", NULL)) { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq == IRQ_NONE) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + } -const char * generic_NCR5380_info (struct Scsi_Host* host) { - static const char string[]="Generic NCR5380/53C400 Driver"; - return string; + printk(KERN_INFO "scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int) instance->NCR5380_instance_name); + if (instance->irq == IRQ_NONE) + printk(" interrupts disabled"); + else + printk(" irq %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); + + ++current_override; + ++count; + } + return count; +} + +/** + * generic_NCR5380_info - reporting string + * @host: NCR5380 to report on + * + * Report driver information for the NCR5380 + */ + +const char *generic_NCR5380_info(struct Scsi_Host *host) +{ + static const char string[] = "Generic NCR5380/53C400 Driver"; + return string; } -int generic_NCR5380_release_resources(struct Scsi_Host * instance) +/** + * generic_NCR5380_release_resources - free resources + * @instance: host adapter to clean up + * + * Free the generic interface resources from this adapter. + * + * Locks: none + */ + +int generic_NCR5380_release_resources(struct Scsi_Host *instance) { - NCR5380_local_declare(); - - NCR5380_setup(instance); + NCR5380_local_declare(); + NCR5380_setup(instance); #ifdef CONFIG_SCSI_G_NCR5380_PORT - release_region(instance->NCR5380_instance_name, NCR5380_region_size); + release_region(instance->NCR5380_instance_name, NCR5380_region_size); #else - release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size); -#endif + release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size); +#endif - if (instance->irq != IRQ_NONE) - free_irq(instance->irq, NULL); + if (instance->irq != IRQ_NONE) + free_irq(instance->irq, NULL); return 0; } #ifdef BIOSPARAM -/* - * Function : int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip) +/** + * generic_NCR5380_biosparam + * @disk: disk to compute geometry for + * @dev: device identifier for this disk + * @ip: sizes to fill in * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for - * the specified device / size. + * Generates a BIOS / DOS compatible H-C-S mapping for the specified + * device / size. * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} + * XXX Most SCSI boards use this mapping, I could be incorrect. Someone + * using hard disks on a trantor should verify that this mapping + * corresponds to that used by the BIOS / ASPI driver by running the linux + * fdisk program and matching the H_C_S coordinates to what DOS uses. * - * Returns : always 0 (success), initializes ip - * - */ - -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. + * Locks: none */ int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip) { - int size = disk->capacity; - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - return 0; + int size = disk->capacity; + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + return 0; } #endif #if NCR53C400_PSEUDO_DMA -static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, int len) -{ - int blocks = len / 128; - int start = 0; - int bl; -#ifdef CONFIG_SCSI_G_NCR5380_PORT - int i; -#endif - NCR5380_local_declare(); - - NCR5380_setup(instance); - -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: About to read %d blocks for %d bytes\n", blocks, len); -#endif - - NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR); - NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); - while (1) { - -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: %d blocks left\n", blocks); -#endif - - if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { -#if (NDEBUG & NDEBUG_C400_PREAD) - if (blocks) - printk("53C400r: blocks still == %d\n", blocks); - else - printk("53C400r: Exiting loop\n"); -#endif - break; - } - -#if 1 - if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { - printk("53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); - return -1; - } -#endif - -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: Waiting for buffer, bl=%d\n", bl); -#endif - - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: Transferring 128 bytes\n"); -#endif +/** + * NCR5380_pread - pseudo DMA read + * @instance: adapter to read from + * @dst: buffer to read into + * @len: buffer length + * + * Perform a psuedo DMA mode read from an NCR53C400 or equivalent + * controller + */ + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) +{ + int blocks = len / 128; + int start = 0; + int bl; + + NCR5380_local_declare(); + NCR5380_setup(instance); + + NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR); + NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); + while (1) { + if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { + break; + } + if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { + printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); + return -1; + } + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY); #ifdef CONFIG_SCSI_G_NCR5380_PORT - for (i=0; i<128; i++) - dst[start+i] = NCR5380_read(C400_HOST_BUFFER); + { + int i; + for (i = 0; i < 128; i++) + dst[start + i] = NCR5380_read(C400_HOST_BUFFER); + } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ - isa_memcpy_fromio(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128); + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128); #endif - start+=128; - blocks--; - } - - if (blocks) { -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: EXTRA: Waiting for buffer\n"); -#endif - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; + start += 128; + blocks--; + } + + if (blocks) { + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + { + // FIXME - no timeout + } -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: Transferring EXTRA 128 bytes\n"); -#endif #ifdef CONFIG_SCSI_G_NCR5380_PORT - for (i=0; i<128; i++) - dst[start+i] = NCR5380_read(C400_HOST_BUFFER); + { + int i; + for (i = 0; i < 128; i++) + dst[start + i] = NCR5380_read(C400_HOST_BUFFER); + } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ - isa_memcpy_fromio(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128); -#endif - start+=128; - blocks--; - } -#if (NDEBUG & NDEBUG_C400_PREAD) - else - printk("53C400r: No EXTRA required\n"); -#endif - -#if (NDEBUG & NDEBUG_C400_PREAD) - printk("53C400r: Final values: blocks=%d start=%d\n", blocks, start); -#endif - - if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) - printk("53C400r: no 53C80 gated irq after transfer"); -#if (NDEBUG & NDEBUG_C400_PREAD) - else - printk("53C400r: Got 53C80 interrupt and tried to clear it\n"); + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128); #endif + start += 128; + blocks--; + } -/* DON'T DO THIS - THEY NEVER ARRIVE! - printk("53C400r: Waiting for 53C80 registers\n"); - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG) - ; -*/ + if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) + printk("53C400r: no 53C80 gated irq after transfer"); - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) - printk("53C400r: no end dma signal\n"); -#if (NDEBUG & NDEBUG_C400_PREAD) - else - printk("53C400r: end dma as expected\n"); +#if 0 + /* + * DON'T DO THIS - THEY NEVER ARRIVE! + */ + printk("53C400r: Waiting for 53C80 registers\n"); + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG) + ; #endif - - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - return 0; -} + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) + printk(KERN_ERR "53C400r: no end dma signal\n"); -static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src, int len) -{ - int blocks = len / 128; - int start = 0; - int i; - int bl; - NCR5380_local_declare(); - - NCR5380_setup(instance); - -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: About to write %d blocks for %d bytes\n", blocks, len); -#endif - - NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); - NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); - while (1) { - if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { - printk("53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); - return -1; - } - - if ((bl=NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - if (blocks) - printk("53C400w: exiting loop, blocks still == %d\n", blocks); - else - printk("53C400w: exiting loop\n"); -#endif - break; - } + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + return 0; +} -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: %d blocks left\n", blocks); +/** + * NCR5380_write - pseudo DMA write + * @instance: adapter to read from + * @dst: buffer to read into + * @len: buffer length + * + * Perform a psuedo DMA mode read from an NCR53C400 or equivalent + * controller + */ - printk("53C400w: waiting for buffer, bl=%d\n", bl); -#endif - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) +{ + int blocks = len / 128; + int start = 0; + int bl; + int i; + + NCR5380_local_declare(); + NCR5380_setup(instance); + + NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); + NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); + while (1) { + if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { + printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); + return -1; + } -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: transferring 128 bytes\n"); -#endif + if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { + break; + } + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + ; // FIXME - timeout #ifdef CONFIG_SCSI_G_NCR5380_PORT - for (i=0; i<128; i++) - NCR5380_write(C400_HOST_BUFFER, src[start+i]); + { + for (i = 0; i < 128; i++) + NCR5380_write(C400_HOST_BUFFER, src[start + i]); + } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ - isa_memcpy_toio(NCR53C400_host_buffer+NCR5380_map_name,src+start,128); + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128); #endif - start+=128; - blocks--; - } - if (blocks) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: EXTRA waiting for buffer\n"); -#endif - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; + start += 128; + blocks--; + } + if (blocks) { + while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) + ; // FIXME - no timeout -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: transferring EXTRA 128 bytes\n"); -#endif #ifdef CONFIG_SCSI_G_NCR5380_PORT - for (i=0; i<128; i++) - NCR5380_write(C400_HOST_BUFFER, src[start+i]); + { + for (i = 0; i < 128; i++) + NCR5380_write(C400_HOST_BUFFER, src[start + i]); + } #else - /* implies CONFIG_SCSI_G_NCR5380_MEM */ - isa_memcpy_toio(NCR53C400_host_buffer+NCR5380_map_name,src+start,128); -#endif - start+=128; - blocks--; - } -#if (NDEBUG & NDEBUG_C400_PWRITE) - else - printk("53C400w: No EXTRA required\n"); -#endif - -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: Final values: blocks=%d start=%d\n", blocks, start); + /* implies CONFIG_SCSI_G_NCR5380_MEM */ + isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128); #endif + start += 128; + blocks--; + } #if 0 - printk("53C400w: waiting for registers to be available\n"); - THEY NEVER DO! - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG) - ; - printk("53C400w: Got em\n"); -#endif - - /* Let's wait for this instead - could be ugly */ - /* All documentation says to check for this. Maybe my hardware is too - * fast. Waiting for it seems to work fine! KLL - */ - while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) - ; - - /* - * I know. i is certainly != 0 here but the loop is new. See previous - * comment. - */ - if (i) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: got 53C80 gated irq (last block)\n"); -#endif - if (!((i=NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER)) - printk("53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n",i); -#if (NDEBUG & NDEBUG_C400_PWRITE) - else - printk("53C400w: Got END OF DMA\n"); -#endif - } - else - printk("53C400w: no 53C80 gated irq after transfer (last block)\n"); + printk("53C400w: waiting for registers to be available\n"); + THEY NEVER DO ! while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG); + printk("53C400w: Got em\n"); +#endif + + /* Let's wait for this instead - could be ugly */ + /* All documentation says to check for this. Maybe my hardware is too + * fast. Waiting for it seems to work fine! KLL + */ + while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) + ; // FIXME - no timeout + + /* + * I know. i is certainly != 0 here but the loop is new. See previous + * comment. + */ + if (i) { + if (!((i = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER)) + printk(KERN_ERR "53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n", i); + } else + printk(KERN_ERR "53C400w: no 53C80 gated irq after transfer (last block)\n"); #if 0 - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) { - printk("53C400w: no end dma signal\n"); - } -#endif - -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: waiting for last byte...\n"); -#endif - while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) - ; - -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: got last byte.\n"); - printk("53C400w: pwrite exiting with status 0, whoopee!\n"); + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) { + printk(KERN_ERR "53C400w: no end dma signal\n"); + } #endif - return 0; + while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) + ; // TIMEOUT + return 0; } -#endif /* PSEUDO_DMA */ +#endif /* PSEUDO_DMA */ +/* + * Include the NCR5380 core code that we build our driver around + */ + #include "NCR5380.c" #define PRINTP(x) len += sprintf(buffer+len, x) #define ANDP , -static int sprint_opcode(char* buffer, int len, int opcode) { - int start = len; - PRINTP("0x%02x " ANDP opcode); - return len-start; -} - -static int sprint_command (char* buffer, int len, unsigned char *command) { - int i,s,start=len; - len += sprint_opcode(buffer, len, command[0]); - for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) - PRINTP("%02x " ANDP command[i]); - PRINTP("\n"); - return len-start; -} - -static int sprint_Scsi_Cmnd (char* buffer, int len, Scsi_Cmnd *cmd) { - int start = len; - PRINTP("host number %d destination target %d, lun %d\n" ANDP - cmd->host->host_no ANDP - cmd->target ANDP - cmd->lun); - PRINTP(" command = "); - len += sprint_command (buffer, len, cmd->cmnd); - return len-start; -} - -int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout) -{ - int len = 0; - NCR5380_local_declare(); - unsigned long flags; - unsigned char status; - int i; - struct Scsi_Host *scsi_ptr; - Scsi_Cmnd *ptr; - struct NCR5380_hostdata *hostdata; +static int sprint_opcode(char *buffer, int len, int opcode) +{ + int start = len; + PRINTP("0x%02x " ANDP opcode); + return len - start; +} + +static int sprint_command(char *buffer, int len, unsigned char *command) +{ + int i, s, start = len; + len += sprint_opcode(buffer, len, command[0]); + for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) + PRINTP("%02x " ANDP command[i]); + PRINTP("\n"); + return len - start; +} + +/** + * sprintf_Scsi_Cmnd - print a scsi command + * @buffer: buffr to print into + * @len: buffer length + * @cmd: SCSI command block + * + * Print out the target and command data in hex + */ + +static int sprint_Scsi_Cmnd(char *buffer, int len, Scsi_Cmnd * cmd) +{ + int start = len; + PRINTP("host number %d destination target %d, lun %d\n" ANDP cmd->host->host_no ANDP cmd->target ANDP cmd->lun); + PRINTP(" command = "); + len += sprint_command(buffer, len, cmd->cmnd); + return len - start; +} + +/** + * generic_NCR5380_proc_info - /proc for NCR5380 driver + * @buffer: buffer to print into + * @start: start position + * @offset: offset into buffer + * @len: length + * @hostno: instance to affect + * @inout: read/write + * + * Provide the procfs information for the 5380 controller. We fill + * this with useful debugging information including the commands + * being executed, disconnected command queue and the statistical + * data + * + * Locks: global cli/lock for queue walk + */ + +int generic_NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) +{ + int len = 0; + NCR5380_local_declare(); + unsigned long flags; + unsigned char status; + int i; + struct Scsi_Host *scsi_ptr; + Scsi_Cmnd *ptr; + struct NCR5380_hostdata *hostdata; #ifdef NCR5380_STATS - Scsi_Device *dev; - extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; + Scsi_Device *dev; + extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; #endif - save_flags(flags); - cli(); + save_flags(flags); + cli(); - for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr=scsi_ptr->next) - if (scsi_ptr->host_no == hostno) - break; - NCR5380_setup(scsi_ptr); - hostdata = (struct NCR5380_hostdata *)scsi_ptr->hostdata; - - PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name); - PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE); - PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE); + for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr = scsi_ptr->next) + if (scsi_ptr->host_no == hostno) + break; + NCR5380_setup(scsi_ptr); + hostdata = (struct NCR5380_hostdata *) scsi_ptr->hostdata; + + PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name); + PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE); + PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE); #ifdef NCR53C400 - PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE); - PRINTP("NCR53C400 card%s detected\n" ANDP (((struct NCR5380_hostdata *)scsi_ptr->hostdata)->flags & FLAG_NCR53C400)?"":" not"); + PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE); + PRINTP("NCR53C400 card%s detected\n" ANDP(((struct NCR5380_hostdata *) scsi_ptr->hostdata)->flags & FLAG_NCR53C400) ? "" : " not"); # if NCR53C400_PSEUDO_DMA - PRINTP("NCR53C400 pseudo DMA used\n"); + PRINTP("NCR53C400 pseudo DMA used\n"); # endif #else - PRINTP("NO NCR53C400 driver extensions\n"); + PRINTP("NO NCR53C400 driver extensions\n"); #endif - PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name); - if (scsi_ptr->irq == IRQ_NONE) - PRINTP("no interrupt\n"); - else - PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq); + PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name); + if (scsi_ptr->irq == IRQ_NONE) + PRINTP("no interrupt\n"); + else + PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq); #ifdef NCR5380_STATS - if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue) - PRINTP("There are commands pending, transfer rates may be crud\n"); - if (hostdata->pendingr) - PRINTP(" %d pending reads" ANDP hostdata->pendingr); - if (hostdata->pendingw) - PRINTP(" %d pending writes" ANDP hostdata->pendingw); - if (hostdata->pendingr || hostdata->pendingw) - PRINTP("\n"); - for (dev = scsi_ptr->host_queue; dev; dev=dev->next) { - unsigned long br = hostdata->bytes_read[dev->id]; - unsigned long bw = hostdata->bytes_write[dev->id]; - long tr = hostdata->time_read[dev->id] / HZ; - long tw = hostdata->time_write[dev->id] / HZ; - - PRINTP(" T:%d %s " ANDP dev->id ANDP (dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int)dev->type] : "Unknown"); - for (i=0; i<8; i++) - if (dev->vendor[i] >= 0x20) - *(buffer+(len++)) = dev->vendor[i]; - *(buffer+(len++)) = ' '; - for (i=0; i<16; i++) - if (dev->model[i] >= 0x20) - *(buffer+(len++)) = dev->model[i]; - *(buffer+(len++)) = ' '; - for (i=0; i<4; i++) - if (dev->rev[i] >= 0x20) - *(buffer+(len++)) = dev->rev[i]; - *(buffer+(len++)) = ' '; - - PRINTP("\n%10ld kb read in %5ld secs" ANDP br/1024 ANDP tr); - if (tr) - PRINTP(" @ %5ld bps" ANDP br / tr); - - PRINTP("\n%10ld kb written in %5ld secs" ANDP bw/1024 ANDP tw); - if (tw) - PRINTP(" @ %5ld bps" ANDP bw / tw); - PRINTP("\n"); - } -#endif - - status = NCR5380_read(STATUS_REG); - if (!(status & SR_REQ)) - PRINTP("REQ not asserted, phase unknown.\n"); - else { - for (i = 0; (phases[i].value != PHASE_UNKNOWN) && - (phases[i].value != (status & PHASE_MASK)); ++i) - ; - PRINTP("Phase %s\n" ANDP phases[i].name); - } - - if (!hostdata->connected) { - PRINTP("No currently connected command\n"); - } else { - len += sprint_Scsi_Cmnd (buffer, len, (Scsi_Cmnd *) hostdata->connected); - } - - PRINTP("issue_queue\n"); - - for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) - len += sprint_Scsi_Cmnd (buffer, len, ptr); - - PRINTP("disconnected_queue\n"); - - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) - len += sprint_Scsi_Cmnd (buffer, len, ptr); - - *start = buffer + offset; - len -= offset; - if (len > length) - len = length; - restore_flags(flags); - return len; + if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue) + PRINTP("There are commands pending, transfer rates may be crud\n"); + if (hostdata->pendingr) + PRINTP(" %d pending reads" ANDP hostdata->pendingr); + if (hostdata->pendingw) + PRINTP(" %d pending writes" ANDP hostdata->pendingw); + if (hostdata->pendingr || hostdata->pendingw) + PRINTP("\n"); + for (dev = scsi_ptr->host_queue; dev; dev = dev->next) { + unsigned long br = hostdata->bytes_read[dev->id]; + unsigned long bw = hostdata->bytes_write[dev->id]; + long tr = hostdata->time_read[dev->id] / HZ; + long tw = hostdata->time_write[dev->id] / HZ; + + PRINTP(" T:%d %s " ANDP dev->id ANDP(dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int) dev->type] : "Unknown"); + for (i = 0; i < 8; i++) + if (dev->vendor[i] >= 0x20) + *(buffer + (len++)) = dev->vendor[i]; + *(buffer + (len++)) = ' '; + for (i = 0; i < 16; i++) + if (dev->model[i] >= 0x20) + *(buffer + (len++)) = dev->model[i]; + *(buffer + (len++)) = ' '; + for (i = 0; i < 4; i++) + if (dev->rev[i] >= 0x20) + *(buffer + (len++)) = dev->rev[i]; + *(buffer + (len++)) = ' '; + + PRINTP("\n%10ld kb read in %5ld secs" ANDP br / 1024 ANDP tr); + if (tr) + PRINTP(" @ %5ld bps" ANDP br / tr); + + PRINTP("\n%10ld kb written in %5ld secs" ANDP bw / 1024 ANDP tw); + if (tw) + PRINTP(" @ %5ld bps" ANDP bw / tw); + PRINTP("\n"); + } +#endif + + status = NCR5380_read(STATUS_REG); + if (!(status & SR_REQ)) + PRINTP("REQ not asserted, phase unknown.\n"); + else { + for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); + PRINTP("Phase %s\n" ANDP phases[i].name); + } + + if (!hostdata->connected) { + PRINTP("No currently connected command\n"); + } else { + len += sprint_Scsi_Cmnd(buffer, len, (Scsi_Cmnd *) hostdata->connected); + } + + PRINTP("issue_queue\n"); + + for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + len += sprint_Scsi_Cmnd(buffer, len, ptr); + + PRINTP("disconnected_queue\n"); + + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + len += sprint_Scsi_Cmnd(buffer, len, ptr); + + *start = buffer + offset; + len -= offset; + if (len > length) + len = length; + restore_flags(flags); + return len; } #undef PRINTP #undef ANDP -/* Eventually this will go into an include file, but this will be later */ +/* + * Eventually this will go into an include file, but this will be later + */ static Scsi_Host_Template driver_template = GENERIC_NCR5380; #include #include "scsi_module.c" -#ifdef MODULE - MODULE_PARM(ncr_irq, "i"); MODULE_PARM(ncr_dma, "i"); MODULE_PARM(ncr_addr, "i"); @@ -913,65 +898,20 @@ MODULE_PARM(ncr_53c400a, "i"); MODULE_PARM(dtc_3181e, "i"); MODULE_LICENSE("GPL"); -#else - -static int __init do_NCR5380_setup(char *str) -{ - int ints[10]; - - get_options(str, sizeof(ints)/sizeof(int), ints); - generic_NCR5380_setup(str,ints); - - return 1; -} - -static int __init do_NCR53C400_setup(char *str) -{ - int ints[10]; - - get_options(str, sizeof(ints)/sizeof(int), ints); - generic_NCR53C400_setup(str,ints); - return 1; -} - -static int __init do_NCR53C400A_setup(char *str) -{ - int ints[10]; - - get_options(str, sizeof(ints)/sizeof(int), ints); - generic_NCR53C400A_setup(str,ints); - - return 1; -} - -static int __init do_DTC3181E_setup(char *str) -{ - int ints[10]; - - get_options(str, sizeof(ints)/sizeof(int), ints); - generic_DTC3181E_setup(str,ints); - - return 1; -} - -__setup("ncr5380=", do_NCR5380_setup); -__setup("ncr53c400=", do_NCR53C400_setup); -__setup("ncr53c400a=", do_NCR53C400A_setup); -__setup("dtc3181e=", do_DTC3181E_setup); static struct isapnp_device_id id_table[] __devinitdata = { { - ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('D','T','C'), ISAPNP_FUNCTION(0x436e), - 0 - }, + ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), + 0}, {0} }; MODULE_DEVICE_TABLE(isapnp, id_table); -MODULE_LICENSE("GPL"); -#endif - +__setup("ncr5380=", do_NCR5380_setup); +__setup("ncr53c400=", do_NCR53C400_setup); +__setup("ncr53c400a=", do_NCR53C400A_setup); +__setup("dtc3181e=", do_DTC3181E_setup); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/g_NCR5380.h linux-2.5/drivers/scsi/g_NCR5380.h --- linux-2.5.5/drivers/scsi/g_NCR5380.h Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/scsi/g_NCR5380.h Sun Feb 10 19:55:31 2002 @@ -43,24 +43,18 @@ #define NCR5380_BIOSPARAM NULL #endif -#ifndef ASM int generic_NCR5380_abort(Scsi_Cmnd *); int generic_NCR5380_detect(Scsi_Host_Template *); int generic_NCR5380_release_resources(struct Scsi_Host *); -int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int generic_NCR5380_reset(Scsi_Cmnd *, unsigned int); -int notyet_generic_proc_info (char *buffer ,char **start, off_t offset, - int length, int hostno, int inout); -const char* generic_NCR5380_info(struct Scsi_Host *); +int notyet_generic_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); +const char *generic_NCR5380_info(struct Scsi_Host *); #ifdef BIOSPARAM int generic_NCR5380_biosparam(Disk *, kdev_t, int *); #endif -int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout); - -#ifndef NULL -#define NULL 0 -#endif +int generic_NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); #ifndef CMD_PER_LUN #define CMD_PER_LUN 2 @@ -92,19 +86,15 @@ #define STRVAL(x) __STRVAL(x) #ifdef CONFIG_SCSI_G_NCR5380_PORT - #define NCR5380_map_config port - #define NCR5380_map_type int - #define NCR5380_map_name port - #define NCR5380_instance_name io_port - #define NCR53C400_register_offset 0 - #define NCR53C400_address_adjust 8 - +/* + * FIXME: size should be runtime decided + */ #ifdef NCR53C400 #define NCR5380_region_size 16 #else @@ -114,30 +104,21 @@ #define NCR5380_read(reg) (inb(NCR5380_map_name + (reg))) #define NCR5380_write(reg, value) (outb((value), (NCR5380_map_name + (reg)))) -#else +#else /* therefore CONFIG_SCSI_G_NCR5380_MEM */ #define NCR5380_map_config memory - #define NCR5380_map_type unsigned long - #define NCR5380_map_name base - #define NCR5380_instance_name base - #define NCR53C400_register_offset 0x108 - #define NCR53C400_address_adjust 0 - #define NCR53C400_mem_base 0x3880 - #define NCR53C400_host_buffer 0x3900 - #define NCR5380_region_size 0x3a00 - #define NCR5380_read(reg) isa_readb(NCR5380_map_name + NCR53C400_mem_base + (reg)) -#define NCR5380_write(reg, value) isa_writeb(NCR5380_map_name + NCR53C400_mem_base + (reg), value) +#define NCR5380_write(reg, value) isa_writeb(value, NCR5380_map_name + NCR53C400_mem_base + (reg)) #endif @@ -164,7 +145,5 @@ #define BOARD_NCR53C400A 2 #define BOARD_DTC3181E 3 -#endif /* else def HOSTS_C */ -#endif /* ndef ASM */ -#endif /* GENERIC_NCR5380_H */ - +#endif /* else def HOSTS_C */ +#endif /* GENERIC_NCR5380_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/i60uscsi.c linux-2.5/drivers/scsi/i60uscsi.c --- linux-2.5.5/drivers/scsi/i60uscsi.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/scsi/i60uscsi.c Mon Jan 14 22:39:45 2002 @@ -640,7 +640,6 @@ ULONG idx; UCHAR index; UCHAR i; - ULONG flags; Ch = hcsp->HCS_Index; for (i = 0; i < 8; i++) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/ibmmca.c linux-2.5/drivers/scsi/ibmmca.c --- linux-2.5.5/drivers/scsi/ibmmca.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/scsi/ibmmca.c Fri Feb 8 02:15:53 2002 @@ -1406,9 +1406,9 @@ io_base = 0; id_base = 0; if (str) { - token = strtok(str,","); j = 0; - while (token) { + while ((token = strsep(&str,",")) != NULL) { + if (!*token) continue; if (!strcmp(token,"activity")) display_mode |= LED_ACTIVITY; if (!strcmp(token,"display")) display_mode |= LED_DISP; if (!strcmp(token,"adisplay")) display_mode |= LED_ADISP; @@ -1424,7 +1424,6 @@ scsi_id[id_base++] = simple_strtoul(token,NULL,0); j++; } - token = strtok(NULL,","); } } else if (ints) { for (i = 0; i < IM_MAX_HOSTS && 2*i+2 < ints[0]; i++) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/ide-scsi.c linux-2.5/drivers/scsi/ide-scsi.c --- linux-2.5.5/drivers/scsi/ide-scsi.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/scsi/ide-scsi.c Sun Mar 3 20:03:53 2002 @@ -182,7 +182,7 @@ if (!test_bit(PC_TRANSFORM, &pc->flags)) return; - if (drive->media == ide_cdrom || drive->media == ide_optical) { + if (drive->type == ATA_ROM || drive->type == ATA_MOD) { if (c[0] == READ_6 || c[0] == WRITE_6) { c[8] = c[4]; c[5] = c[3]; c[4] = c[2]; c[3] = c[1] & 0x1f; c[2] = 0; c[1] &= 0xe0; @@ -221,7 +221,7 @@ if (!test_bit(PC_TRANSFORM, &pc->flags)) return; - if (drive->media == ide_cdrom || drive->media == ide_optical) { + if (drive->type == ATA_ROM || drive->type == ATA_MOD) { if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) { scsi_buf[0] = atapi_buf[1]; /* Mode data length */ scsi_buf[1] = atapi_buf[2]; /* Medium type */ @@ -508,7 +508,8 @@ */ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id) { - DRIVER(drive)->busy++; + ata_ops(drive)->busy++; + idescsi_drives[id] = drive; drive->driver_data = scsi; drive->ready_stat = 0; @@ -535,18 +536,13 @@ return 0; } -int idescsi_init(void); -int idescsi_reinit(ide_drive_t *drive); +static int idescsi_reinit(ide_drive_t *drive); /* * IDE subdriver functions, registered with ide.c */ -static ide_driver_t idescsi_driver = { - name: "ide-scsi", - media: ide_scsi, - busy: 0, - supports_dma: 1, - supports_dsc_overlap: 0, +static struct ata_operations idescsi_driver = { + owner: THIS_MODULE, cleanup: idescsi_cleanup, standby: NULL, flushcache: NULL, @@ -561,54 +557,23 @@ capacity: NULL, special: NULL, proc: NULL, - driver_init: idescsi_init, driver_reinit: idescsi_reinit, }; -int idescsi_reinit (ide_drive_t *drive) +static int idescsi_reinit (ide_drive_t *drive) { -#if 0 - idescsi_scsi_t *scsi; - byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255}; - int i, failed, id; - - if (!idescsi_initialized) - return 0; - for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++) - idescsi_drives[i] = NULL; - - MOD_INC_USE_COUNT; - for (i = 0; media[i] != 255; i++) { - failed = 0; - while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) { - - if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) { - printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name); - continue; - } - if (ide_register_subdriver (drive, &idescsi_driver)) { - printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name); - kfree (scsi); - continue; - } - for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++); - idescsi_setup (drive, scsi, id); - failed--; - } - } - ide_register_module(&idescsi_module); - MOD_DEC_USE_COUNT; -#endif return 0; } /* * idescsi_init will register the driver for each scsi. */ -int idescsi_init (void) +int idescsi_init(void) { ide_drive_t *drive; idescsi_scsi_t *scsi; + /* FIXME: The following is just plain wrong, since those are definitely *not* the + * media types supported by the ATA layer */ byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255}; int i, failed, id; @@ -620,7 +585,7 @@ MOD_INC_USE_COUNT; for (i = 0; media[i] != 255; i++) { failed = 0; - while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) { + while ((drive = ide_scan_devices (media[i], "ide-scsi", NULL, failed++)) != NULL) { if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) { printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name); @@ -636,7 +601,7 @@ failed--; } } - ide_register_module(&idescsi_driver); + revalidate_drives(); MOD_DEC_USE_COUNT; return 0; } @@ -668,7 +633,7 @@ for (id = 0; id < MAX_HWIFS * MAX_DRIVES; id++) { drive = idescsi_drives[id]; if (drive) - DRIVER(drive)->busy--; + ata_ops(drive)->busy--; } return 0; } @@ -898,15 +863,22 @@ int i, failed; scsi_unregister_host(&idescsi_template); + + /* FIXME: The media types scanned here have literally nothing to do + * with the media types used by the overall ATA code! + * + * This is basically showing us, that there is something wrong with the + * ide_scan_devices function. + */ + for (i = 0; media[i] != 255; i++) { failed = 0; - while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL) + while ((drive = ide_scan_devices (media[i], "ide-scsi", &idescsi_driver, failed)) != NULL) if (idescsi_cleanup (drive)) { printk ("%s: exit_idescsi_module() called while still busy\n", drive->name); failed++; } } - ide_unregister_module(&idescsi_driver); } module_init(init_idescsi_module); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/imm.c linux-2.5/drivers/scsi/imm.c --- linux-2.5.5/drivers/scsi/imm.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/scsi/imm.c Wed Jan 23 01:45:56 2002 @@ -998,7 +998,7 @@ case 4: if (cmd->use_sg) { /* if many buffers are available, start filling the first */ - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; + cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset; } else { @@ -1007,7 +1007,7 @@ cmd->SCp.this_residual = cmd->request_bufflen; cmd->SCp.ptr = cmd->request_buffer; } - cmd->SCp.buffers_residual = cmd->use_sg; + cmd->SCp.buffers_residual = cmd->use_sg - 1; cmd->SCp.phase++; if (cmd->SCp.this_residual & 0x01) cmd->SCp.this_residual++; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/ips.c linux-2.5/drivers/scsi/ips.c --- linux-2.5.5/drivers/scsi/ips.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/scsi/ips.c Fri Feb 8 15:46:34 2002 @@ -81,7 +81,7 @@ /* 2.3.18 and later */ /* - Sync with other changes from the 2.3 kernels */ /* 4.00.06 - Fix timeout with initial FFDC command */ -/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig */ +/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig */ /* 4.10.00 - Add support for ServeRAID 4M/4L */ /* 4.10.13 - Fix for dynamic unload and proc file system */ /* 4.20.03 - Rename version to coincide with new release schedules */ @@ -193,6 +193,7 @@ #ifdef MODULE static char *ips = NULL; MODULE_PARM(ips, "s"); + MODULE_LICENSE("GPL"); #endif /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/megaraid.c linux-2.5/drivers/scsi/megaraid.c --- linux-2.5.5/drivers/scsi/megaraid.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/scsi/megaraid.c Mon Feb 4 22:15:17 2002 @@ -586,10 +586,10 @@ #define DRIVER_LOCK(p) #define DRIVER_UNLOCK(p) #define IO_LOCK_T unsigned long io_flags = 0 -#define IO_LOCK(host) spin_lock_irqsave(host->host_lock,io_flags) -#define IO_UNLOCK(host) spin_unlock_irqrestore(host->host_lock,io_flags) -#define IO_LOCK_IRQ(host) spin_lock_irq(host->host_lock) -#define IO_UNLOCK_IRQ(host) spin_unlock_irq(host->host_lock) +#define IO_LOCK(host) spin_lock_irqsave((host)->host_lock,io_flags) +#define IO_UNLOCK(host) spin_unlock_irqrestore((host)->host_lock,io_flags) +#define IO_LOCK_IRQ(host) spin_lock_irq((host)->host_lock) +#define IO_UNLOCK_IRQ(host) spin_unlock_irq((host)->host_lock) #define queue_task_irq(a,b) queue_task(a,b) #define queue_task_irq_off(a,b) queue_task(a,b) @@ -614,8 +614,8 @@ #define DRIVER_LOCK(p) #define DRIVER_UNLOCK(p) #define IO_LOCK_T unsigned long io_flags = 0 -#define IO_LOCK(host) spin_lock_irqsave(host->host_lock,io_flags); -#define IO_UNLOCK(host) spin_unlock_irqrestore(host->host_lock,io_flags); +#define IO_LOCK(host) spin_lock_irqsave(&io_request_lock,io_flags); +#define IO_UNLOCK(host) spin_unlock_irqrestore(&io_request_lock,io_flags); #define pci_free_consistent(a,b,c,d) #define pci_unmap_single(a,b,c,d) @@ -1151,12 +1151,12 @@ if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU) { memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14); } else if (mbox->cmd == MEGA_MBOXCMD_EXTPASSTHRU) { - SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION < 1); + SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1); memcpy( SCpnt->sense_buffer, epthru->reqsensearea, 14 ); - SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION < 1); + SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1); /*SCpnt->result = (DRIVER_SENSE << 24) | (DID_ERROR << 16) | status;*/ @@ -4533,7 +4533,6 @@ unsigned int cmd, unsigned long arg) { int adapno; - kdev_t dev; u32 inlen; struct uioctl_t ioc; char *kvaddr = NULL; @@ -4557,7 +4556,7 @@ #endif IO_LOCK_T; - if (!inode || !(dev = inode->i_rdev)) + if (!inode || kdev_none(inode->i_rdev)) return -EINVAL; if (_IOC_TYPE (cmd) != MEGAIOC_MAGIC) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/mesh.c linux-2.5/drivers/scsi/mesh.c --- linux-2.5.5/drivers/scsi/mesh.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/scsi/mesh.c Wed Jan 30 21:57:15 2002 @@ -28,7 +28,8 @@ #include #include #include -#include +#include +#include #ifdef CONFIG_PMAC_PBOOK #include #include @@ -155,7 +156,6 @@ struct mesh_target tgts[8]; void *dma_cmd_space; struct device_node *ofnode; - u8* mio_base; #ifndef MESH_NEW_STYLE_EH Scsi_Cmnd *completed_q; Scsi_Cmnd *completed_qtail; @@ -258,8 +258,6 @@ if (mesh == 0) mesh = find_compatible_devices("scsi", "chrp,mesh0"); for (; mesh != 0; mesh = mesh->next) { - struct device_node *mio; - if (mesh->n_addrs != 2 || mesh->n_intrs != 2) { printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs" " (got %d,%d)", mesh->n_addrs, mesh->n_intrs); @@ -325,12 +323,6 @@ if (mesh_sync_period < minper) mesh_sync_period = minper; - ms->mio_base = 0; - for (mio = ms->ofnode->parent; mio; mio = mio->parent) - if (strcmp(mio->name, "mac-io") == 0 && mio->n_addrs > 0) - break; - if (mio) - ms->mio_base = (u8 *) ioremap(mio->addrs[0].address, 0x40); set_mesh_power(ms, 1); mesh_init(ms); @@ -363,11 +355,9 @@ iounmap((void *) ms->mesh); if (ms->dma) iounmap((void *) ms->dma); - if (ms->mio_base) - iounmap((void *) ms->mio_base); kfree(ms->dma_cmd_space); free_irq(ms->meshintr, ms); - feature_clear(ms->ofnode, FEATURE_MESH_enable); + pmac_call_feature(PMAC_FTR_MESH_ENABLE, ms->ofnode, 0, 0); return 0; } @@ -377,16 +367,10 @@ if (_machine != _MACH_Pmac) return; if (state) { - feature_set(ms->ofnode, FEATURE_MESH_enable); - /* This seems to enable the termination power. strangely - this doesn't fully agree with OF, but with MacOS */ - if (ms->mio_base) - out_8(ms->mio_base + 0x36, 0x70); + pmac_call_feature(PMAC_FTR_MESH_ENABLE, ms->ofnode, 0, 1); mdelay(200); } else { - feature_clear(ms->ofnode, FEATURE_MESH_enable); - if (ms->mio_base) - out_8(ms->mio_base + 0x36, 0x34); + pmac_call_feature(PMAC_FTR_MESH_ENABLE, ms->ofnode, 0, 0); mdelay(10); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/osst.c linux-2.5/drivers/scsi/osst.c --- linux-2.5.5/drivers/scsi/osst.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/scsi/osst.c Fri Feb 8 02:15:53 2002 @@ -16,15 +16,15 @@ Copyright 1992 - 2000 Kai Makisara email Kai.Makisara@metla.fi - $Header: /home/cvsroot/Driver/osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $ + $Header: /home/cvsroot/Driver/osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $ Microscopic alterations - Rik Ling, 2000/12/21 Last modified: Wed Feb 2 22:04:05 2000 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 */ -static const char * cvsid = "$Id: osst.c,v 1.61 2001/06/03 21:55:12 riede Exp $"; -const char * osst_version = "0.9.8"; +static const char * cvsid = "$Id: osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $"; +const char * osst_version = "0.9.10"; /* The "failure to reconnect" firmware bug */ #define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/ @@ -226,20 +226,20 @@ SRpnt->sr_cmnd[0] != MODE_SENSE && SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ if (driver_byte(result) & DRIVER_SENSE) { - printk(KERN_WARNING "osst%d:W: Error with sense data: ", dev); - print_req_sense("osst", SRpnt); + printk(KERN_WARNING "osst%d:W: Command with sense data: ", dev); + print_req_sense("osst:", SRpnt); } else { static int notyetprinted = 1; printk(KERN_WARNING - "osst%d:W: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", + "osst%d:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK, host_byte(result)); if (notyetprinted) { notyetprinted = 0; printk(KERN_INFO - "osst%d:I: This error may be caused by your scsi controller,\n", dev); + "osst%d:I: This warning may be caused by your scsi controller,\n", dev); printk(KERN_INFO "osst%d:I: it has been reported with some Buslogic cards.\n", dev); } @@ -271,11 +271,10 @@ /* Wakeup from interrupt */ static void osst_sleep_done (Scsi_Cmnd * SCpnt) { - unsigned int dev; + unsigned int dev = TAPE_NR(SCpnt->request.rq_dev); OS_Scsi_Tape * STp; - if ((dev = TAPE_NR(SCpnt->request.rq_dev)) < osst_template.nr_dev) { - STp = os_scsi_tapes[dev]; + if (os_scsi_tapes && (STp = os_scsi_tapes[dev])) { if ((STp->buffer)->writing && (SCpnt->sense_buffer[0] & 0x70) == 0x70 && (SCpnt->sense_buffer[2] & 0x40)) { @@ -482,7 +481,8 @@ memset(page_address(STp->buffer->sg[i].page), 0, STp->buffer->sg[i].length); strcpy(STp->buffer->b_data, "READ ERROR ON FRAME"); - } + } else + STp->buffer->buffer_bytes = OS_FRAME_SIZE; return 1; } if (STp->buffer->syscall_result) { @@ -621,8 +621,10 @@ if (!SRpnt) return (-EBUSY); while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && - SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 && - (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8) ) { + (( SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 && + (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8) ) || + ( SRpnt->sr_sense_buffer[2] == 6 && SRpnt->sr_sense_buffer[12] == 0x28 && + SRpnt->sr_sense_buffer[13] == 0 ) )) { #if DEBUG if (debugging) { printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait ready\n", dev); @@ -630,7 +632,7 @@ debugging = 0; } #endif - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ / 10); memset(cmd, 0, MAX_COMMAND_SIZE); @@ -658,6 +660,66 @@ return 0; } +/* + * Wait for a tape to be inserted in the unit + */ +static int osst_wait_for_medium(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout) +{ + unsigned char cmd[MAX_COMMAND_SIZE]; + Scsi_Request * SRpnt; + long startwait = jiffies; +#if DEBUG + int dbg = debugging; + int dev = TAPE_NR(STp->devt); + + printk(OSST_DEB_MSG "osst%d:D: Reached onstream wait for medium\n", dev); +#endif + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE); + *aSRpnt = SRpnt; + if (!SRpnt) return (-EBUSY); + + while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && + SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 0x3a && + SRpnt->sr_sense_buffer[13] == 0 ) { +#if DEBUG + if (debugging) { + printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait medium\n", dev); + printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev); + debugging = 0; + } +#endif + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE); + } + *aSRpnt = SRpnt; +#if DEBUG + debugging = dbg; +#endif + if ( STp->buffer->syscall_result && SRpnt->sr_sense_buffer[2] != 2 && + SRpnt->sr_sense_buffer[12] != 4 && SRpnt->sr_sense_buffer[13] == 1) { +#if DEBUG + printk(OSST_DEB_MSG "osst%d:D: Abnormal exit from onstream wait medium\n", dev); + printk(OSST_DEB_MSG "osst%d:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", dev, + STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2], + SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]); +#endif + return 0; + } +#if DEBUG + printk(OSST_DEB_MSG "osst%d:D: Normal exit from onstream wait medium\n", dev); +#endif + return 1; +} + static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame) { int retval; @@ -696,7 +758,7 @@ result = osst_write_error_recovery(STp, aSRpnt, 0); result |= osst_wait_ready(STp, aSRpnt, 5 * 60); - STp->ps[STp->partition].rw = ST_IDLE; + STp->ps[STp->partition].rw = OS_WRITING_COMPLETE; return (result); } @@ -745,7 +807,7 @@ notyetprinted--; } #endif - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout (HZ / OSST_POLL_PER_SEC); } #if DEBUG @@ -903,6 +965,8 @@ #endif if ( osst_initiate_read(STp, aSRpnt) || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) { + if (STp->raw) + return (-EIO); position = osst_get_frame_position(STp, aSRpnt); if (position >= 0xbae && position < 0xbb8) position = 0xbb8; @@ -968,7 +1032,7 @@ if (cnt > 1) { STp->recover_count++; STp->recover_erreg++; - printk(KERN_WARNING "osst%d:I: Read error at position %d recovered\n", + printk(KERN_WARNING "osst%d:I: Don't worry, Read error at position %d recovered\n", dev, STp->read_error_frame); } STp->read_count++; @@ -1525,7 +1589,10 @@ retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending); else retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending); - printk(KERN_WARNING "osst%d:I: Write error%srecovered\n", dev, retval?" not ":" "); + printk(KERN_WARNING "osst%d:%s: %sWrite error%srecovered\n", dev, + retval?"E" :"I", + retval?"" :"Don't worry, ", + retval?" not ":" "); break; case OS_WRITE_LAST_MARK: printk(KERN_ERR "osst%d:E: Bad frame in update last marker, fatal\n", dev); @@ -1596,7 +1663,7 @@ mt_count, last_mark_ppos); #endif if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) { - osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG printk(OSST_DEB_MSG @@ -1628,7 +1695,7 @@ #if DEBUG printk(OSST_DEB_MSG "osst%d:D: Positioning to last mark at %d\n", dev, last_mark_ppos); #endif - osst_set_frame_position(STp, aSRpnt, last_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); cnt++; if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG @@ -1755,7 +1822,7 @@ #endif return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); } else { - osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n", @@ -1795,7 +1862,7 @@ #endif return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); } - osst_set_frame_position(STp, aSRpnt, STp->first_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos); if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG printk(OSST_DEB_MSG @@ -1827,7 +1894,7 @@ #if DEBUG else printk(OSST_DEB_MSG "osst%d:D: Positioning to next mark at %d\n", dev, next_mark_ppos); #endif - osst_set_frame_position(STp, aSRpnt, next_mark_ppos, 0); + osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); cnt++; if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG @@ -2464,7 +2531,7 @@ } #if DEBUG - printk(KERN_INFO "osst%d:D: Block Size changed to 32.5K\n", dev); + printk(KERN_INFO "osst%d:D: Drive Block Size changed to 32.5K\n", dev); /* * In debug mode, we want to see as many errors as possible * to test the error recovery mechanism. @@ -3402,6 +3469,7 @@ if (retval) goto out; STps->rw = ST_IDLE; + /* FIXME -- this may leave the tape without EOD and up2date headers */ } if ((count % STp->block_size) != 0) { @@ -3814,6 +3882,10 @@ ioctl_result = osst_flush_write_buffer(STp, &SRpnt); else ioctl_result = 0; +#if DEBUG + if (debugging) + printk(OSST_DEB_MSG "osst%d:D: Writing %ld filemark(s).\n", dev, arg); +#endif for (i=0; i= 0) fileno += arg; @@ -3833,14 +3905,9 @@ cmd[4] = arg; timeout = STp->timeout; #if DEBUG - if (debugging) { - if (cmd_in == MTWEOF) - printk(OSST_DEB_MSG "osst%d:D: Writing %d filemarks.\n", dev, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); - else - printk(OSST_DEB_MSG "osst%d:D: Writing %d setmarks.\n", dev, + if (debugging) + printk(OSST_DEB_MSG "osst%d:D: Writing %d setmark(s).\n", dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); - } #endif if (fileno >= 0) fileno += arg; @@ -3853,8 +3920,12 @@ case MTRETEN: cmd[0] = START_STOP; cmd[1] = 1; /* Don't wait for completion */ - if (cmd_in == MTLOAD) + if (cmd_in == MTLOAD) { + if (STp->ready == ST_NO_TAPE) + cmd[4] = 4; /* open tray */ + else cmd[4] = 1; /* load */ + } if (cmd_in == MTRETEN) cmd[4] = 3; /* retension then mount */ if (cmd_in == MTOFFL) @@ -3993,7 +4064,7 @@ printk(OSST_DEB_MSG "osst%d:D: IOCTL (%d) Result=%d\n", dev, cmd_in, ioctl_result); #endif - if (!ioctl_result) { + if (!ioctl_result) { /* success */ if (cmd_in == MTFSFM) { fileno--; @@ -4070,6 +4141,8 @@ if (cmd_in == MTLOCK) STp->door_locked = ST_LOCK_FAILS; + if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60)) + ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60); } *aSRpnt = SRpnt; @@ -4110,6 +4183,7 @@ __MOD_INC_USE_COUNT(STp->device->host->hostt->module); if (osst_template.module) __MOD_INC_USE_COUNT(osst_template.module); + STp->device->access_count++; if (mode != STp->current_mode) { #if DEBUG @@ -4126,6 +4200,8 @@ STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY); STp->raw = (minor(inode->i_rdev) & 0x40) != 0; + if (STp->raw) + STp->header_ok = 0; /* Allocate a buffer for this user */ need_dma_buffer = STp->restr_dma; @@ -4216,7 +4292,7 @@ STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ for (i=0; i < ST_NBR_PARTITIONS; i++) { STps = &(STp->ps[i]); - STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */ + STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */ STps->eof = ST_NOEOF; STps->at_sm = 0; STps->last_block_valid = FALSE; @@ -4264,8 +4340,8 @@ STp->door_locked = ST_LOCKED_AUTO; } if (!STp->frame_in_buffer) { - STp->block_size = (STp->raw) ? OS_FRAME_SIZE : ( - (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE); + STp->block_size = (STm->default_blksize > 0) ? + STm->default_blksize : OS_DATA_SIZE; STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0; } STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size; @@ -4358,8 +4434,6 @@ return 0; } - STp->min_block = STp->max_block = (-1); - osst_configure_onstream(STp, &SRpnt); /* STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; FIXME */ @@ -4386,11 +4460,9 @@ } else STp->buffer->aux = NULL; /* this had better never happen! */ - STp->block_size = (STp->raw) ? OS_FRAME_SIZE : ( + STp->block_size = STp->raw ? OS_FRAME_SIZE : ( (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE); - STp->min_block = 512; - STp->max_block = OS_DATA_SIZE; - STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size; + STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size; STp->buffer->buffer_bytes = STp->buffer->read_pointer = STp->frame_in_buffer = 0; @@ -4448,6 +4520,8 @@ STp->buffer = NULL; } STp->in_use = 0; + STp->header_ok = 0; + STp->device->access_count--; if (STp->device->host->hostt->module) __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); @@ -4484,7 +4558,7 @@ if (result != 0 && result != (-ENOSPC)) goto out; } - if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) { + if ( STps->rw >= ST_WRITING && !(STp->device)->was_reset) { #if DEBUG if (debugging) { @@ -4494,16 +4568,17 @@ dev, STp->nbr_waits, STp->nbr_finished); } #endif + if (STp->write_type != OS_WRITE_NEW_MARK) { + /* true unless the user wrote the filemark for us */ + result = osst_flush_drive_buffer(STp, &SRpnt); + if (result < 0) goto out; + result = osst_write_filemark(STp, &SRpnt); + if (result < 0) goto out; - result = osst_flush_drive_buffer(STp, &SRpnt); - if (result < 0) goto out; - result = osst_write_filemark(STp, &SRpnt); - if (result < 0) goto out; - - if (STps->drv_file >= 0) - STps->drv_file++ ; - STps->drv_block = 0; - + if (STps->drv_file >= 0) + STps->drv_file++ ; + STps->drv_block = 0; + } result = osst_write_eod(STp, &SRpnt); osst_write_header(STp, &SRpnt, !(STp->rew_at_close)); @@ -4587,7 +4662,12 @@ if (STp->buffer != NULL) STp->buffer->in_use = 0; + if (STp->raw) + STp->header_ok = 0; + STp->in_use = 0; + STp->device->access_count--; + if (STp->device->host->hostt->module) __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); if(osst_template.module) @@ -4637,7 +4717,10 @@ cmd_type = _IOC_TYPE(cmd_in); cmd_nr = _IOC_NR(cmd_in); - +#if DEBUG + printk(OSST_DEB_MSG "osst%d:D: Ioctl %d,%d in %s mode\n", dev, + cmd_type, cmd_nr, STp->raw?"raw":"normal"); +#endif if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { struct mtop mtc; @@ -4720,8 +4803,8 @@ } } - if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && - mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM && + if (mtc.mt_op != MTNOP && mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM && + mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETBLK && mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART) STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */ @@ -4773,7 +4856,10 @@ } if (mtc.mt_op == MTSEEK) { - i = osst_seek_sector(STp, &SRpnt, mtc.mt_count); + if (STp->raw) + i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0); + else + i = osst_seek_sector(STp, &SRpnt, mtc.mt_count); if (!STp->can_partitions) STp->ps[0].rw = ST_IDLE; retval = i; @@ -4878,7 +4964,10 @@ retval = (-EINVAL); goto out; } - blk = osst_get_sector(STp, &SRpnt); + if (STp->raw) + blk = osst_get_frame_position(STp, &SRpnt); + else + blk = osst_get_sector(STp, &SRpnt); if (blk < 0) { retval = blk; goto out; @@ -4972,7 +5061,7 @@ tb = NULL; break; } - tb->sg[segs].page = NULL; + tb->sg[segs].page = NULL; tb->sg[segs].length = b_size; got += b_size; segs++; @@ -5424,6 +5513,8 @@ tpnt->partition = 0; tpnt->new_partition = 0; tpnt->nbr_partitions = 0; + tpnt->min_block = 512; + tpnt->max_block = OS_DATA_SIZE; tpnt->timeout = OSST_TIMEOUT; tpnt->long_timeout = OSST_LONG_TIMEOUT; @@ -5463,6 +5554,7 @@ tpnt->current_mode = 0; tpnt->modes[0].defined = TRUE; + tpnt->modes[2].defined = TRUE; tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE; init_MUTEX(&tpnt->lock); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/osst.h linux-2.5/drivers/scsi/osst.h --- linux-2.5.5/drivers/scsi/osst.h Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/scsi/osst.h Tue Feb 19 00:07:17 2002 @@ -1,5 +1,5 @@ /* - * $Header: /home/cvsroot/Driver/osst.h,v 1.11 2001/01/26 01:54:49 riede Exp $ + * $Header: /home/cvsroot/Driver/osst.h,v 1.12 2001/10/11 00:30:15 riede Exp $ */ #include @@ -638,3 +638,5 @@ #define OS_WRITE_HEADER 4 #define OS_WRITE_FILLER 5 +/* Additional rw state */ +#define OS_WRITING_COMPLETE 3 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/pas16.c linux-2.5/drivers/scsi/pas16.c --- linux-2.5.5/drivers/scsi/pas16.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/scsi/pas16.c Mon Jan 7 23:17:50 2002 @@ -1,7 +1,7 @@ #define AUTOSENSE #define PSEUDO_DMA -#define FOO -#define UNSAFE /* Not unsafe for PAS16 -- use it */ +#define BOARD_REQUIRES_NO_UDELAY /* PAS16 needs no I/O recovery delays */ +#define UNSAFE /* Not unsafe for PAS16 -- use it */ /* * This driver adapted from Drew Eckhardt's Trantor T128 driver @@ -52,8 +52,6 @@ * * PARITY - enable parity checking. Not supported. * - * SCSI2 - enable support for SCSI-II tagged queueing. Untested. - * * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. This * parameter comes from the NCR5380 code. It is NOT unsafe with * the PAS16 and you should use it. If you don't you will have @@ -62,8 +60,6 @@ * want to use UNSAFE you can try defining LIMIT_TRANSFERSIZE or * twiddle with the transfer size in the high level code. * - * USLEEP - enable support for devices that don't disconnect. Untested. - * * The card is detected and initialized in one of several ways : * 1. Autoprobe (default) - There are many different models of * the Pro Audio Spectrum/Studio 16, and I only have one of @@ -109,7 +105,7 @@ * * (IRQ_AUTO == 254, IRQ_NONE == 255 in NCR5380.h) */ - + #include #include @@ -133,467 +129,402 @@ static int pas_wmaxi = 0; static unsigned short pas16_addr = 0; static int pas16_irq = 0; - -int scsi_irq_translate[] = - { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 }; +static int scsi_irq_translate[] = { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 }; /* The default_irqs array contains values used to set the irq into the * board via software (as must be done on newer model boards without * irq jumpers on the board). The first value in the array will be * assigned to logical board 0, the next to board 1, etc. */ -int default_irqs[] __initdata = - { PAS16_DEFAULT_BOARD_1_IRQ, - PAS16_DEFAULT_BOARD_2_IRQ, - PAS16_DEFAULT_BOARD_3_IRQ, - PAS16_DEFAULT_BOARD_4_IRQ - }; + +static int default_irqs[] __initdata = { + PAS16_DEFAULT_BOARD_1_IRQ, + PAS16_DEFAULT_BOARD_2_IRQ, + PAS16_DEFAULT_BOARD_3_IRQ, + PAS16_DEFAULT_BOARD_4_IRQ +}; static struct override { - unsigned short io_port; - int irq; -} overrides + unsigned short io_port; + int irq; +} overrides #ifdef PAS16_OVERRIDE - [] __initdata = PAS16_OVERRIDE; +[] __initdata = PAS16_OVERRIDE; #else - [4] __initdata = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO}, - {0,IRQ_AUTO}}; +[4] __initdata = { + {0, IRQ_AUTO}, + {0, IRQ_AUTO}, + {0, IRQ_AUTO}, + {0, IRQ_AUTO} +}; #endif #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) static struct base { - unsigned short io_port; - int noauto; -} bases[] __initdata = - { {PAS16_DEFAULT_BASE_1, 0}, - {PAS16_DEFAULT_BASE_2, 0}, - {PAS16_DEFAULT_BASE_3, 0}, - {PAS16_DEFAULT_BASE_4, 0} - }; + unsigned short io_port; + int noauto; +} bases[] __initdata = { + {PAS16_DEFAULT_BASE_1, 0}, + {PAS16_DEFAULT_BASE_2, 0}, + {PAS16_DEFAULT_BASE_3, 0}, + {PAS16_DEFAULT_BASE_4, 0} +}; #define NO_BASES (sizeof (bases) / sizeof (struct base)) -unsigned short pas16_offset[ 8 ] = - { - 0x1c00, /* OUTPUT_DATA_REG */ - 0x1c01, /* INITIATOR_COMMAND_REG */ - 0x1c02, /* MODE_REG */ - 0x1c03, /* TARGET_COMMAND_REG */ - 0x3c00, /* STATUS_REG ro, SELECT_ENABLE_REG wo */ - 0x3c01, /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */ - 0x3c02, /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?) - * START_DMA_TARGET_RECEIVE_REG wo - */ - 0x3c03, /* RESET_PARITY_INTERRUPT_REG ro, - * START_DMA_INITIATOR_RECEIVE_REG wo - */ - }; +unsigned short pas16_offset[8] = { + 0x1c00, /* OUTPUT_DATA_REG */ + 0x1c01, /* INITIATOR_COMMAND_REG */ + 0x1c02, /* MODE_REG */ + 0x1c03, /* TARGET_COMMAND_REG */ + 0x3c00, /* STATUS_REG ro, SELECT_ENABLE_REG wo */ + 0x3c01, /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */ + 0x3c02, /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?) + * START_DMA_TARGET_RECEIVE_REG wo + */ + 0x3c03, /* RESET_PARITY_INTERRUPT_REG ro, + * START_DMA_INITIATOR_RECEIVE_REG wo + */ +}; /*----------------------------------------------------------------*/ -/* the following will set the monitor border color (useful to find - where something crashed or gets stuck at */ -/* 1 = blue - 2 = green - 3 = cyan - 4 = red - 5 = magenta - 6 = yellow - 7 = white -*/ -#if 1 -#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);} -#else -#define rtrc(i) {} -#endif - -/* - * Function : enable_board( int board_num, unsigned short port ) - * - * Purpose : set address in new model board - * - * Inputs : board_num - logical board number 0-3, port - base address +/** + * enable_board - enable a pas16 board + * @board_num: logical board id + * @port: port to assign it * + * Sets the address on new model PAS16 hardware */ -static void __init - enable_board( int board_num, unsigned short port ) +static void __init enable_board(int board_num, unsigned short port) { - outb( 0xbc + board_num, MASTER_ADDRESS_PTR ); - outb( port >> 2, MASTER_ADDRESS_PTR ); + outb(0xbc + board_num, MASTER_ADDRESS_PTR); + outb(port >> 2, MASTER_ADDRESS_PTR); } - - -/* - * Function : init_board( unsigned short port, int irq ) - * - * Purpose : Set the board up to handle the SCSI interface - * - * Inputs : port - base address of the board, - * irq - irq to assign to the SCSI port - * force_irq - set it even if it conflicts with sound driver +/** + * init_board - set up board + * @port: board address + * @irq: interrupt line + * @force_irq: if true allow scsi/audio on the same int * + * Set the board up to handle the SCSI interface */ -static void __init - init_board( unsigned short io_port, int irq, int force_irq ) +static void __init init_board(unsigned short io_port, int irq, int force_irq) { - unsigned int tmp; - unsigned int pas_irq_code; + unsigned int tmp; + unsigned int pas_irq_code; /* Initialize the SCSI part of the board */ - outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG ); /* Timeout counter */ - outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET ); /* Reset TC */ - outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */ + outb(0x30, io_port + P_TIMEOUT_COUNTER_REG); /* Timeout counter */ + outb(0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET); /* Reset TC */ + outb(0x01, io_port + WAIT_STATE); /* 1 Wait state */ - NCR5380_read( RESET_PARITY_INTERRUPT_REG ); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); - /* Set the SCSI interrupt pointer without mucking up the sound - * interrupt pointer in the same byte. + /* + * Set the SCSI interrupt pointer without mucking up the sound + * interrupt pointer in the same byte. */ - pas_irq_code = ( irq < 16 ) ? scsi_irq_translate[irq] : 0; - tmp = inb( io_port + IO_CONFIG_3 ); - - if( (( tmp & 0x0f ) == pas_irq_code) && pas_irq_code > 0 - && !force_irq ) - { - printk( "pas16: WARNING: Can't use same irq as sound " - "driver -- interrupts disabled\n" ); - /* Set up the drive parameters, disable 5380 interrupts */ - outb( 0x4d, io_port + SYS_CONFIG_4 ); - } - else - { - tmp = ( tmp & 0x0f ) | ( pas_irq_code << 4 ); - outb( tmp, io_port + IO_CONFIG_3 ); + + pas_irq_code = (irq < 16) ? scsi_irq_translate[irq] : 0; + tmp = inb(io_port + IO_CONFIG_3); + + if (((tmp & 0x0f) == pas_irq_code) && pas_irq_code > 0 && !force_irq) { + printk(KERN_WARNING "pas16: WARNING: Can't use same irq as sound " "driver -- interrupts disabled\n"); + /* Set up the drive parameters, disable 5380 interrupts */ + outb(0x4d, io_port + SYS_CONFIG_4); + } else { + tmp = (tmp & 0x0f) | (pas_irq_code << 4); + outb(tmp, io_port + IO_CONFIG_3); - /* Set up the drive parameters and enable 5380 interrupts */ - outb( 0x6d, io_port + SYS_CONFIG_4 ); + /* Set up the drive parameters and enable 5380 interrupts */ + outb(0x6d, io_port + SYS_CONFIG_4); } } -/* - * Function : pas16_hw_detect( unsigned short board_num ) - * - * Purpose : determine if a pas16 board is present - * - * Inputs : board_num - logical board number ( 0 - 3 ) +/** + * pas16_hw_detect - probe for hardware + * @board_num: logical board ID to probe for * - * Returns : 0 if board not found, 1 if found. + * Determine if a pas16 board is present */ -static int __init - pas16_hw_detect( unsigned short board_num ) +static int __init pas16_hw_detect(unsigned short board_num) { - unsigned char board_rev, tmp; - unsigned short io_port = bases[ board_num ].io_port; + unsigned char board_rev, tmp; + unsigned short io_port = bases[board_num].io_port; - /* See if we can find a PAS16 board at the address associated - * with this logical board number. - */ - - /* First, attempt to take a newer model board out of reset and - * give it a base address. This shouldn't affect older boards. - */ - enable_board( board_num, io_port ); + /* See if we can find a PAS16 board at the address associated + * with this logical board number. + */ - /* Now see if it looks like a PAS16 board */ - board_rev = inb( io_port + PCB_CONFIG ); + /* First, attempt to take a newer model board out of reset and + * give it a base address. This shouldn't affect older boards. + */ + enable_board(board_num, io_port); - if( board_rev == 0xff ) - return 0; + /* Now see if it looks like a PAS16 board */ + board_rev = inb(io_port + PCB_CONFIG); - tmp = board_rev ^ 0xe0; + if (board_rev == 0xff) + return 0; - outb( tmp, io_port + PCB_CONFIG ); - tmp = inb( io_port + PCB_CONFIG ); - outb( board_rev, io_port + PCB_CONFIG ); + tmp = board_rev ^ 0xe0; - if( board_rev != tmp ) /* Not a PAS-16 */ - return 0; + outb(tmp, io_port + PCB_CONFIG); + tmp = inb(io_port + PCB_CONFIG); + outb(board_rev, io_port + PCB_CONFIG); - if( ( inb( io_port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 ) - return 0; /* return if no SCSI interface found */ + if (board_rev != tmp) /* Not a PAS-16 */ + return 0; - /* Mediavision has some new model boards that return ID bits - * that indicate a SCSI interface, but they're not (LMS). We'll - * put in an additional test to try to weed them out. - */ - - outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */ - NCR5380_write( MODE_REG, 0x20 ); /* Is it really SCSI? */ - if( NCR5380_read( MODE_REG ) != 0x20 ) /* Write to a reg. */ - return 0; /* and try to read */ - NCR5380_write( MODE_REG, 0x00 ); /* it back. */ - if( NCR5380_read( MODE_REG ) != 0x00 ) - return 0; + if ((inb(io_port + OPERATION_MODE_1) & 0x03) != 0x03) + return 0; /* return if no SCSI interface found */ - return 1; -} + /* Mediavision has some new model boards that return ID bits + * that indicate a SCSI interface, but they're not (LMS). We'll + * put in an additional test to try to weed them out. + */ + outb(0x01, io_port + WAIT_STATE); /* 1 Wait state */ + NCR5380_write(MODE_REG, 0x20); /* Is it really SCSI? */ + if (NCR5380_read(MODE_REG) != 0x20) /* Write to a reg. */ + return 0; /* and try to read */ + NCR5380_write(MODE_REG, 0x00); /* it back. */ + if (NCR5380_read(MODE_REG) != 0x00) + return 0; -/* - * Function : pas16_setup(char *str, int *ints) - * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. + return 1; +} + +/** + * pas16_setup - parse command line + * @str: command line block * + * LILO command line initialization of the overrides array from + * the passed in pas16= options */ -void __init pas16_setup(char *str, int *ints) +int __init pas16_setup(char *str) { - static int commandline_current = 0; - int i; - if (ints[0] != 2) - printk("pas16_setup : usage pas16=io_port,irq\n"); - else - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].io_port = (unsigned short) ints[1]; - overrides[commandline_current].irq = ints[2]; - for (i = 0; i < NO_BASES; ++i) - if (bases[i].io_port == (unsigned short) ints[1]) { - bases[i].noauto = 1; - break; - } - ++commandline_current; + static int commandline_current = 0; + int i; + int ints[10]; + + get_options(str, sizeof(ints) / sizeof(int), ints); + if (ints[0] != 2) + printk(KERN_ERR "pas16_setup : usage pas16=io_port,irq\n"); + else if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].io_port = (unsigned short) ints[1]; + overrides[commandline_current].irq = ints[2]; + for (i = 0; i < NO_BASES; ++i) + if (bases[i].io_port == (unsigned short) ints[1]) { + bases[i].noauto = 1; + break; + } + ++commandline_current; } + return 1; } -/* - * Function : int pas16_detect(Scsi_Host_Template * tpnt) - * - * Purpose : detects and initializes PAS16 controllers - * that were autoprobed, overridden on the LILO command line, - * or specified at compile time. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. +__setup("pas16=", pas16_setup); + +/** + * pas16_detect - detect and configure a pas16 + * @tpnt: template * + * Detects and initializes PAS16 controllers that were autoprobed, + * overridden on the LILO command line, or specified at compile time. */ int __init pas16_detect(Scsi_Host_Template * tpnt) { - static int current_override = 0; - static unsigned short current_base = 0; - struct Scsi_Host *instance; - unsigned short io_port; - int count; + static int current_override = 0; + static unsigned short current_base = 0; + struct Scsi_Host *instance; + unsigned short io_port; + int count; + + tpnt->proc_name = "pas16"; + tpnt->proc_info = &pas16_proc_info; + + if (pas16_addr != 0) { + overrides[0].io_port = pas16_addr; + /* + * This is how we avoid seeing more than + * one host adapter at the same I/O port. + * Cribbed shamelessly from pas16_setup(). + */ + for (count = 0; count < NO_BASES; ++count) + if (bases[count].io_port == pas16_addr) { + bases[count].noauto = 1; + break; + } + } + if (pas16_irq != 0) + overrides[0].irq = pas16_irq; - tpnt->proc_name = "pas16"; - tpnt->proc_info = &pas16_proc_info; + for (count = 0; current_override < NO_OVERRIDES; ++current_override) { + io_port = 0; - if (pas16_addr != 0) { - overrides[0].io_port = pas16_addr; - /* - * This is how we avoid seeing more than - * one host adapter at the same I/O port. - * Cribbed shamelessly from pas16_setup(). - */ - for (count = 0; count < NO_BASES; ++count) - if (bases[count].io_port == pas16_addr) { - bases[count].noauto = 1; - break; - } - } - if (pas16_irq != 0) - overrides[0].irq = pas16_irq; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - io_port = 0; - - if (overrides[current_override].io_port) - { - io_port = overrides[current_override].io_port; - enable_board( current_override, io_port ); - init_board( io_port, overrides[current_override].irq, 1 ); - } - else - for (; !io_port && (current_base < NO_BASES); ++current_base) { -#if (PDEBUG & PDEBUG_INIT) - printk("scsi-pas16 : probing io_port %04x\n", (unsigned int) bases[current_base].io_port); -#endif - if ( !bases[current_base].noauto && - pas16_hw_detect( current_base ) ){ - io_port = bases[current_base].io_port; - init_board( io_port, default_irqs[ current_base ], 0 ); -#if (PDEBUG & PDEBUG_INIT) - printk("scsi-pas16 : detected board.\n"); -#endif + if (overrides[current_override].io_port) { + io_port = overrides[current_override].io_port; + enable_board(current_override, io_port); + init_board(io_port, overrides[current_override].irq, 1); + } + else + { + for (; !io_port && (current_base < NO_BASES); ++current_base) { + if (!bases[current_base].noauto && pas16_hw_detect(current_base)) { + io_port = bases[current_base].io_port; + init_board(io_port, default_irqs[current_base], 0); + } + } } - } + if (!io_port) + break; -#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT) - printk("scsi-pas16 : io_port = %04x\n", (unsigned int) io_port); -#endif + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) + break; + + instance->io_port = io_port; + + NCR5380_init(instance, 0); + + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, do_pas16_intr, SA_INTERRUPT, "pas16", NULL)) { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq == IRQ_NONE) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + /* Disable 5380 interrupts, leave drive params the same */ + outb(0x4d, io_port + SYS_CONFIG_4); + outb((inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3); + } - if (!io_port) - break; + printk(KERN_INFO "scsi%d : at 0x%04x", instance->host_no, (int) + instance->io_port); + if (instance->irq == IRQ_NONE) + printk(" interrupts disabled"); + else + printk(" irq %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - break; - - instance->io_port = io_port; - - NCR5380_init(instance, 0); - - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS); - - if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_pas16_intr, SA_INTERRUPT, "pas16", instance)) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = IRQ_NONE; - } - - if (instance->irq == IRQ_NONE) { - printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - /* Disable 5380 interrupts, leave drive params the same */ - outb( 0x4d, io_port + SYS_CONFIG_4 ); - outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 ); + ++current_override; + ++count; } - -#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT) - printk("scsi%d : irq = %d\n", instance->host_no, instance->irq); -#endif - - printk("scsi%d : at 0x%04x", instance->host_no, (int) - instance->io_port); - if (instance->irq == IRQ_NONE) - printk (" interrupts disabled"); - else - printk (" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; + return count; } -/* - * Function : int pas16_biosparam(Disk *disk, kdev_t dev, int *ip) +/** + * pas16_biosparam - generate C/H/S data + * @disk: Disk to set up + * @dev: device ident of disk + * @ip: array to return C/H/S mapping * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for + * Generates a BIOS / DOS compatible H-C-S mapping for * the specified device / size. - * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} - * - * Returns : always 0 (success), initializes ip - * */ -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. - */ - -int pas16_biosparam(Disk * disk, kdev_t dev, int * ip) +int pas16_biosparam(Disk * disk, kdev_t dev, int *ip) { - int size = disk->capacity; - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; /* I think I have it as /(32*64) */ - if( ip[2] > 1024 ) { /* yes, >, not >= */ - ip[0]=255; - ip[1]=63; - ip[2]=size/(63*255); - if( ip[2] > 1023 ) /* yes >1023... */ - ip[2] = 1023; - } + int size = disk->capacity; + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; /* I think I have it as /(32*64) */ + if (ip[2] > 1024) { /* yes, >, not >= */ + ip[0] = 255; + ip[1] = 63; + ip[2] = size / (63 * 255); + if (ip[2] > 1023) /* yes >1023... */ + ip[2] = 1023; + } - return 0; + return 0; } -/* - * Function : int NCR5380_pread (struct Scsi_Host *instance, - * unsigned char *dst, int len) - * - * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to - * dst - * - * Inputs : dst = destination, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. +/** + * NCR5380_pread - pseudo DMA read + * @instance: board to read from + * @dst: destination for data + * @len: expected/max block length + * + * Fast 5380 pseudo-dma read function, transfers len bytes to + * dst. Unlike most boards the PAS has IRQs enabled here, which + * helps no end. */ -static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, - int len) { - register unsigned char *d = dst; - register unsigned short reg = (unsigned short) (instance->io_port + - P_DATA_REG_OFFSET); - register int i = len; - int ii = 0; - - while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) ) - ++ii; - - insb( reg, d, i ); - - if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { - outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); - printk("scsi%d : watchdog timer fired in NCR5380_pread()\n", - instance->host_no); - return -1; - } - if (ii > pas_maxi) - pas_maxi = ii; - return 0; +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) +{ + unsigned char *d = dst; + unsigned short reg = (unsigned short) (instance->io_port + P_DATA_REG_OFFSET); + int i = len; + int ii = 0; + + while (!(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY)) + ++ii; + + insb(reg, d, i); + + if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { + outb(P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); + printk(KERN_ERR "scsi%d : watchdog timer fired in NCR5380_pread()\n", instance->host_no); + return -1; + } + if (ii > pas_maxi) + pas_maxi = ii; + return 0; } -/* - * Function : int NCR5380_pwrite (struct Scsi_Host *instance, - * unsigned char *src, int len) - * - * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from - * src - * - * Inputs : src = source, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. +/** + * NCR5380_pwrite - pseudo DMA write + * @instance: board to write to + * @src: source for data + * @len: expected/max block length + * + * Fast 5380 pseudo-dma write function, transfers len bytes from + * src. Unlike most boards the PAS has IRQs enabled here, which + * helps no end. */ -static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src, - int len) { - register unsigned char *s = src; - register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET); - register int i = len; - int ii = 0; - - while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) ) - ++ii; - - outsb( reg, s, i ); - - if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { - outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); - printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n", - instance->host_no); - return -1; - } - if (ii > pas_maxi) - pas_wmaxi = ii; - return 0; +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) +{ + unsigned char *s = src; + unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET); + int i = len; + int ii = 0; + + while (!((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY)) + ++ii; + + outsb(reg, s, i); + + if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { + outb(P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); + printk(KERN_ERR "scsi%d : watchdog timer fired in NCR5380_pwrite()\n", instance->host_no); + return -1; + } + if (ii > pas_maxi) + pas_wmaxi = ii; + return 0; } #include "NCR5380.c" diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/pci2000.c linux-2.5/drivers/scsi/pci2000.c --- linux-2.5.5/drivers/scsi/pci2000.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/scsi/pci2000.c Sun Jan 6 19:17:51 2002 @@ -389,7 +389,7 @@ OpDone (SCpnt, DID_OK << 16); irq_return: - spin_unlock_irqrestore(&shost->host_lock, flags); + spin_unlock_irqrestore(shost->host_lock, flags); out:; } /**************************************************************** diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/pcmcia/aha152x_stub.c linux-2.5/drivers/scsi/pcmcia/aha152x_stub.c --- linux-2.5.5/drivers/scsi/pcmcia/aha152x_stub.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/scsi/pcmcia/aha152x_stub.c Thu Dec 27 22:10:28 2001 @@ -5,7 +5,7 @@ This driver supports the Adaptec AHA-1460, the New Media Bus Toaster, and the New Media Toast & Jam. - aha152x_cs.c 1.54 2000/06/12 21:27:25 + aha152x_cs.c 1.58 2001/10/13 00:08:51 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -22,8 +22,8 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the + terms of the GNU General Public License version 2 (the "GPL"), in + which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision @@ -57,42 +57,39 @@ #include #include -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"aha152x_cs.c 1.54 2000/06/12 21:27:25 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds "); +MODULE_DESCRIPTION("Adaptec AHA152x-compatible PCMCIA SCSI driver"); +MODULE_LICENSE("Dual MPL/GPL"); -/* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); -/* SCSI bus setup options */ -static int host_id = 7; -static int reconnect = 1; -static int parity = 1; -static int synchronous = 0; -static int reset_delay = 100; -static int ext_trans = 0; +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") -MODULE_PARM(irq_mask, "i"); -MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM(host_id, "i"); -MODULE_PARM(reconnect, "i"); -MODULE_PARM(parity, "i"); -MODULE_PARM(synchronous, "i"); -MODULE_PARM(reset_delay, "i"); -MODULE_PARM(ext_trans, "i"); +INT_MODULE_PARM(irq_mask, 0xdeb8); +INT_MODULE_PARM(host_id, 7); +INT_MODULE_PARM(reconnect, 1); +INT_MODULE_PARM(parity, 1); +INT_MODULE_PARM(synchronous, 0); +INT_MODULE_PARM(reset_delay, 100); +INT_MODULE_PARM(ext_trans, 0); -MODULE_LICENSE("Dual MPL/GPL"); +#ifdef AHA152X_DEBUG +INT_MODULE_PARM(debug, 0); +#endif + +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"aha152x_cs.c 1.58 2001/10/13 00:08:51 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ @@ -277,7 +274,6 @@ release_region(link->io.BasePort1, link->io.NumPorts1); /* Set configuration options for the aha152x driver */ - ints[0] = 7; ints[1] = link->io.BasePort1; ints[2] = link->irq.AssignedIRQ; ints[3] = host_id; @@ -285,9 +281,13 @@ ints[5] = parity; ints[6] = synchronous; ints[7] = reset_delay; - if (ext_trans) { - ints[8] = ext_trans; ints[0] = 8; - } + ints[8] = ext_trans; +#ifdef AHA152X_DEBUG + ints[9] = debug; + ints[0] = 9; +#else + ints[0] = 8; +#endif aha152x_setup("PCMCIA setup", ints); scsi_register_host(&driver_template); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/pcmcia/fdomain_stub.c linux-2.5/drivers/scsi/pcmcia/fdomain_stub.c --- linux-2.5.5/drivers/scsi/pcmcia/fdomain_stub.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/scsi/pcmcia/fdomain_stub.c Thu Dec 27 22:10:28 2001 @@ -2,7 +2,7 @@ A driver for Future Domain-compatible PCMCIA SCSI cards - fdomain_cs.c 1.43 2000/06/12 21:27:25 + fdomain_cs.c 1.47 2001/10/13 00:08:52 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -19,8 +19,8 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the + terms of the GNU General Public License version 2 (the "GPL"), in + which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision @@ -54,27 +54,30 @@ #include #include -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"fdomain_cs.c 1.43 2000/06/12 21:27:25 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds "); +MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver"); +MODULE_LICENSE("Dual MPL/GPL"); + +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +INT_MODULE_PARM(irq_mask, 0xdeb8); static int irq_list[4] = { -1 }; - -MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"fdomain_cs.c 1.47 2001/10/13 00:08:52 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + /*====================================================================*/ typedef struct scsi_info_t { @@ -212,6 +215,7 @@ u_char tuple_data[64]; Scsi_Device *dev; dev_node_t *node, **tail; + char str[16]; struct Scsi_Host *host; DEBUG(0, "fdomain_config(0x%p)\n", link); @@ -252,7 +256,8 @@ ints[0] = 2; ints[1] = link->io.BasePort1; ints[2] = link->irq.AssignedIRQ; - fdomain_setup("PCMCIA setup", ints); + sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ); + fdomain_setup(str, ints); scsi_register_host(&driver_template); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/pcmcia/qlogic_stub.c linux-2.5/drivers/scsi/pcmcia/qlogic_stub.c --- linux-2.5.5/drivers/scsi/pcmcia/qlogic_stub.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/scsi/pcmcia/qlogic_stub.c Thu Dec 27 22:10:28 2001 @@ -2,7 +2,7 @@ A driver for the Qlogic SCSI card - qlogic_cs.c 1.79 2000/06/12 21:27:26 + qlogic_cs.c 1.83 2001/10/13 00:08:53 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -19,8 +19,8 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the + terms of the GNU General Public License version 2 (the "GPL"), in + which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -61,26 +62,29 @@ extern void qlogicfas_preset(int port, int irq); -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"qlogic_cs.c 1.79 2000/06/12 21:27:26 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ -/* Parameters that can be set with 'insmod' */ +/* Module parameters */ + +MODULE_AUTHOR("David Hinds "); +MODULE_DESCRIPTION("Qlogic PCMCIA SCSI driver"); +MODULE_LICENSE("Dual MPL/GPL"); + +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +INT_MODULE_PARM(irq_mask, 0xdeb8); static int irq_list[4] = { -1 }; - -MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); + +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"qlogic_cs.c 1.83 2001/10/13 00:08:53 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif /*====================================================================*/ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/ppa.c linux-2.5/drivers/scsi/ppa.c --- linux-2.5.5/drivers/scsi/ppa.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/scsi/ppa.c Tue Feb 19 00:43:15 2002 @@ -152,7 +152,6 @@ "pardevice is owning the port for too longtime!\n", i); parport_unregister_device(ppa_hosts[i].dev); - spin_lock_irq(ppa_hosts[i].cur_cmd->host->host_lock); return 0; } } @@ -221,13 +220,11 @@ printk(" supported by the imm (ZIP Plus) driver. If the\n"); printk(" cable is marked with \"AutoDetect\", this is what has\n"); printk(" happened.\n"); - spin_lock_irq(hreg->host_lock); return 0; } try_again = 1; goto retry_entry; } else { - spin_lock_irq(hreg->host_lock); return 1; /* return number of hosts detected */ } } @@ -702,7 +699,7 @@ * change things for "normal" hardware since generally * the 6th bit is always high. * This makes the CPU load higher on some hardware - * but otherwise we can not get more then 50K/secs + * but otherwise we can not get more than 50K/secs * on this problem hardware. */ if ((r & 0xc0) != 0xc0) { @@ -738,7 +735,7 @@ if (cmd->SCp.buffers_residual--) { cmd->SCp.buffer++; cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = cmd->SCp.buffer->address; + cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset; } } /* Now check to see if the drive is ready to comunicate */ @@ -792,6 +789,7 @@ { ppa_struct *tmp = (ppa_struct *) data; Scsi_Cmnd *cmd = tmp->cur_cmd; + struct Scsi_Host *host = cmd->host; unsigned long flags; if (!cmd) { @@ -843,11 +841,12 @@ if (cmd->SCp.phase > 0) ppa_pb_release(cmd->host->unique_id); + spin_lock_irqsave(host->host_lock, flags); tmp->cur_cmd = 0; - - spin_lock_irqsave(cmd->host->host_lock, flags); + cmd->scsi_done(cmd); - spin_unlock_irqrestore(cmd->host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); + return; } @@ -921,16 +920,16 @@ case 4: /* Phase 4 - Setup scatter/gather buffers */ if (cmd->use_sg) { /* if many buffers are available, start filling the first */ - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; + cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = cmd->SCp.buffer->address; + cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset; } else { /* else fill the only available buffer */ cmd->SCp.buffer = NULL; cmd->SCp.this_residual = cmd->request_bufflen; cmd->SCp.ptr = cmd->request_buffer; } - cmd->SCp.buffers_residual = cmd->use_sg; + cmd->SCp.buffers_residual = cmd->use_sg - 1; cmd->SCp.phase++; case 5: /* Phase 5 - Data transfer stage */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/qlogicfas.c linux-2.5/drivers/scsi/qlogicfas.c --- linux-2.5.5/drivers/scsi/qlogicfas.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/scsi/qlogicfas.c Fri Mar 1 15:07:38 2002 @@ -344,6 +344,7 @@ unsigned int reqlen; /* total length of transfer */ struct scatterlist *sglist; /* scatter-gather list pointer */ unsigned int sgcount; /* sg counter */ +char *buf; rtrc(1) j = inb(qbase + 6); @@ -391,7 +392,8 @@ REG0; return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); } - if (ql_pdma(phase, sglist->address, sglist->length)) + buf = page_address(sglist->page) + sglist->offset; + if (ql_pdma(phase, buf, sglist->length)) break; sglist++; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/scsi.c linux-2.5/drivers/scsi/scsi.c --- linux-2.5.5/drivers/scsi/scsi.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/scsi/scsi.c Mon Mar 4 00:00:02 2002 @@ -75,6 +75,8 @@ #include #endif +#undef USE_STATIC_SCSI_MEMORY + struct proc_dir_entry *proc_scsi; #ifdef CONFIG_PROC_FS @@ -158,6 +160,8 @@ "Enclosure ", }; +static char * scsi_null_device_strs = "nullnullnullnull"; + /* * Function prototypes. */ @@ -165,6 +169,11 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt); /* + * Private interface into the new error handling code. + */ +extern int scsi_new_reset(Scsi_Cmnd *SCpnt, unsigned int flag); + +/* * Function: scsi_initialize_queue() * * Purpose: Selects queue handler function for a device. @@ -1826,6 +1835,8 @@ HBA_ptr->host_queue = scd->next; } blk_cleanup_queue(&scd->request_queue); + if (scd->inquiry) + kfree(scd->inquiry); kfree((char *) scd); } else { goto out; @@ -2124,6 +2135,8 @@ blk_cleanup_queue(&SDpnt->request_queue); /* Next free up the Scsi_Device structures for this host */ shpnt->host_queue = SDpnt->next; + if (SDpnt->inquiry) + kfree(SDpnt->inquiry); kfree((char *) SDpnt); } @@ -2613,6 +2626,9 @@ return NULL; memset(SDpnt, 0, sizeof(Scsi_Device)); + SDpnt->vendor = scsi_null_device_strs; + SDpnt->model = scsi_null_device_strs; + SDpnt->rev = scsi_null_device_strs; SDpnt->host = SHpnt; SDpnt->id = SHpnt->this_id; @@ -2659,7 +2675,97 @@ * it now. */ scsi_release_commandblocks(SDpnt); + if (SDpnt->inquiry) + kfree(SDpnt->inquiry); kfree(SDpnt); +} + +/* + * Function: scsi_reset_provider_done_command + * + * Purpose: Dummy done routine. + * + * Notes: Some low level drivers will call scsi_done and end up here, + * others won't bother. + * We don't want the bogus command used for the bus/device + * reset to find its way into the mid-layer so we intercept + * it here. + */ +static void +scsi_reset_provider_done_command(Scsi_Cmnd *SCpnt) +{ +} + +/* + * Function: scsi_reset_provider + * + * Purpose: Send requested reset to a bus or device at any phase. + * + * Arguments: device - device to send reset to + * flag - reset type (see scsi.h) + * + * Returns: SUCCESS/FAILURE. + * + * Notes: This is used by the SCSI Generic driver to provide + * Bus/Device reset capability. + */ +int +scsi_reset_provider(Scsi_Device *dev, int flag) +{ + Scsi_Cmnd SC, *SCpnt = &SC; + int rtn; + + memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout)); + SCpnt->host = dev->host; + SCpnt->device = dev; + SCpnt->target = dev->id; + SCpnt->lun = dev->lun; + SCpnt->channel = dev->channel; + SCpnt->request.rq_status = RQ_SCSI_BUSY; + SCpnt->request.waiting = NULL; + SCpnt->use_sg = 0; + SCpnt->old_use_sg = 0; + SCpnt->old_cmd_len = 0; + SCpnt->underflow = 0; + SCpnt->transfersize = 0; + SCpnt->resid = 0; + SCpnt->serial_number = 0; + SCpnt->serial_number_at_timeout = 0; + SCpnt->host_scribble = NULL; + SCpnt->next = NULL; + SCpnt->state = SCSI_STATE_INITIALIZING; + SCpnt->owner = SCSI_OWNER_MIDLEVEL; + + memset(&SCpnt->cmnd, '\0', sizeof(SCpnt->cmnd)); + + SCpnt->scsi_done = scsi_reset_provider_done_command; + SCpnt->done = NULL; + SCpnt->reset_chain = NULL; + + SCpnt->buffer = NULL; + SCpnt->bufflen = 0; + SCpnt->request_buffer = NULL; + SCpnt->request_bufflen = 0; + + SCpnt->internal_timeout = NORMAL_TIMEOUT; + SCpnt->abort_reason = DID_ABORT; + + SCpnt->cmd_len = 0; + + SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN; + SCpnt->sc_request = NULL; + SCpnt->sc_magic = SCSI_CMND_MAGIC; + + /* + * Sometimes the command can get back into the timer chain, + * so use the pid as an identifier. + */ + SCpnt->pid = 0; + + rtn = scsi_new_reset(SCpnt, flag); + + scsi_delete_timer(SCpnt); + return rtn; } /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/scsi.h linux-2.5/drivers/scsi/scsi.h --- linux-2.5.5/drivers/scsi/scsi.h Thu Feb 21 17:47:03 2002 +++ linux-2.5/drivers/scsi/scsi.h Tue Mar 5 14:07:18 2002 @@ -575,7 +575,11 @@ devfs_handle_t de; /* directory for the device */ char type; char scsi_level; - char vendor[8], model[16], rev[4]; + unsigned char inquiry_len; /* valid bytes in 'inquiry' */ + unsigned char * inquiry; /* INQUIRY response data */ + char * vendor; /* [back_compat] point into 'inquiry' ... */ + char * model; /* ... after scan; point to static string */ + char * rev; /* ... "nullnullnullnull" before scan */ unsigned char current_tag; /* current tag */ unsigned char sync_min_period; /* Not less than this period */ unsigned char sync_max_offset; /* Not greater than this offset */ @@ -833,6 +837,16 @@ remove_wait_queue(QUEUE, &wait);\ current->state = TASK_RUNNING; \ }; } + +/* + * old style reset request from external source + * (private to sg.c and scsi_error.c, supplied by scsi_obsolete.c) + */ +#define SCSI_TRY_RESET_DEVICE 1 +#define SCSI_TRY_RESET_BUS 2 +#define SCSI_TRY_RESET_HOST 3 + +extern int scsi_reset_provider(Scsi_Device *, int); #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/scsi_debug.c linux-2.5/drivers/scsi/scsi_debug.c --- linux-2.5.5/drivers/scsi/scsi_debug.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/scsi/scsi_debug.c Sun Mar 3 20:37:43 2002 @@ -14,8 +14,8 @@ * * D. Gilbert (dpg) work for MOD device test [20010421] * dpg, work for devfs large number of disks [20010809] - * dpg, make more generic [20011123] * dpg, forked for lk 2.5 series [20011216, 20020101] + * dpg, use vmalloc() more inquiry+mode_sense [20020302] */ #include @@ -46,7 +46,7 @@ #include #endif -static char scsi_debug_version_str[] = "Version: 1.57 (20011216)"; +static char scsi_debug_version_str[] = "Version: 1.59 (20020302)"; #ifndef SCSI_CMD_READ_16 #define SCSI_CMD_READ_16 0x88 @@ -60,22 +60,26 @@ #define DEF_DEV_SIZE_MB 8 #define DEF_FAKE_BLK0 0 +#define DEF_OPTS 0 +#define SCSI_DEBUG_OPT_NOISE 1 +#define SCSI_DEBUG_OPT_MEDIUM_ERR 2 + +#define OPT_MEDIUM_ERR_ADDR 0x1234 + static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS; +static int scsi_debug_opts = DEF_OPTS; #define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1) #define N_HEAD 8 #define N_SECTOR 32 -#define DISK_READONLY(TGT) (0) -#define DISK_REMOVEABLE(TGT) (0) +#define DEV_READONLY(TGT) (0) +#define DEV_REMOVEABLE(TGT) (0) #define DEVICE_TYPE(TGT) (TYPE_DISK); #define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1) static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; #define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024) -#define STORE_ELEM_ORDER 1 -#define STORE_ELEM_SIZE (PAGE_SIZE * (1 << STORE_ELEM_ORDER)) -#define STORE_ELEMENTS ((STORE_SIZE / STORE_ELEM_SIZE) + 1) /* default sector size is 512 bytes, 2**9 bytes */ #define POW2_SECT_SIZE 9 @@ -83,34 +87,24 @@ #define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD)) -static int scsi_debug_fake_blk0 = DEF_FAKE_BLK0; - /* Do not attempt to use a timer to simulate a real disk with latency */ /* Only use this in the actual kernel, not in the simulator. */ #define IMMEDIATE -#define SDEBUG_SG_ADDRESS - #define START_PARTITION 4 /* Time to wait before completing a command */ #define DISK_SPEED (HZ/10) /* 100ms */ #define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER) #define SECT_SIZE_PER(TGT) SECT_SIZE -#define SECT_PER_ELEM (STORE_ELEM_SIZE / SECT_SIZE) static int starts[] = {N_SECTOR, N_HEAD * N_SECTOR, /* Single cylinder */ N_HEAD * N_SECTOR * 4, 0 /* CAPACITY */, 0}; -static int npart = 0; - -typedef struct scsi_debug_store_elem { - unsigned char * p; -} Sd_store_elem; -static Sd_store_elem * store_arr = 0; +static unsigned char * fake_storep; typedef struct sdebug_dev_info { Scsi_Device * sdp; @@ -135,13 +129,18 @@ static volatile done_fct_t * do_done = 0; -struct Scsi_Host * SHpnt = NULL; +static struct Scsi_Host * SHpnt = NULL; +static int scsi_debug_inquiry(unsigned char * cmd, int target, + unsigned char * buff, int bufflen, + Sdebug_dev_info * devip); +static int scsi_debug_mode_sense(unsigned char * cmd, int target, + unsigned char * buff, int bufflen, + Sdebug_dev_info * devip); static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, int * errstsp, Sdebug_dev_info * devip); static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, int * errstsp, Sdebug_dev_info * devip); -static void scsi_debug_send_self_command(struct Scsi_Host * shpnt); static void scsi_debug_intr_handle(unsigned long); static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp); static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, @@ -160,49 +159,23 @@ #define SENSE_BUFF_LEN 32 static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN]; -static int made_block0 = 0; -static void scsi_debug_mkblock0(unsigned char * buff, int bufflen, - Scsi_Cmnd * SCpnt) +static inline +unsigned char * sdebug_scatg2virt(const struct scatterlist * sclp) { - int i; - struct partition *p; - - memset(buff, 0, bufflen); - *((unsigned short *) (buff + 510)) = 0xAA55; - p = (struct partition *) (buff + 0x1be); - i = 0; - while (starts[i + 1]) { - int start_cyl, end_cyl; - - start_cyl = starts[i] / N_HEAD / N_SECTOR; - end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR; - p->boot_ind = 0; - - p->head = (i == 0 ? 1 : 0); - p->sector = 1 | ((start_cyl >> 8) << 6); - p->cyl = (start_cyl & 0xff); - - p->end_head = N_HEAD - 1; - p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6); - p->end_cyl = (end_cyl & 0xff); - - p->start_sect = starts[i]; - p->nr_sects = starts[i + 1] - starts[i]; - p->sys_ind = 0x83; /* Linux ext2 partition */ - p++; - i++; - } - if (!npart) - npart = i; - made_block0 = 1; - i = (bufflen > STORE_ELEM_SIZE) ? STORE_ELEM_SIZE : bufflen; - memcpy(store_arr[0].p, buff, i); + if (NULL == sclp) + return NULL; + else if (sclp->page) + return (unsigned char *)page_address(sclp->page) + + sclp->offset; + else + return NULL; } +static int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) { - unchar *cmd = (unchar *) SCpnt->cmnd; + unsigned char *cmd = (unsigned char *) SCpnt->cmnd; int block; int upper_blk; unsigned char *buff; @@ -214,6 +187,12 @@ Sdebug_dev_info * devip = NULL; char * sbuff; + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { + printk(KERN_INFO "scsi_debug: queue_command: cmd "); + for (i = 0, num = SCpnt->cmd_len; i < num; ++i) + printk("%02x ", cmd[i]); + printk(" use_sg=%d\n", SCpnt->use_sg); + } /* * If we are being notified of the mid-level reposessing a command * due to timeout, just return. @@ -222,14 +201,23 @@ return 0; } - buff = (unsigned char *) SCpnt->request_buffer; + if (SCpnt->use_sg) { /* just use first element */ + struct scatterlist *sgpnt = (struct scatterlist *) + SCpnt->request_buffer; + + buff = sdebug_scatg2virt(&sgpnt[0]); + bufflen = sgpnt[0].length; + /* READ and WRITE process scatterlist themselves */ + } + else + buff = (unsigned char *) SCpnt->request_buffer; /* * If a command comes for the ID of the host itself, just print * a silly message and return. */ if(target == 7) { - printk("How do you do!\n"); + printk(KERN_WARNING "How do you do!\n"); SCpnt->result = 0; done(SCpnt); return 0; @@ -243,7 +231,7 @@ #if 0 printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n", (int)SCpnt->device->host->host_no, (int)SCpnt->device->id, - SCpnt->device, (int)(unsigned char)*cmd); + SCpnt->device, (int)*cmd); #endif if (NULL == SCpnt->device->hostdata) { devip = devInfoReg(SCpnt->device); @@ -257,6 +245,13 @@ devip = SCpnt->device->hostdata; switch (*cmd) { + case INQUIRY: /* mandatory */ + scsi_debug_errsts = scsi_debug_inquiry(cmd, target, buff, + bufflen, devip); + /* assume INQUIRY called first so setup max_cmd_len */ + if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) + SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; + break; case REQUEST_SENSE: /* mandatory */ SCSI_LOG_LLQUEUE(3, printk("Request sense...\n")); if (devip) { @@ -294,23 +289,6 @@ } scsi_debug_errsts = 0; break; - case INQUIRY: /* mandatory */ - SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen)); - memset(buff, 0, bufflen); - buff[0] = DEVICE_TYPE(target); - buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0; - /* Removable disk */ - buff[2] = 2; /* claim SCSI 2 */ - buff[4] = 36 - 5; - memcpy(&buff[8], "Linux ", 8); - memcpy(&buff[16], "scsi_debug ", 16); - memcpy(&buff[32], "0002", 4); - scsi_debug_errsts = 0; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) - if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) - SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; -#endif - break; case SEND_DIAGNOSTIC: /* mandatory */ SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n")); if (buff) @@ -318,7 +296,8 @@ scsi_debug_errsts = 0; break; case TEST_UNIT_READY: /* mandatory */ - SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen)); + SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", + buff, bufflen)); if (buff) memset(buff, 0, bufflen); scsi_debug_errsts = 0; @@ -424,19 +403,15 @@ (done) (SCpnt); return 0; case MODE_SENSE: - /* - * Used to detect write protected status. - */ - scsi_debug_errsts = 0; - memset(buff, 0, 6); + case MODE_SENSE_10: + scsi_debug_errsts = + scsi_debug_mode_sense(cmd, target, buff, bufflen, devip); break; default: #if 0 - SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd)); - SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); - return 0; -#else + printk(KERN_INFO "scsi_debug: Unsupported command, " + "opcode=0x%x\n", (int)cmd[0]); +#endif if (check_reset(SCpnt, devip)) { done(SCpnt); return 0; @@ -445,7 +420,6 @@ (CHECK_CONDITION << 1); mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14); break; -#endif } spin_lock_irqsave(&mailbox_lock, iflags); @@ -485,10 +459,11 @@ spin_unlock_irqrestore(&mailbox_lock, iflags); add_timer(&timeout[i]); if (!done) - printk("scsi_debug_queuecommand: done can't be NULL\n"); + printk(KERN_ERR "scsi_debug_queuecommand: " + "done can't be NULL\n"); #if 0 - printk("Sending command (%d %x %d %d)...", i, done, + printk(KERN_INFO "Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies); #endif #endif @@ -496,6 +471,14 @@ return 0; } +static int scsi_debug_ioctl(Scsi_Device *dev, int cmd, void *arg) +{ + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { + printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd); + } + return -ENOTTY; +} + static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip) { if (devip->reset) { @@ -508,21 +491,188 @@ return 0; } -static inline -unsigned char * sdebug_scatg2virt(const struct scatterlist * sclp) -{ - if (NULL == sclp) - return NULL; - else if (sclp->page) - return (unsigned char *)page_address(sclp->page) + - sclp->offset; +#define SDEBUG_MAX_INQ_SZ 58 + +static int scsi_debug_inquiry(unsigned char * cmd, int target, + unsigned char * buff, int bufflen, + Sdebug_dev_info * devip) +{ + unsigned char pq_pdt; + unsigned char arr[SDEBUG_MAX_INQ_SZ]; + int min_len = bufflen > SDEBUG_MAX_INQ_SZ ? + SDEBUG_MAX_INQ_SZ : bufflen; + + SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen)); + if (bufflen < cmd[4]) + printk(KERN_INFO "scsi_debug: inquiry: bufflen=%d " + "< alloc_length=%d\n", bufflen, (int)cmd[4]); + memset(buff, 0, bufflen); + memset(arr, 0, SDEBUG_MAX_INQ_SZ); + pq_pdt = DEVICE_TYPE(target); + arr[0] = pq_pdt; + if (0x2 & cmd[1]) { /* CMDDT bit set */ + mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14); + return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + } + else if (0x1 & cmd[1]) { /* EVPD bit set */ + if (0 == cmd[2]) { /* supported vital product data pages */ + arr[3] = 1; + arr[4] = 0x80; /* ... only unit serial number */ + } + else if (0x80 == cmd[2]) { /* unit serial number */ + arr[1] = 0x80; + arr[3] = 4; + arr[4] = '1'; arr[5] = '2'; arr[6] = '3'; + arr[7] = '4'; + } + else { + /* Illegal request, invalid field in cdb */ + mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14); + return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + } + memcpy(buff, arr, min_len); + return 0; + } + /* drops through here for a standard inquiry */ + arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ + arr[2] = 3; /* claim SCSI 3 */ + arr[4] = SDEBUG_MAX_INQ_SZ - 5; + arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */ + memcpy(&arr[8], "Linux ", 8); + memcpy(&arr[16], "scsi_debug ", 16); + memcpy(&arr[32], "0003", 4); + memcpy(buff, arr, min_len); + return 0; +} + +/* <> */ + +static int sdebug_err_recov_pg(unsigned char * p, int pcontrol, int target) +{ /* Read-Write Error Recovery page for mode_sense */ + unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, + 5, 0, 0xff, 0xff}; + + memcpy(p, err_recov_pg, sizeof(err_recov_pg)); + if (1 == pcontrol) + memset(p + 2, 0, sizeof(err_recov_pg) - 2); + return sizeof(err_recov_pg); +} + +static int sdebug_disconnect_pg(unsigned char * p, int pcontrol, int target) +{ /* Disconnect-Reconnect page for mode_sense */ + unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0}; + + memcpy(p, disconnect_pg, sizeof(disconnect_pg)); + if (1 == pcontrol) + memset(p + 2, 0, sizeof(disconnect_pg) - 2); + return sizeof(disconnect_pg); +} + +static int sdebug_caching_pg(unsigned char * p, int pcontrol, int target) +{ /* Caching page for mode_sense */ + unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; + + memcpy(p, caching_pg, sizeof(caching_pg)); + if (1 == pcontrol) + memset(p + 2, 0, sizeof(caching_pg) - 2); + return sizeof(caching_pg); +} + +static int sdebug_ctrl_m_pg(unsigned char * p, int pcontrol, int target) +{ /* Control mode page for mode_sense */ + unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, + 0, 0, 0x2, 0x4b}; + + memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); + if (1 == pcontrol) + memset(p + 2, 0, sizeof(ctrl_m_pg) - 2); + return sizeof(ctrl_m_pg); +} + + +#define SDEBUG_MAX_MSENSE_SZ 256 + +static int scsi_debug_mode_sense(unsigned char * cmd, int target, + unsigned char * buff, int bufflen, + Sdebug_dev_info * devip) +{ + unsigned char dbd; + int pcontrol, pcode; + unsigned char dev_spec; + int alloc_len, msense_6, offset, len; + unsigned char * ap; + unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; + int min_len = bufflen > SDEBUG_MAX_MSENSE_SZ ? + SDEBUG_MAX_MSENSE_SZ : bufflen; + + SCSI_LOG_LLQUEUE(3, printk("Mode sense ...(%p %d)\n", buff, bufflen)); + dbd = cmd[1] & 0x8; + pcontrol = (cmd[2] & 0xc0) >> 6; + pcode = cmd[2] & 0x3f; + msense_6 = (MODE_SENSE == cmd[0]); + alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[6]); + /* printk(KERN_INFO "msense: dbd=%d pcontrol=%d pcode=%d " + "msense_6=%d alloc_len=%d\n", dbd, pcontrol, pcode, " + "msense_6, alloc_len); */ + if (bufflen < alloc_len) + printk(KERN_INFO "scsi_debug: mode_sense: bufflen=%d " + "< alloc_length=%d\n", bufflen, alloc_len); + memset(buff, 0, bufflen); + memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); + if (0x3 == pcontrol) { /* Saving values not supported */ + mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x39, 0, 14); + return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + } + dev_spec = DEV_READONLY(target) ? 0x80 : 0x0; + if (msense_6) { + arr[2] = dev_spec; + offset = 4; + } else { -#ifdef SDEBUG_SG_ADDRESS - return sclp->address; -#else - return NULL; -#endif + arr[3] = dev_spec; + offset = 8; + } + ap = arr + offset; + + switch (pcode) { + case 0x1: /* Read-Write error recovery page, direct access */ + len = sdebug_err_recov_pg(ap, pcontrol, target); + offset += len; + break; + case 0x2: /* Disconnect-Reconnect page, all devices */ + len = sdebug_disconnect_pg(ap, pcontrol, target); + offset += len; + break; + case 0x8: /* Caching page, direct access */ + len = sdebug_caching_pg(ap, pcontrol, target); + offset += len; + break; + case 0xa: /* Control Mode page, all devices */ + len = sdebug_ctrl_m_pg(ap, pcontrol, target); + offset += len; + break; + case 0x3f: /* Read all Mode pages */ + len = sdebug_err_recov_pg(ap, pcontrol, target); + len += sdebug_disconnect_pg(ap + len, pcontrol, target); + len += sdebug_caching_pg(ap + len, pcontrol, target); + len += sdebug_ctrl_m_pg(ap + len, pcontrol, target); + offset += len; + break; + default: + mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x24, 0, 14); + return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + } + if (msense_6) + arr[0] = offset - 1; + else { + offset -= 2; + arr[0] = (offset >> 8) & 0xff; + arr[1] = offset & 0xff; } + memcpy(buff, arr, min_len); + return 0; } static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, @@ -549,11 +699,19 @@ usleep(delay); } #endif - + if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && + (block >= OPT_MEDIUM_ERR_ADDR) && + (block < (OPT_MEDIUM_ERR_ADDR + num))) { + *errstsp = (COMMAND_COMPLETE << 8) | + (CHECK_CONDITION << 1); + mk_sense_buffer(devip, 1, MEDIUM_ERROR, 0x11, 0, 14); + /* claim unrecoverable read error */ + return 1; + } read_lock_irqsave(&sdebug_atomic_rw, iflags); sgcount = 0; nbytes = bufflen; - /* printk("scsi_debug_read: block=%d, tot_bufflen=%d\n", + /* printk(KERN_INFO "scsi_debug_read: block=%d, tot_bufflen=%d\n", block, bufflen); */ if (SCpnt->use_sg) { sgcount = 0; @@ -563,30 +721,7 @@ } *errstsp = 0; do { - int resid, k, off, len, rem, blk; - unsigned char * bp; - - /* If this is block 0, then we want to read the partition - * table for this device. Let's make one up */ - if (scsi_debug_fake_blk0 && (block == 0) && (! made_block0)) { - scsi_debug_mkblock0(buff, bufflen, SCpnt); - *errstsp = 0; - break; - } - bp = buff; - blk = block; - for (resid = bufflen; resid > 0; resid -= len) { - k = blk / SECT_PER_ELEM; - off = (blk % SECT_PER_ELEM) * SECT_SIZE; - rem = STORE_ELEM_SIZE - off; - len = (resid > rem) ? rem : resid; -/* printk("sdr: blk=%d k=%d off=%d rem=%d resid" - "=%d len=%d sgcount=%d\n", blk, k, - off, rem, resid, len, sgcount); */ - memcpy(bp, store_arr[k].p + off, len); - bp += len; - blk += len / SECT_SIZE; - } + memcpy(buff, fake_storep + (block * SECT_SIZE), bufflen); #if 0 /* Simulate a disk change */ if (block == 0xfff0) { @@ -612,7 +747,8 @@ } } else if (nbytes > 0) - printk("sdebug_read: unexpected nbytes=%d\n", nbytes); + printk(KERN_WARNING "sdebug_read: unexpected " + "nbytes=%d\n", nbytes); } while (nbytes); read_unlock_irqrestore(&sdebug_atomic_rw, iflags); return 0; @@ -645,20 +781,7 @@ } *errstsp = 0; do { - int resid, k, off, len, rem, blk; - unsigned char * bp; - - bp = buff; - blk = block; - for (resid = bufflen; resid > 0; resid -= len) { - k = blk / SECT_PER_ELEM; - off = (blk % SECT_PER_ELEM) * SECT_SIZE; - rem = STORE_ELEM_SIZE - off; - len = (resid > rem) ? rem : resid; - memcpy(store_arr[k].p + off, bp, len); - bp += len; - blk += len / SECT_SIZE; - } + memcpy(fake_storep + (block * SECT_SIZE), buff, bufflen); nbytes -= bufflen; if (SCpnt->use_sg) { @@ -670,52 +793,13 @@ } } else if (nbytes > 0) - printk("sdebug_write: unexpected nbytes=%d\n", nbytes); + printk(KERN_WARNING "sdebug_write: " + "unexpected nbytes=%d\n", nbytes); } while (nbytes); write_unlock_irqrestore(&sdebug_atomic_rw, iflags); return 0; } -static void scsi_debug_send_self_command(struct Scsi_Host * shpnt) -{ - static unsigned char cmd[6] = - {TEST_UNIT_READY, 0, 0, 0, 0, 0}; - - Scsi_Request * scp; - Scsi_Device * sdev; - - printk("Allocating host dev\n"); - sdev = scsi_get_host_dev(shpnt); - if(sdev==NULL) - { - printk("Out of memory.\n"); - return; - } - - printk("Got %p. Allocating command block\n", sdev); - scp = scsi_allocate_request(sdev); - printk("Got %p\n", scp); - - if(scp==NULL) - { - printk("Out of memory.\n"); - goto bail; - } - - scp->sr_cmd_len = 6; - scp->sr_use_sg = 0; - - printk("Sending command\n"); - scsi_wait_req (scp, (void *) cmd, (void *) NULL, - 0, 100, 3); - - printk("Releasing command\n"); - scsi_release_request(scp); -bail: - printk("Freeing device\n"); - scsi_free_host_dev(sdev); -} - /* A "high" level interrupt handler. This should be called once per jiffy * to simulate a regular scsi disk. We use a timer to do this. */ @@ -734,18 +818,19 @@ SCint[indx] = NULL; if (!my_done) { - printk("scsi_debug_intr_handle: Unexpected interrupt\n"); + printk(KERN_ERR "scsi_debug_intr_handle: Unexpected " + "interrupt\n"); return; } #if 0 - printk("In intr_handle..."); - printk("...done %d %x %d %d\n", i, my_done, to, jiffies); - printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done); + printk(KERN_INFO "In intr_handle..."); + printk(KERN_INFO "...done %d %x %d %d\n", i, my_done, to, jiffies); + printk(KERN_INFO "In intr_handle: %d %x %x\n", i, SCtmp, my_done); #endif my_done(SCtmp); #if 0 - printk("Called done.\n"); + printk(KERN_INFO "Called done.\n"); #endif } @@ -753,14 +838,13 @@ static int do_init(void) { - int sz; + int sz = STORE_SIZE; starts[3] = CAPACITY; - sz = sizeof(Sd_store_elem) * STORE_ELEMENTS; - store_arr = kmalloc(sz, GFP_ATOMIC); - if (NULL == store_arr) + fake_storep = vmalloc(sz); + if (NULL == fake_storep) return 1; - memset(store_arr, 0, sz); + memset(fake_storep, 0, sz); sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES; do_done = kmalloc(sz, GFP_ATOMIC); @@ -783,8 +867,8 @@ return 0; out: - if (store_arr) - kfree(store_arr); + if (fake_storep) + vfree(fake_storep); if (do_done) kfree((void *)do_done); if (timeout) @@ -799,34 +883,31 @@ kfree(SCint); kfree(timeout); kfree((void *)do_done); - kfree(store_arr); + vfree(fake_storep); } -int scsi_debug_detect(Scsi_Host_Template * tpnt) +static int scsi_debug_detect(Scsi_Host_Template * tpnt) { - int k, num, sz; + int k, sz; + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: detect\n"); if (0 == initialized) { ++initialized; sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs; devInfop = kmalloc(sz, GFP_ATOMIC); if (NULL == devInfop) { - printk("scsi_debug_detect: out of memory, 0.5\n"); + printk(KERN_ERR "scsi_debug_detect: out of " + "memory, 0.5\n"); return 0; } memset(devInfop, 0, sz); if (do_init()) { - printk("scsi_debug_detect: out of memory, 0\n"); + printk(KERN_ERR "scsi_debug_detect: out of memory" + ", 0\n"); return 0; } - for (k = 0; k < STORE_ELEMENTS; ++k) { - store_arr[k].p = (unsigned char *) - __get_free_pages(GFP_ATOMIC, STORE_ELEM_ORDER); - if (0 == store_arr[k].p) - goto detect_err; - memset(store_arr[k].p, 0, STORE_ELEM_SIZE); - } for (k = 0; k < NUM_SENSE_BUFFS; ++k) sense_buffers[k][0] = 0x70; for (k = 0; k < NR_HOSTS_PRESENT; k++) { @@ -836,43 +917,21 @@ return NR_HOSTS_PRESENT; } else { - printk("scsi_debug_detect: called again\n"); + printk(KERN_WARNING "scsi_debug_detect: called again\n"); return 0; } - -detect_err: - num = k; - for (k = 0; k < STORE_ELEMENTS; ++k) { - if (0 != store_arr[k].p) { - free_pages((unsigned long)store_arr[k].p, - STORE_ELEM_ORDER); - store_arr[k].p = NULL; - } - } - printk("scsi_debug_detect: out of memory: %d out of %d bytes\n", - (int)(num * STORE_ELEM_SIZE), - (int)(scsi_debug_dev_size_mb * 1024 * 1024)); - return 0; } static int num_releases = 0; -int scsi_debug_release(struct Scsi_Host * hpnt) +static int scsi_debug_release(struct Scsi_Host * hpnt) { - int k; - + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: release\n"); scsi_unregister(hpnt); if (++num_releases != NR_HOSTS_PRESENT) return 0; - - for (k = 0; k < STORE_ELEMENTS; ++k) { - if (0 != store_arr[k].p) { - free_pages((unsigned long)store_arr[k].p, - STORE_ELEM_ORDER); - store_arr[k].p = NULL; - } - } do_end(); kfree(devInfop); return 0; @@ -922,8 +981,10 @@ sbuff[13] = asq; } -int scsi_debug_abort(Scsi_Cmnd * SCpnt) +static int scsi_debug_abort(Scsi_Cmnd * SCpnt) { + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: abort\n"); #if 1 ++num_aborts; return SUCCESS; @@ -947,8 +1008,10 @@ #endif } -int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info) +static int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info) { + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: biosparam\n"); /* int size = disk->capacity; */ info[0] = N_HEAD; info[1] = N_SECTOR; @@ -958,36 +1021,13 @@ return 0; } -#if 0 -int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why) -{ - int i; - unsigned long iflags; - - void (*my_done) (Scsi_Cmnd *); - printk("Bus unlocked by reset - %d\n", why); - scsi_debug_lockup = 0; - for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) { - if (SCint[i] == NULL) - continue; - SCint[i]->result = DID_RESET << 16; - my_done = do_done[i]; - my_done(SCint[i]); - spin_lock_irqsave(&mailbox_lock, iflags); - SCint[i] = NULL; - do_done[i] = NULL; - timeout[i].function = NULL; - spin_unlock_irqrestore(&mailbox_lock, iflags); - } - return SCSI_RESET_SUCCESS; -} -#endif - -int scsi_debug_device_reset(Scsi_Cmnd * SCpnt) +static int scsi_debug_device_reset(Scsi_Cmnd * SCpnt) { Scsi_Device * sdp; int k; + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: device_reset\n"); ++num_dev_resets; if (SCpnt && ((sdp = SCpnt->device))) { for (k = 0; k < scsi_debug_num_devs; ++k) { @@ -1000,12 +1040,14 @@ return SUCCESS; } -int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt) +static int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt) { Scsi_Device * sdp; struct Scsi_Host * hp; int k; + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: bus_reset\n"); ++num_bus_resets; if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { for (k = 0; k < scsi_debug_num_devs; ++k) { @@ -1016,10 +1058,12 @@ return SUCCESS; } -int scsi_debug_host_reset(Scsi_Cmnd * SCpnt) +static int scsi_debug_host_reset(Scsi_Cmnd * SCpnt) { int k; + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: host_reset\n"); ++num_host_resets; for (k = 0; k < scsi_debug_num_devs; ++k) devInfop[k].reset = 1; @@ -1037,7 +1081,7 @@ scsi_debug_num_devs = tmp; return 1; } else { - printk("scsi_debug_num_devs: usage scsi_debug_num_devs= " + printk(KERN_INFO "scsi_debug_num_devs: usage scsi_debug_num_devs= " "( can be from 1 to around 2000)\n"); return 0; } @@ -1054,13 +1098,32 @@ scsi_debug_dev_size_mb = tmp; return 1; } else { - printk("scsi_debug_dev_size_mb: usage scsi_debug_dev_size_mb=\n" + printk(KERN_INFO "scsi_debug_dev_size_mb: usage " + "scsi_debug_dev_size_mb=\n" " ( is number of MB ram shared by all devs\n"); return 0; } } __setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup); + +static int __init scsi_debug_opts_setup(char *str) +{ + int tmp; + + if (get_option(&str, &tmp) == 1) { + if (tmp > 0) + scsi_debug_opts = tmp; + return 1; + } else { + printk(KERN_INFO "scsi_debug_opts: usage " + "scsi_debug_opts=\n" + " (1->noise, 2->medium_error, 4->... (can be or-ed)\n"); + return 0; + } +} + +__setup("scsi_debug_opts=", scsi_debug_opts_setup); #endif MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); @@ -1069,6 +1132,8 @@ MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate"); MODULE_PARM(scsi_debug_dev_size_mb, "i"); MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs"); +MODULE_PARM(scsi_debug_opts, "i"); +MODULE_PARM_DESC(scsi_debug_opts, "1->noise, 2->medium_error, 4->..."); #ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); @@ -1076,19 +1141,20 @@ static char sdebug_info[256]; -const char * scsi_debug_info(struct Scsi_Host * shp) +static const char * scsi_debug_info(struct Scsi_Host * shp) { sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, " - "dev_size_mb=%d\n", scsi_debug_version_str, - scsi_debug_num_devs, scsi_debug_dev_size_mb); + "dev_size_mb=%d, opts=0x%x", scsi_debug_version_str, + scsi_debug_num_devs, scsi_debug_dev_size_mb, + scsi_debug_opts); return sdebug_info; } /* scsi_debug_proc_info * Used if the driver currently has no own support for /proc/scsi */ -int scsi_debug_proc_info(char *buffer, char **start, off_t offset, - int length, int inode, int inout) +static int scsi_debug_proc_info(char *buffer, char **start, off_t offset, + int length, int inode, int inout) { int len, pos, begin; int orig_length; @@ -1096,55 +1162,28 @@ orig_length = length; if (inout == 1) { - /* First check for the Signature */ - if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) { - buffer += 11; - length -= 11; - - if (buffer[length - 1] == '\n') { - buffer[length - 1] = '\0'; - length--; - } - /* - * OK, we are getting some kind of command. Figure out - * what we are supposed to do here. Simulate bus lockups - * to test our reset capability. - */ - if (length == 4 && strncmp(buffer, "test", length) == 0) { - printk("Testing send self command %p\n", SHpnt); - scsi_debug_send_self_command(SHpnt); - return orig_length; - } - if (length == 6 && strncmp(buffer, "lockup", length) == 0) { - scsi_debug_lockup = 1; - return orig_length; - } - if (length == 6 && strncmp(buffer, "unlock", length) == 0) { - scsi_debug_lockup = 0; - return orig_length; - } - printk("Unknown command:%s (%d)\n", buffer, length); - } else - printk("Wrong Signature:%10s\n", (char *) buffer); - - return -EINVAL; + char arr[16]; + int minLen = length > 15 ? 15 : length; + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + memcpy(arr, buffer, minLen); + arr[minLen] = '\0'; + if (1 != sscanf(arr, "%d", &pos)) + return -EINVAL; + scsi_debug_opts = pos; + return length; } begin = 0; pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n" - "num_devs=%d, shared (ram) size=%d MB, sector_size=%d bytes\n" - "cylinders=%d, heads=%d, sectors=%d\n" + "num_devs=%d, shared (ram) size=%d MB, opts=0x%x\n" + "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" "number of aborts=%d, device_reset=%d, bus_resets=%d, " "host_resets=%d\n", scsi_debug_version_str, scsi_debug_num_devs, - scsi_debug_dev_size_mb, SECT_SIZE, + scsi_debug_dev_size_mb, scsi_debug_opts, SECT_SIZE, N_CYLINDER, N_HEAD, N_SECTOR, num_aborts, num_dev_resets, num_bus_resets, num_host_resets); -#if 0 - "This driver is not a real scsi driver, but it plays one on TV.\n" - "It is very handy for debugging specific problems because you\n" - "can simulate a variety of error conditions\n"); -#endif if (pos < offset) { len = 0; begin = pos; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/scsi_debug.h linux-2.5/drivers/scsi/scsi_debug.h --- linux-2.5.5/drivers/scsi/scsi_debug.h Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/scsi/scsi_debug.h Sun Mar 3 20:37:43 2002 @@ -3,16 +3,16 @@ #include #include -int scsi_debug_detect(Scsi_Host_Template *); -int scsi_debug_command(Scsi_Cmnd *); -int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); -int scsi_debug_abort(Scsi_Cmnd *); -int scsi_debug_biosparam(Disk *, kdev_t, int[]); -int scsi_debug_bus_reset(Scsi_Cmnd *); -int scsi_debug_dev_reset(Scsi_Cmnd *); -int scsi_debug_host_reset(Scsi_Cmnd *); -int scsi_debug_proc_info(char *, char **, off_t, int, int, int); -const char * scsi_debug_info(struct Scsi_Host *); +static int scsi_debug_detect(Scsi_Host_Template *); +/* static int scsi_debug_command(Scsi_Cmnd *); */ +static int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +static int scsi_debug_abort(Scsi_Cmnd *); +static int scsi_debug_biosparam(Disk *, kdev_t, int[]); +static int scsi_debug_bus_reset(Scsi_Cmnd *); +static int scsi_debug_device_reset(Scsi_Cmnd *); +static int scsi_debug_host_reset(Scsi_Cmnd *); +static int scsi_debug_proc_info(char *, char **, off_t, int, int, int); +static const char * scsi_debug_info(struct Scsi_Host *); #ifndef NULL #define NULL 0 @@ -31,6 +31,7 @@ info: scsi_debug_info, \ detect: scsi_debug_detect, \ release: scsi_debug_release, \ + ioctl: scsi_debug_ioctl, \ queuecommand: scsi_debug_queuecommand, \ eh_abort_handler: scsi_debug_abort, \ eh_bus_reset_handler: scsi_debug_bus_reset, \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/scsi_error.c linux-2.5/drivers/scsi/scsi_error.c --- linux-2.5.5/drivers/scsi/scsi_error.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/scsi/scsi_error.c Sun Mar 3 23:46:15 2002 @@ -979,15 +979,24 @@ case DID_SOFT_ERROR: goto maybe_retry; + case DID_ERROR: + if (msg_byte(SCpnt->result) == COMMAND_COMPLETE && + status_byte(SCpnt->result) == RESERVATION_CONFLICT) + /* + * execute reservation conflict processing code + * lower down + */ + break; + /* FALLTHROUGH */ + case DID_BUS_BUSY: case DID_PARITY: - case DID_ERROR: goto maybe_retry; case DID_TIME_OUT: /* - * When we scan the bus, we get timeout messages for - * these commands if there is no device available. - * Other hosts report DID_NO_CONNECT for the same thing. + * When we scan the bus, we get timeout messages for + * these commands if there is no device available. + * Other hosts report DID_NO_CONNECT for the same thing. */ if ((SCpnt->cmnd[0] == TEST_UNIT_READY || SCpnt->cmnd[0] == INQUIRY)) { @@ -1048,8 +1057,13 @@ */ return SUCCESS; case BUSY: - case RESERVATION_CONFLICT: goto maybe_retry; + + case RESERVATION_CONFLICT: + printk("scsi%d (%d,%d,%d) : RESERVATION CONFLICT\n", + SCpnt->host->host_no, SCpnt->channel, + SCpnt->device->id, SCpnt->device->lun); + return SUCCESS; /* causes immediate I/O error */ default: return FAILED; } @@ -1948,6 +1962,46 @@ if (host->eh_notify != NULL) up(host->eh_notify); } + +/* + * Function: scsi_new_reset + * + * Purpose: Send requested reset to a bus or device at any phase. + * + * Arguments: SCpnt - command ptr to send reset with (usually a dummy) + * flag - reset type (see scsi.h) + * + * Returns: SUCCESS/FAILURE. + * + * Notes: This is used by the SCSI Generic driver to provide + * Bus/Device reset capability. + */ +int +scsi_new_reset(Scsi_Cmnd *SCpnt, int flag) +{ + int rtn; + + switch(flag) { + case SCSI_TRY_RESET_DEVICE: + rtn = scsi_try_bus_device_reset(SCpnt, 0); + if (rtn == SUCCESS) + break; + /* FALLTHROUGH */ + case SCSI_TRY_RESET_BUS: + rtn = scsi_try_bus_reset(SCpnt); + if (rtn == SUCCESS) + break; + /* FALLTHROUGH */ + case SCSI_TRY_RESET_HOST: + rtn = scsi_try_host_reset(SCpnt); + break; + default: + rtn = FAILED; + } + + return rtn; +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/scsi_merge.c linux-2.5/drivers/scsi/scsi_merge.c --- linux-2.5.5/drivers/scsi/scsi_merge.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/scsi/scsi_merge.c Thu Feb 21 02:49:28 2002 @@ -136,7 +136,7 @@ * hardware have no practical limit. */ bounce_limit = BLK_BOUNCE_ANY; - else + else if (SHpnt->pci_dev) bounce_limit = SHpnt->pci_dev->dma_mask; } else if (SHpnt->unchecked_isa_dma) bounce_limit = BLK_BOUNCE_ISA; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/scsi_scan.c linux-2.5/drivers/scsi/scsi_scan.c --- linux-2.5.5/drivers/scsi/scsi_scan.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/scsi/scsi_scan.c Mon Mar 4 00:00:02 2002 @@ -22,27 +22,36 @@ #include #endif -/* The following devices are known not to tolerate a lun != 0 scan for - * one reason or another. Some will respond to all luns, others will - * lock up. +/* + * Flags for irregular SCSI devices that need special treatment */ +#define BLIST_NOLUN 0x001 /* Don't scan for LUNs */ +#define BLIST_FORCELUN 0x002 /* Known to have LUNs, force sanning */ +#define BLIST_BORKEN 0x004 /* Flag for broken handshaking */ +#define BLIST_KEY 0x008 /* Needs to be unlocked by special command */ +#define BLIST_SINGLELUN 0x010 /* LUNs should better not be used in parallel */ +#define BLIST_NOTQ 0x020 /* Buggy Tagged Command Queuing */ +#define BLIST_SPARSELUN 0x040 /* Non consecutive LUN numbering */ +#define BLIST_MAX5LUN 0x080 /* Avoid LUNS >= 5 */ +#define BLIST_ISDISK 0x100 /* Treat as (removable) disk */ +#define BLIST_ISROM 0x200 /* Treat as (removable) CD-ROM */ +#define BLIST_LARGELUN 0x400 /* LUNs larger than 7 despite reporting as SCSI 2 */ +#define BLIST_INQUIRY_36 0x800 /* override additional length field */ +#define BLIST_INQUIRY_58 0x1000 /* ... for broken inquiry responses */ -#define BLIST_NOLUN 0x001 -#define BLIST_FORCELUN 0x002 -#define BLIST_BORKEN 0x004 -#define BLIST_KEY 0x008 -#define BLIST_SINGLELUN 0x010 -#define BLIST_NOTQ 0x020 -#define BLIST_SPARSELUN 0x040 -#define BLIST_MAX5LUN 0x080 -#define BLIST_ISDISK 0x100 -#define BLIST_ISROM 0x200 +/* + * scan_scsis_single() return values. + */ +#define SCSI_SCAN_NO_RESPONSE 0 +#define SCSI_SCAN_DEVICE_PRESENT 1 +#define SCSI_SCAN_DEVICE_ADDED 2 static void print_inquiry(unsigned char *data); static int scan_scsis_single(unsigned int channel, unsigned int dev, - unsigned int lun, int lun0_scsi_level, - unsigned int *max_scsi_dev, unsigned int *sparse_lun, - Scsi_Device ** SDpnt, struct Scsi_Host *shpnt, + unsigned int lun, int scsi_level, Scsi_Device ** SDpnt2, + struct Scsi_Host *shpnt, char *scsi_result); +static void scan_scsis_target(unsigned int channel, unsigned int dev, + Scsi_Device ** SDpnt2, struct Scsi_Host *shpnt, char *scsi_result); static int find_lun0_scsi_level(unsigned int channel, unsigned int dev, struct Scsi_Host *shpnt); @@ -61,6 +70,10 @@ */ static struct dev_info device_list[] = { +/* The following devices are known not to tolerate a lun != 0 scan for + * one reason or another. Some will respond to all luns, others will + * lock up. + */ {"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ @@ -74,7 +87,6 @@ {"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN}, /* Locks-up sometimes when LUN>0 polled. */ {"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN}, /* guess what? */ {"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN}, /*Responds to all lun */ - {"MICROP", "4110", "*", BLIST_NOTQ}, /* Buggy Tagged Queuing */ {"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ {"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN}, /* Responds to all lun */ {"RODIME", "RO3000S", "2.33", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ @@ -125,6 +137,7 @@ {"INSITE", "Floptical F*8I", "*", BLIST_KEY}, {"INSITE", "I325VM", "*", BLIST_KEY}, {"LASOUND","CDX7405","3.10", BLIST_MAX5LUN | BLIST_SINGLELUN}, + {"MICROP", "4110", "*", BLIST_NOTQ}, /* Buggy Tagged Queuing */ {"NRC", "MBR-7", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"NRC", "MBR-7.4", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"REGAL", "CDC-4X", "*", BLIST_MAX5LUN | BLIST_SINGLELUN}, @@ -151,7 +164,7 @@ {"DELL", "PV660F PSEUDO", "*", BLIST_SPARSELUN}, {"DELL", "PSEUDO DEVICE .", "*", BLIST_SPARSELUN}, // Dell PV 530F {"DELL", "PV530F", "*", BLIST_SPARSELUN}, // Dell PV 530F - {"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN}, + {"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"CMD", "CRA-7280", "*", BLIST_SPARSELUN}, // CMD RAID Controller {"CNSI", "G7324", "*", BLIST_SPARSELUN}, // Chaparral G7324 RAID {"CNSi", "G8324", "*", BLIST_SPARSELUN}, // Chaparral G8324 RAID @@ -162,6 +175,7 @@ {"HP", "NetRAID-4M", "*", BLIST_FORCELUN}, {"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN}, {"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN}, + {"COMPAQ", "MSA1000", "*", BLIST_FORCELUN}, /* * Must be at end of list... @@ -169,6 +183,8 @@ {NULL, NULL, NULL} }; +static char * scsi_null_device_strs = "nullnullnullnull"; + #define MAX_SCSI_LUNS 0xFFFFFFFF #ifdef CONFIG_SCSI_MULTI_LUN @@ -177,11 +193,27 @@ static unsigned int max_scsi_luns = 1; #endif +#ifdef CONFIG_SCSI_REPORT_LUNS +/* + * max_scsi_report_luns: the maximum number of LUNS that will be + * returned from the REPORT LUNS command. 8 times this value must + * be allocated. In theory this could be up to an 8 byte value, but + * in practice, the maximum number of LUNs suppored by any device + * is about 16k. + */ +static unsigned int max_scsi_report_luns = 128; +#endif + #ifdef MODULE MODULE_PARM(max_scsi_luns, "i"); MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)"); +#ifdef CONFIG_SCSI_REPORT_LUNS +MODULE_PARM(max_scsi_report_luns, "i"); +MODULE_PARM_DESC(max_scsi_report_luns, "REPORT LUNS maximum number of LUNS received (should be between 1 and 16384)"); +#endif + #else static int __init scsi_luns_setup(char *str) @@ -200,6 +232,59 @@ __setup("max_scsi_luns=", scsi_luns_setup); +#ifdef CONFIG_SCSI_REPORT_LUNS +static int __init max_scsi_report_luns_setup(char *str) +{ + unsigned int tmp; + + if (get_option(&str, &tmp) == 1) { + max_scsi_report_luns = tmp; + return 1; + } else { + printk("scsi_report_luns_setup : usage max_scsi_report_luns=n " + "(n should be between 1 and 16384)\n"); + return 0; + } +} + +__setup("max_scsi_report_luns=", max_scsi_report_luns_setup); +#endif /* CONFIG_SCSI_REPORT_LUNS */ + +#endif + +#ifdef CONFIG_SCSI_REPORT_LUNS +/* + * Function: scsilun_to_int + * + * Purpose: Convert ScsiLun (8 byte LUN) to an int. + * + * Arguments: scsilun_pnt - pointer to a ScsiLun to be converted + * + * Lock status: None + * + * Returns: cpu ordered integer containing the truncated LUN value + * + * Notes: The ScsiLun is assumed to be four levels, with each level + * effectively containing a SCSI byte-ordered (big endidan) + * short; the addressing bits of each level are ignored (the + * highest two bits). For a description of the LUN format, post + * SCSI-3 see the SCSI Architecture Model, for SCSI-3 see the + * SCSI Controller Commands. + * + * Given a ScsiLun of: 0a 04 0b 03 00 00 00 00, this function + * returns the integer: 0x0b030a04 + */ +static int scsilun_to_int(ScsiLun *scsilun_pnt) +{ + int i; + unsigned int lun; + + lun = 0; + for (i = 0; i < sizeof(lun); i += 2) + lun = lun | (((scsilun_pnt->scsi_lun[i] << 8) | + scsilun_pnt->scsi_lun[i + 1]) << (i * 8)); + return lun; +} #endif static void print_inquiry(unsigned char *data) @@ -243,23 +328,20 @@ printk("\n"); } -static int get_device_flags(unsigned char *response_data) +static int get_device_flags(unsigned char *vendor_pnt, unsigned char *model_pnt) { int i = 0; - unsigned char *pnt; for (i = 0; 1; i++) { if (device_list[i].vendor == NULL) return 0; - pnt = &response_data[8]; - while (*pnt && *pnt == ' ') - pnt++; - if (memcmp(device_list[i].vendor, pnt, + while (*vendor_pnt && *vendor_pnt == ' ') + vendor_pnt++; + if (memcmp(device_list[i].vendor, vendor_pnt, strlen(device_list[i].vendor))) continue; - pnt = &response_data[16]; - while (*pnt && *pnt == ' ') - pnt++; - if (memcmp(device_list[i].model, pnt, + while (*model_pnt && *model_pnt == ' ') + model_pnt++; + if (memcmp(device_list[i].model, model_pnt, strlen(device_list[i].model))) continue; return device_list[i].flags; @@ -283,13 +365,10 @@ uint channel; unsigned int dev; unsigned int lun; - unsigned int max_dev_lun; unsigned char *scsi_result; unsigned char scsi_result0[256]; Scsi_Device *SDpnt; Scsi_Device *SDtail; - unsigned int sparse_lun; - int lun0_sl; scsi_result = NULL; @@ -297,6 +376,9 @@ GFP_ATOMIC); if (SDpnt) { memset(SDpnt, 0, sizeof(Scsi_Device)); + SDpnt->vendor = scsi_null_device_strs; + SDpnt->model = scsi_null_device_strs; + SDpnt->rev = scsi_null_device_strs; /* * Register the queue for the device. All I/O requests will * come in through here. We also need to register a pointer to @@ -352,6 +434,8 @@ if (hardcoded == 1) { Scsi_Device *oldSDpnt = SDpnt; struct Scsi_Device_Template *sdtpnt; + unsigned int lun0_sl; + channel = hchannel; if (channel > shpnt->max_channel) goto leave; @@ -365,8 +449,8 @@ lun0_sl = SCSI_3; /* actually don't care for 0 == lun */ else lun0_sl = find_lun0_scsi_level(channel, dev, shpnt); - scan_scsis_single(channel, dev, lun, lun0_sl, &max_dev_lun, - &sparse_lun, &SDpnt, shpnt, scsi_result); + scan_scsis_single(channel, dev, lun, lun0_sl, &SDpnt, shpnt, + scsi_result); if (SDpnt != oldSDpnt) { /* it could happen the blockdevice hasn't yet been inited */ @@ -411,31 +495,11 @@ order_dev = dev; if (shpnt->this_id != order_dev) { - - /* - * We need the for so our continue, etc. work fine. We put this in - * a variable so that we can override it during the scan if we - * detect a device *KNOWN* to have multiple logical units. - */ - max_dev_lun = (max_scsi_luns < shpnt->max_lun ? - max_scsi_luns : shpnt->max_lun); - sparse_lun = 0; - for (lun = 0, lun0_sl = SCSI_2; lun < max_dev_lun; ++lun) { - /* don't probe further for luns > 7 for targets <= SCSI_2 */ - if ((lun0_sl < SCSI_3) && (lun > 7)) - break; - - if (!scan_scsis_single(channel, order_dev, lun, lun0_sl, - &max_dev_lun, &sparse_lun, &SDpnt, shpnt, - scsi_result) - && !sparse_lun) - break; /* break means don't probe further for luns!=0 */ - if (SDpnt && (0 == lun)) - lun0_sl = SDpnt->scsi_level; - } /* for lun ends */ - } /* if this_id != id ends */ - } /* for dev ends */ - } /* for channel ends */ + scan_scsis_target(channel, order_dev, + &SDpnt, shpnt, scsi_result); + } + } + } } /* if/else hardcoded */ leave: @@ -461,6 +525,8 @@ /* Last device block does not exist. Free memory. */ if (SDpnt != NULL) { blk_cleanup_queue(&SDpnt->request_queue); + if (SDpnt->inquiry) + kfree(SDpnt->inquiry); kfree((char *) SDpnt); } @@ -483,15 +549,38 @@ } /* - * The worker for scan_scsis. - * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on. - * Global variables used : scsi_devices(linked list) + * Function: scan_scsis_single + * + * Purpose: Determine if a SCSI device (a single LUN) exists, and + * configure it into the system. + * + * Arguments: channel - the host's channel + * dev - target dev (target id) + * lun - LUN + * scsi_level - SCSI 1, 2 or 3 + * SDpnt2 - pointer to pointer of a preallocated Scsi_Device + * shpnt - host device to use + * scsi_result - preallocated buffer for the SCSI command result + * + * Lock status: None + * + * Returns: SCSI_SCAN_NO_RESPONSE - no valid response received from the + * device, this includes allocation failures preventing IO from + * being sent, or any general failures. + * + * SCSI_SCAN_DEVICE_PRESENT - device responded, SDpnt2 has all + * values needed to send IO set, plus scsi_level is set, but no + * new Scsi_Device was added/allocated. + * + * SCSI_SCAN_DEVICE_ADDED - device responded, and added to list; + * SDpnt2 filled, and pointed to new allocated Scsi_Device. + * + * Notes: This could be cleaned up more by moving SDpnt2 and Scsi_Device + * allocation into scan_scsis_target. */ static int scan_scsis_single(unsigned int channel, unsigned int dev, - unsigned int lun, int lun0_scsi_level, - unsigned int *max_dev_lun, unsigned int *sparse_lun, - Scsi_Device ** SDpnt2, struct Scsi_Host *shpnt, - char *scsi_result) + unsigned int lun, int scsi_level, Scsi_Device ** SDpnt2, + struct Scsi_Host *shpnt, char *scsi_result) { char devname[64]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; @@ -499,7 +588,9 @@ Scsi_Device *SDtail, *SDpnt = *SDpnt2; Scsi_Request * SRpnt; int bflags, type = -1; + int possible_inq_resp_len; extern devfs_handle_t scsi_devfs_handle; + int scsi_level; SDpnt->host = shpnt; SDpnt->id = dev; @@ -523,7 +614,8 @@ if (NULL == (SRpnt = scsi_allocate_request(SDpnt))) { printk("scan_scsis_single: no memory\n"); - return 0; + scsi_release_commandblocks(SDpnt); + return SCSI_SCAN_NO_RESPONSE; } /* @@ -532,25 +624,26 @@ * devices (and TEST_UNIT_READY to poll for media change). - Paul G. */ - SCSI_LOG_SCAN_BUS(3, printk("scsi: performing INQUIRY\n")); + SCSI_LOG_SCAN_BUS(3, + printk("scsi scan: INQUIRY to host %d channel %d id %d lun %d\n", + shpnt->host_no, channel, dev, lun) + ); + /* * Build an INQUIRY command block. */ + memset(scsi_cmd, 0, 6); scsi_cmd[0] = INQUIRY; - if ((lun > 0) && (lun0_scsi_level <= SCSI_2)) + if ((lun > 0) && (scsi_level <= SCSI_2)) scsi_cmd[1] = (lun << 5) & 0xe0; - else - scsi_cmd[1] = 0; /* SCSI_3 and higher, don't touch */ - scsi_cmd[2] = 0; - scsi_cmd[3] = 0; - scsi_cmd[4] = 255; - scsi_cmd[5] = 0; + scsi_cmd[4] = 36; /* issue conservative alloc_length */ SRpnt->sr_cmd_len = 0; SRpnt->sr_data_direction = SCSI_DATA_READ; + memset(scsi_result, 0, 36); scsi_wait_req (SRpnt, (void *) scsi_cmd, (void *) scsi_result, - 256, SCSI_TIMEOUT+4*HZ, 3); + 36, SCSI_TIMEOUT+4*HZ, 3); SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n", SRpnt->sr_result ? "failed" : "successful", SRpnt->sr_result)); @@ -565,6 +658,7 @@ SRpnt->sr_sense_buffer[12] == 0x28 && SRpnt->sr_sense_buffer[13] == 0) { /* not-ready to ready transition - good */ + /* dpg: bogus? INQUIRY never returns UNIT_ATTENTION */ } else { /* assume no peripheral if any other sort of error */ scsi_release_request(SRpnt); @@ -573,25 +667,63 @@ } /* - * Check for SPARSELUN before checking the peripheral qualifier, - * so sparse lun devices are completely scanned. - */ - - /* * Get any flags for this device. */ - bflags = get_device_flags (scsi_result); + bflags = get_device_flags (&scsi_result[8], &scsi_result[16]); - if (bflags & BLIST_SPARSELUN) { - *sparse_lun = 1; + possible_inq_resp_len = (unsigned char)scsi_result[4] + 5; + if (BLIST_INQUIRY_36 & bflags) + possible_inq_resp_len = 36; + else if (BLIST_INQUIRY_58 & bflags) + possible_inq_resp_len = 58; + else if (possible_inq_resp_len > 255) + possible_inq_resp_len = 36; /* sanity */ + + if (possible_inq_resp_len > 36) { /* do additional INQUIRY */ + memset(scsi_cmd, 0, 6); + scsi_cmd[0] = INQUIRY; + if ((lun > 0) && (scsi_level <= SCSI_2)) + scsi_cmd[1] = (lun << 5) & 0xe0; + scsi_cmd[4] = (unsigned char)possible_inq_resp_len; + SRpnt->sr_cmd_len = 0; + SRpnt->sr_data_direction = SCSI_DATA_READ; + + scsi_wait_req (SRpnt, (void *) scsi_cmd, + (void *) scsi_result, + 256, SCSI_TIMEOUT+4*HZ, 3); + /* assume successful */ + } + SDpnt->inquiry_len = possible_inq_resp_len; + SDpnt->inquiry = kmalloc(possible_inq_resp_len, GFP_ATOMIC); + if (NULL == SDpnt->inquiry) { + scsi_release_commandblocks(SDpnt); + scsi_release_request(SRpnt); + return SCSI_SCAN_NO_RESPONSE; } + memcpy(SDpnt->inquiry, scsi_result, possible_inq_resp_len); + SDpnt->vendor = (char *)(SDpnt->inquiry + 8); + SDpnt->model = (char *)(SDpnt->inquiry + 16); + SDpnt->rev = (char *)(SDpnt->inquiry + 32); + + SDpnt->scsi_level = scsi_result[2] & 0x07; + if (SDpnt->scsi_level >= 2 || + (SDpnt->scsi_level == 1 && + (scsi_result[3] & 0x0f) == 1)) + SDpnt->scsi_level++; + /* * Check the peripheral qualifier field - this tells us whether LUNS * are supported here or not. */ if ((scsi_result[0] >> 5) == 3) { - scsi_release_request(SRpnt); - return 0; /* assume no peripheral if any sort of error */ + /* + * Peripheral qualifier 3 (011b): The device server is not + * capable of supporting a physical device on this logical + * unit. + */ + scsi_release_commandblocks(SDpnt); + scsi_release_request(SRpnt); + return SCSI_SCAN_DEVICE_PRESENT; } /* The Toshiba ROM was "gender-changed" here as an inline hack. This is now much more generic. @@ -609,9 +741,6 @@ scsi_result[1] |= 0x80; /* removable */ } - memcpy(SDpnt->vendor, scsi_result + 8, 8); - memcpy(SDpnt->model, scsi_result + 16, 16); - memcpy(SDpnt->rev, scsi_result + 32, 4); SDpnt->removable = (0x80 & scsi_result[1]) >> 7; /* Use the peripheral qualifier field to determine online/offline */ @@ -630,6 +759,7 @@ switch (type = (scsi_result[0] & 0x1f)) { case TYPE_TAPE: case TYPE_DISK: + case TYPE_PRINTER: case TYPE_MOD: case TYPE_PROCESSOR: case TYPE_SCANNER: @@ -667,12 +797,6 @@ SDpnt->attached += (*sdtpnt->detect) (SDpnt); - SDpnt->scsi_level = scsi_result[2] & 0x07; - if (SDpnt->scsi_level >= 2 || - (SDpnt->scsi_level == 1 && - (scsi_result[3] & 0x0f) == 1)) - SDpnt->scsi_level++; - /* * Accommodate drivers that want to sleep when they should be in a polling * loop. @@ -726,6 +850,9 @@ scsi_wait_req (SRpnt, (void *) scsi_cmd, (void *) scsi_result, 0x2a, SCSI_TIMEOUT, 3); + /* + * scsi_result no longer holds inquiry data. + */ } scsi_release_request(SRpnt); @@ -741,14 +868,18 @@ SDpnt = (Scsi_Device *) kmalloc(sizeof(Scsi_Device), GFP_ATOMIC); if (!SDpnt) { printk("scsi: scan_scsis_single: Cannot malloc\n"); - return 0; + return SCSI_SCAN_NO_RESPONSE; } memset(SDpnt, 0, sizeof(Scsi_Device)); + SDpnt->vendor = scsi_null_device_strs; + SDpnt->model = scsi_null_device_strs; + SDpnt->rev = scsi_null_device_strs; *SDpnt2 = SDpnt; SDpnt->queue_depth = 1; SDpnt->host = shpnt; SDpnt->online = TRUE; + SDpnt->scsi_level = scsi_level; /* * Register the queue for the device. All I/O requests will come @@ -788,62 +919,375 @@ SDpnt->prev = SDtail; SDpnt->next = NULL; + return SCSI_SCAN_DEVICE_ADDED; +} + +/* + * Function: scsi_report_lun_scan + * + * Purpose: Use a SCSI REPORT LUN to determine what LUNs to scan. + * + * Arguments: SDlun0_pnt - pointer to a Scsi_Device for LUN 0 + * channel - the host's channel + * dev - target dev (target id) + * SDpnt2 - pointer to pointer of a preallocated Scsi_Device + * shpnt - host device to use + * scsi_result - preallocated buffer for the SCSI command result + * + * Lock status: None + * + * Returns: If the LUNs for device at shpnt/channel/dev are scanned, + * return 0, else return 1. + * + * Notes: This code copies and truncates the 8 byte LUN into the + * current 4 byte (int) lun. + */ +static int scsi_report_lun_scan(Scsi_Device *SDlun0_pnt, unsigned + int channel, unsigned int dev, Scsi_Device **SDpnt2, + struct Scsi_Host *shpnt, char *scsi_result) +{ +#ifdef CONFIG_SCSI_REPORT_LUNS + + char devname[64]; + unsigned char scsi_cmd[MAX_COMMAND_SIZE]; + unsigned int length; + unsigned int lun; + unsigned int num_luns; + unsigned int retries; + ScsiLun *fcp_cur_lun_pnt, *lun_data_pnt; + Scsi_Request *SRpnt; + int scsi_level; + char *byte_pnt; + int got_command_blocks = 0; + /* - * Some scsi devices cannot be polled for lun != 0 due to firmware bugs + * Only support SCSI-3 and up devices. */ - if (bflags & BLIST_NOLUN) - return 0; /* break; */ + if (SDlun0_pnt->scsi_level < SCSI_3) + return 1; /* - * If this device is known to support sparse multiple units, override the - * other settings, and scan all of them. + * Note SDlun0_pnt might be invalid after scan_scsis_single is called. */ - if (bflags & BLIST_SPARSELUN) { - *max_dev_lun = shpnt->max_lun; - *sparse_lun = 1; - return 1; - } + /* - * If this device is known to support multiple units, override the other - * settings, and scan all of them. + * Command blocks might be built depending on whether LUN 0 was + * configured or not. Checking has_cmdblocks here is ugly. */ - if (bflags & BLIST_FORCELUN) { - /* - * Scanning MAX_SCSI_LUNS units would be a bad idea. - * Any better idea? - * I think we need REPORT LUNS in future to avoid scanning - * of unused LUNs. But, that is another item. - */ - if (*max_dev_lun < shpnt->max_lun) - *max_dev_lun = shpnt->max_lun; - else if ((max_scsi_luns >> 1) >= *max_dev_lun) - *max_dev_lun += shpnt->max_lun; - else *max_dev_lun = max_scsi_luns; + if (SDlun0_pnt->has_cmdblocks == 0) { + got_command_blocks = 1; + scsi_build_commandblocks(SDlun0_pnt); + } + SRpnt = scsi_allocate_request(SDlun0_pnt); + + sprintf (devname, "host %d channel %d id %d", + SDlun0_pnt->host->host_no, SDlun0_pnt->channel, + SDlun0_pnt->id); + /* + * Allocate enough to hold the header (the same size as one ScsiLun) + * plus the max number of luns we are requesting. + * + * XXX: Maybe allocate this once, like scsi_result, and pass it down. + * scsi_result can't be used, as it is needed for the scan INQUIRY + * data. In addition, reallocating and trying again (with the exact + * amount we need) would be nice, but then we need to somehow limit the + * size allocated based on the available memory (and limits of kmalloc). + */ + length = (max_scsi_report_luns + 1) * sizeof(ScsiLun); + lun_data_pnt = (ScsiLun *) kmalloc(length, + (shpnt->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC)); + if (lun_data_pnt == NULL) { + printk("scsi: scsi_report_lun_scan: Cannot malloc\n"); + if (got_command_blocks) + scsi_release_commandblocks(SDlun0_pnt); return 1; } + + scsi_cmd[0] = REPORT_LUNS; /* - * REGAL CDC-4X: avoid hang after LUN 4 + * bytes 1 - 5: reserved, set to zero. */ - if (bflags & BLIST_MAX5LUN) { - *max_dev_lun = 5; + memset(&scsi_cmd[1], 0, 5); + /* + * bytes 6 - 9: length of the command. + */ + scsi_cmd[6] = (unsigned char) (length >> 24) & 0xff; + scsi_cmd[7] = (unsigned char) (length >> 16) & 0xff; + scsi_cmd[8] = (unsigned char) (length >> 8) & 0xff; + scsi_cmd[9] = (unsigned char) length & 0xff; + + scsi_cmd[10] = 0; /* reserved */ + scsi_cmd[11] = 0; /* control */ + SRpnt->sr_cmd_len = 0; + SRpnt->sr_data_direction = SCSI_DATA_READ; + + /* + * We can get a UNIT ATTENTION, for example a power on/reset, so retry + * a few times (like sd.c does for TEST UNIT READY). Experience shows + * some combinations of adapter/devices get at least two power + * on/resets. + * + * Illegal requests (for devices that do not support REPORT LUNS) + * should come through as a check condition, and will not generate a + * retry. + */ + retries = 0; + while (retries++ < 3) { + SCSI_LOG_SCAN_BUS(3, + printk("scsi: Sending REPORT LUNS to %s (try %d)\n", + devname, retries)); + + scsi_wait_req (SRpnt, (void *) scsi_cmd, (void *) lun_data_pnt, + length, SCSI_TIMEOUT+4*HZ, 3); + + SCSI_LOG_SCAN_BUS(3, + printk("scsi: REPORT LUNS %s (try %d) result 0x%x\n", + SRpnt->sr_result ? "failed" : "successful", retries, + SRpnt->sr_result)); + + if (SRpnt->sr_result == 0 + || SRpnt->sr_sense_buffer[2] != UNIT_ATTENTION) + break; + } + + scsi_release_request(SRpnt); + if (got_command_blocks) + scsi_release_commandblocks(SDlun0_pnt); + + if (SRpnt->sr_result) { + kfree((char *) lun_data_pnt); return 1; } /* - * We assume the device can't handle lun!=0 if: - it reports scsi-0 - * (ANSI SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it - * reports scsi-1 (ANSI SCSI Revision 1) and Response Data Format 0 - */ - if (((scsi_result[2] & 0x07) == 0) - || - ((scsi_result[2] & 0x07) == 1 && - (scsi_result[3] & 0x0f) == 0)) - return 0; + * Get the length from the first four bytes of lun_data_pnt. + */ + byte_pnt = (char*) lun_data_pnt->scsi_lun; + length = ((byte_pnt[0] << 24) | (byte_pnt[1] << 16) | + (byte_pnt[2] << 8) | (byte_pnt[3] << 0)); + if ((length / sizeof(ScsiLun)) > max_scsi_report_luns) { + printk("scsi: On %s only %d (max_scsi_report_luns) of %d luns" + " reported, try increasing max_scsi_report_luns.\n", + devname, max_scsi_report_luns, + length / sizeof(ScsiLun)); + num_luns = max_scsi_report_luns; + } else + num_luns = (length / sizeof(ScsiLun)); + + scsi_level = SDlun0_pnt->scsi_level; + + SCSI_LOG_SCAN_BUS(3, + printk("scsi: REPORT LUN scan of host %d channel %d id %d\n", + SDlun0_pnt->host->host_no, SDlun0_pnt->channel, + SDlun0_pnt->id)); + /* + * Scan the luns in lun_data_pnt. The entry at offset 0 is really + * the header, so start at 1 and go up to and including num_luns. + */ + for (fcp_cur_lun_pnt = &lun_data_pnt[1]; + fcp_cur_lun_pnt <= &lun_data_pnt[num_luns]; + fcp_cur_lun_pnt++) { + lun = scsilun_to_int(fcp_cur_lun_pnt); + /* + * Check if the unused part of fcp_cur_lun_pnt is non-zero, + * and so does not fit in lun. + */ + if (memcmp(&fcp_cur_lun_pnt->scsi_lun[sizeof(lun)], + "\0\0\0\0", 4) != 0) { + int i; + + /* + * Output an error displaying the LUN in byte order, + * this differs from what linux would print for the + * integer LUN value. + */ + printk("scsi: %s lun 0x", devname); + byte_pnt = (char*) fcp_cur_lun_pnt->scsi_lun; + for (i = 0; i < sizeof(ScsiLun); i++) + printk("%02x", byte_pnt[i]); + printk(" has a LUN larger than that supported by" + " the kernel\n"); + } else if (lun == 0) { + /* + * LUN 0 has already been scanned. + */ + } else if (lun > shpnt->max_lun) { + printk("scsi: %s lun %d has a LUN larger than allowed" + " by the host adapter\n", devname, lun); + } else { + /* + * Don't use SDlun0_pnt after this call - it can be + * overwritten via SDpnt2 if there was no real device + * at LUN 0. + */ + if (scan_scsis_single(channel, dev, lun, + scsi_level, SDpnt2, shpnt, scsi_result) + == SCSI_SCAN_NO_RESPONSE) { + /* + * Got some results, but now none, abort. + */ + printk("scsi: no response from %s lun %d while" + " scanning, scan aborted\n", devname, + lun); + break; + } + } + } + + kfree((char *) lun_data_pnt); + return 0; + +#else return 1; +#endif /* CONFIG_SCSI_REPORT_LUNS */ + +} + +/* + * Function: scan_scsis_target + * + * Purpose: Scan the given scsi target dev, and as needed all LUNs + * on the target dev. + * + * Arguments: channel - the host's channel + * dev - target dev (target id) + * SDpnt2 - pointer to pointer of a preallocated Scsi_Device + * shpnt - host device to use + * scsi_result - preallocated buffer for the SCSI command result + * + * Lock status: None + * + * Returns: void + * + * Notes: This tries to be compatible with linux 2.4.x. This function + * relies on scan_scsis_single to setup SDlun0_pnt. + * + * It would be better if the Scsi_Device allocation and freeing + * was done here, rather than oddly embedded in scan_scsis_single + * and scan_scsis. + */ +static void scan_scsis_target(unsigned int channel, unsigned int dev, + Scsi_Device **SDpnt2, struct Scsi_Host *shpnt, + char *scsi_result) +{ + int bflags, scsi_level; + Scsi_Device *SDlun0_pnt; + unsigned int sparse_lun = 0; + unsigned int max_dev_lun, lun; + unsigned int sdlun0_res; + + /* + * Scan lun 0, use the results to determine whether to scan further. + * Ideally, we would not configure LUN 0 until we scan. + */ + SDlun0_pnt = *SDpnt2; + sdlun0_res = scan_scsis_single(channel, dev, 0 /* LUN 0 */, SCSI_2, + SDpnt2, shpnt, scsi_result); + if (sdlun0_res == SCSI_SCAN_NO_RESPONSE) + return; + + /* + * If no new SDpnt was allocated (SCSI_SCAN_DEVICE_PRESENT), SDlun0_pnt + * can later be modified. It is unlikely the lun level would change, + * but save it just in case. + */ + scsi_level = SDlun0_pnt->scsi_level; + + /* + * We could probably use and save the bflags from lun 0 for all luns + * on a target, but be safe and match current behaviour. (LUN 0 + * bflags controls the target settings checked within this function.) + */ + bflags = get_device_flags (SDlun0_pnt->vendor, SDlun0_pnt->model); + + /* + * Some scsi devices cannot be polled for lun != 0 due to firmware bugs + */ + if (bflags & BLIST_NOLUN) + return; + + /* + * Ending the scan here if max_scsi_luns == 1 breaks scanning of + * SPARSE, FORCE, MAX5 LUN devices, and the report lun scans. + */ + + if (scsi_report_lun_scan(SDlun0_pnt, channel, dev, SDpnt2, shpnt, + scsi_result) == 0) + return; + + SCSI_LOG_SCAN_BUS(3, + printk("scsi: Sequential scan of host %d channel %d id %d\n", + SDlun0_pnt->host->host_no, SDlun0_pnt->channel, + SDlun0_pnt->id)); + + max_dev_lun = (max_scsi_luns < shpnt->max_lun ? + max_scsi_luns : shpnt->max_lun); + /* + * If this device is known to support sparse multiple units, + * override the other settings, and scan all of them. + */ + if (bflags & BLIST_SPARSELUN) { + max_dev_lun = shpnt->max_lun; + sparse_lun = 1; + } else if (sdlun0_res == SCSI_SCAN_DEVICE_PRESENT) { + /* + * LUN 0 responded, but no LUN 0 was added, don't scan any + * further. This matches linux 2.4.x behaviour. + */ + return; + } + /* + * If less than SCSI_1_CSS, and not a forced lun scan, stop + * scanning, this matches 2.4 behaviour, but it could be a bug + * to scan SCSI_1_CSS devices past LUN 0. + */ + if ((scsi_level < SCSI_1_CCS) && ((bflags & + (BLIST_FORCELUN | BLIST_SPARSELUN | BLIST_MAX5LUN)) == 0)) + return; + /* + * If this device is known to support multiple units, override + * the other settings, and scan all of them. + */ + if (bflags & BLIST_FORCELUN) + max_dev_lun = shpnt->max_lun; + /* + * REGAL CDC-4X: avoid hang after LUN 4 + */ + if (bflags & BLIST_MAX5LUN) + max_dev_lun = min(5U, max_dev_lun); + /* + * Do not scan past LUN 7. + */ + if (scsi_level < SCSI_3) + max_dev_lun = min(8U, max_dev_lun); + + /* + * We have already scanned lun 0. + */ + for (lun = 1; lun < max_dev_lun; ++lun) { + int res; + /* + * Scan until scan_scsis_single says stop, + * unless sparse_lun is set. + */ + res = scan_scsis_single(channel, dev, lun, + scsi_level, SDpnt2, shpnt, scsi_result); + if (res == SCSI_SCAN_NO_RESPONSE) { + /* + * Got a response on LUN 0, but now no response. + */ + printk("scsi: no response from device" + " host%d/bus%d/target%d/lun%d" + " while scanning, scan aborted\n", + shpnt->host_no, channel, dev, lun); + return; + } else if ((res == SCSI_SCAN_DEVICE_PRESENT) + && !sparse_lun) + return; + } } /* - * The worker for scan_scsis. * Returns the scsi_level of lun0 on this host, channel and dev (if already * known), otherwise returns SCSI_2. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/scsi_syms.c linux-2.5/drivers/scsi/scsi_syms.c --- linux-2.5.5/drivers/scsi/scsi_syms.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/scsi/scsi_syms.c Sun Mar 3 23:46:15 2002 @@ -81,6 +81,11 @@ EXPORT_SYMBOL(scsi_deregister_blocked_host); /* + * This symbol is for the highlevel drivers (e.g. sg) only. + */ +EXPORT_SYMBOL(scsi_reset_provider); + +/* * These are here only while I debug the rest of the scsi stuff. */ EXPORT_SYMBOL(scsi_hostlist); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/sd.c linux-2.5/drivers/scsi/sd.c --- linux-2.5.5/drivers/scsi/sd.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/scsi/sd.c Mon Feb 25 18:47:47 2002 @@ -50,6 +50,7 @@ #include #define MAJOR_NR SCSI_DISK0_MAJOR +#define LOCAL_END_REQUEST #include #include #include "scsi.h" @@ -272,7 +273,7 @@ target = DEVICE_NR(dev); dpnt = &rscsi_disks[target]; - if (!dpnt) + if (!dpnt->device) return NULL; /* No such device */ return &dpnt->device->request_queue; } @@ -301,7 +302,7 @@ dpnt = &rscsi_disks[dev]; if (devm >= (sd_template.dev_max << 4) || (devm & 0xf) || - !dpnt || + !dpnt->device || !dpnt->device->online || block + SCpnt->request.nr_sectors > sd[devm].nr_sects) { SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/sg.c linux-2.5/drivers/scsi/sg.c --- linux-2.5.5/drivers/scsi/sg.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/scsi/sg.c Sun Mar 3 20:36:50 2002 @@ -7,7 +7,7 @@ * Original driver (sg.c): * Copyright (C) 1992 Lawrence Foard * Version 2 and 3 extensions to driver: - * Copyright (C) 1998 - 2001 Douglas Gilbert + * Copyright (C) 1998 - 2002 Douglas Gilbert * * Modified 19-JAN-1998 Richard Gooch Devfs support * @@ -19,9 +19,9 @@ */ #include #ifdef CONFIG_PROC_FS - static char sg_version_str[] = "Version: 3.5.23 (20020103)"; + static char sg_version_str[] = "Version: 3.5.24 (20020228)"; #endif - static int sg_version_num = 30523; /* 2 digits for each component */ + static int sg_version_num = 30524; /* 2 digits for each component */ /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First @@ -76,6 +76,8 @@ #include #endif /* LINUX_VERSION_CODE */ +/* #define SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST */ + #define SG_ALLOW_DIO_DEF 0 #define SG_ALLOW_DIO_CODE /* compile out be commenting this define */ #ifdef SG_ALLOW_DIO_CODE @@ -285,7 +287,7 @@ if (flags & O_EXCL) { if (O_RDONLY == (flags & O_ACCMODE)) { - retval = -EACCES; /* Can't lock it with read only access */ + retval = -EPERM; /* Can't lock it with read only access */ goto error_out; } if (sdp->headfp && (flags & O_NONBLOCK)) @@ -643,7 +645,7 @@ if (read_only && (! sg_allow_access(cmnd[0], sfp->parentdp->device->type))) { sg_remove_request(sfp, srp); - return -EACCES; + return -EPERM; } k = sg_common_write(sfp, srp, cmnd, timeout, blocking); if (k < 0) return k; @@ -696,6 +698,7 @@ srp->my_cmdp = SRpnt; q = &SRpnt->sr_device->request_queue; SRpnt->sr_request.rq_dev = sdp->i_rdev; + SRpnt->sr_request.rq_status = RQ_ACTIVE; SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_cmd_len = hp->cmd_len; if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) { @@ -972,7 +975,7 @@ copy_from_user(&opcode, siocp->data, 1); if (! sg_allow_access(opcode, sdp->device->type)) - return -EACCES; + return -EPERM; } return scsi_ioctl_send_command(sdp->device, (void *)arg); case SG_SET_DEBUG: @@ -989,7 +992,7 @@ return scsi_ioctl(sdp->device, cmd_in, (void *)arg); default: if (read_only) - return -EACCES; /* don't know so take safe approach */ + return -EPERM; /* don't know so take safe approach */ return scsi_ioctl(sdp->device, cmd_in, (void *)arg); } } @@ -2581,9 +2584,9 @@ } } -static unsigned char allow_ops[] = {TEST_UNIT_READY, INQUIRY, -READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12, -MODE_SENSE, MODE_SENSE_10}; +static unsigned char allow_ops[] = {TEST_UNIT_READY, REQUEST_SENSE, +INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12, +MODE_SENSE, MODE_SENSE_10, LOG_SENSE}; static int sg_allow_access(unsigned char opcode, char dev_type) { @@ -2983,17 +2986,28 @@ int size, int * eof, void * data) { SG_PROC_READ_FN(sg_proc_hoststrs_info); } +#define SG_MAX_HOST_STR_LEN 256 + static int sg_proc_hoststrs_info(char * buffer, int * len, off_t * begin, off_t offset, int size) { struct Scsi_Host * shp; int k; + char buff[SG_MAX_HOST_STR_LEN]; + char * cp; for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) { - for ( ; k < shp->host_no; ++k) - PRINT_PROC("\n"); - PRINT_PROC("%s\n", shp->hostt->info ? shp->hostt->info(shp) : - (shp->hostt->name ? shp->hostt->name : "")); + for ( ; k < shp->host_no; ++k) + PRINT_PROC("\n"); + strncpy(buff, shp->hostt->info ? shp->hostt->info(shp) : + (shp->hostt->name ? shp->hostt->name : ""), + SG_MAX_HOST_STR_LEN); + buff[SG_MAX_HOST_STR_LEN - 1] = '\0'; + for (cp = buff; *cp; ++cp) { + if ('\n' == *cp) + *cp = ' '; /* suppress imbedded newlines */ + } + PRINT_PROC("%s\n", buff); } return 1; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/sgiwd93.c linux-2.5/drivers/scsi/sgiwd93.c --- linux-2.5.5/drivers/scsi/sgiwd93.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/scsi/sgiwd93.c Sun Mar 3 17:54:36 2002 @@ -4,10 +4,13 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * 1999 Andrew R. Baker (andrewb@uab.edu) * - Support for 2nd SCSI controller on Indigo2 + * 2001 Florian Lohoff (flo@rfc822.org) + * - Delete HPC scatter gather (Read corruption on + * multiple disks) + * - Cleanup wback cache handling * * (In all truth, Jed Schimmel wrote all this code.) * - * $Id: sgiwd93.c,v 1.19 2000/02/04 07:40:47 ralf Exp $ */ #include #include @@ -36,29 +39,34 @@ struct hpc_chunk { struct hpc_dma_desc desc; - unsigned long padding; + u32 _padding; /* align to quadword boundary */ }; struct Scsi_Host *sgiwd93_host = NULL; struct Scsi_Host *sgiwd93_host1 = NULL; /* Wuff wuff, wuff, wd33c93.c, wuff wuff, object oriented, bow wow. */ -static inline void write_wd33c93_count(wd33c93_regs *regp, unsigned long value) +static inline void write_wd33c93_count(const wd33c93_regs regs, + unsigned long value) { - regp->SASR = WD_TRANSFER_COUNT_MSB; - regp->SCMD = ((value >> 16) & 0xff); - regp->SCMD = ((value >> 8) & 0xff); - regp->SCMD = ((value >> 0) & 0xff); + *regs.SASR = WD_TRANSFER_COUNT_MSB; + mb(); + *regs.SCMD = ((value >> 16) & 0xff); + *regs.SCMD = ((value >> 8) & 0xff); + *regs.SCMD = ((value >> 0) & 0xff); + mb(); } -static inline unsigned long read_wd33c93_count(wd33c93_regs *regp) +static inline unsigned long read_wd33c93_count(const wd33c93_regs regs) { unsigned long value; - regp->SASR = WD_TRANSFER_COUNT_MSB; - value = ((regp->SCMD & 0xff) << 16); - value |= ((regp->SCMD & 0xff) << 8); - value |= ((regp->SCMD & 0xff) << 0); + *regs.SASR = WD_TRANSFER_COUNT_MSB; + mb(); + value = ((*regs.SCMD & 0xff) << 16); + value |= ((*regs.SCMD & 0xff) << 8); + value |= ((*regs.SCMD & 0xff) << 0); + mb(); return value; } @@ -81,7 +89,6 @@ unsigned long physaddr; unsigned long count; - dma_cache_wback_inv((unsigned long)addr,len); physaddr = PHYSADDR(addr); while (len) { /* @@ -100,7 +107,6 @@ static int dma_setup(Scsi_Cmnd *cmd, int datainp) { struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)cmd->host->hostdata; - wd33c93_regs *regp = hdata->regp; struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->host->base; struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->dma_bounce_buffer; @@ -111,46 +117,17 @@ hdata->dma_dir = datainp; - if(cmd->SCp.buffers_residual) { - struct scatterlist *slp = cmd->SCp.buffer; - int i, totlen = 0; + /* + * wd33c93 shouldn't pass us bogus dma_setups, but + * it does:-( The other wd33c93 drivers deal with + * it the same way (which isn't that obvious). + * IMHO a better fix would be, not to do these + * dma setups in the first place + */ + if (cmd->SCp.ptr == NULL) + return 1; -#ifdef DEBUG_DMA - printk("SCLIST<"); -#endif - for(i = 0; i <= cmd->SCp.buffers_residual; i++) { -#ifdef DEBUG_DMA - printk("[%p,%d]", - page_address(slp[i].page) + slp[i].offset, - slp[i].length); -#endif - fill_hpc_entries (&hcp, - page_address(slp[i].page) + slp[i].offset, - slp[i].length); - totlen += slp[i].length; - } -#ifdef DEBUG_DMA - printk(">tlen<%d>", totlen); -#endif - hdata->dma_bounce_len = totlen; /* a trick... */ - write_wd33c93_count(regp, totlen); - } else { - /* Non-scattered dma. */ -#ifdef DEBUG_DMA - printk("ONEBUF<%p,%d>", cmd->SCp.ptr, cmd->SCp.this_residual); -#endif - /* - * wd33c93 shouldn't pass us bogus dma_setups, but - * it does:-( The other wd33c93 drivers deal with - * it the same way (which isn't that obvious). - * IMHO a better fix would be, not to do these - * dma setups in the first place - */ - if (cmd->SCp.ptr == NULL) - return 1; - fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual); - write_wd33c93_count(regp, cmd->SCp.this_residual); - } + fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual); /* To make sure, if we trip an HPC bug, that we transfer * every single byte, we tag on an extra zero length dma @@ -165,10 +142,14 @@ /* Start up the HPC. */ hregs->ndptr = PHYSADDR(hdata->dma_bounce_buffer); - if(datainp) + if(datainp) { + dma_cache_inv((unsigned long) cmd->SCp.ptr, cmd->SCp.this_residual); hregs->ctrl = (HPC3_SCTRL_ACTIVE); - else + } else { + dma_cache_wback_inv((unsigned long) cmd->SCp.ptr, cmd->SCp.this_residual); hregs->ctrl = (HPC3_SCTRL_ACTIVE | HPC3_SCTRL_DIR); + } + return 0; } @@ -176,7 +157,6 @@ int status) { struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)instance->hostdata; - wd33c93_regs *regp = hdata->regp; struct hpc3_scsiregs *hregs; if (!SCpnt) @@ -196,44 +176,6 @@ } hregs->ctrl = 0; - /* See how far we got and update scatterlist state if necessary. */ - if(SCpnt->SCp.buffers_residual) { - struct scatterlist *slp = SCpnt->SCp.buffer; - int totlen, wd93_residual, transferred, i; - - /* Yep, we were doing the scatterlist thang. */ - totlen = hdata->dma_bounce_len; - wd93_residual = read_wd33c93_count(regp); - transferred = totlen - wd93_residual; - -#ifdef DEBUG_DMA - printk("tlen<%d>resid<%d>transf<%d> ", - totlen, wd93_residual, transferred); -#endif - - /* Avoid long winded partial-transfer search for common case. */ - if(transferred != totlen) { - /* This is the nut case. */ -#ifdef DEBUG_DMA - printk("Jed was here..."); -#endif - for(i = 0; i <= SCpnt->SCp.buffers_residual; i++) { - if(slp[i].length >= transferred) - break; - transferred -= slp[i].length; - } - } else { - /* This is the common case. */ -#ifdef DEBUG_DMA - printk("did it all..."); -#endif - i = SCpnt->SCp.buffers_residual; - } - SCpnt->SCp.buffer = &slp[i]; - SCpnt->SCp.buffers_residual = SCpnt->SCp.buffers_residual - i; - SCpnt->SCp.ptr = (char *) page_address(slp[i].page) + slp[i].offset; - SCpnt->SCp.this_residual = slp[i].length; - } #ifdef DEBUG_DMA printk("\n"); #endif @@ -263,6 +205,9 @@ }; hcp--; hcp->desc.pnext = PHYSADDR(buf); + + /* Force flush to memory */ + dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); } int __init sgiwd93_detect(Scsi_Host_Template *SGIblows) @@ -272,6 +217,7 @@ struct hpc3_scsiregs *hregs1 = &hpc3c0->scsi_chan1; struct WD33C93_hostdata *hdata; struct WD33C93_hostdata *hdata1; + wd33c93_regs regs; uchar *buf; if(called) @@ -292,10 +238,11 @@ return 0; } init_hpc_chain(buf); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); + /* HPC_SCSI_REG0 | 0x03 | KSEG1 */ - wd33c93_init(sgiwd93_host, (wd33c93_regs *) KSEG1ADDR (0x1fbc0003), - dma_setup, dma_stop, WD33C93_FS_16_20); + regs.SASR = (unsigned char*) KSEG1ADDR (0x1fbc0003); + regs.SCMD = (unsigned char*) KSEG1ADDR (0x1fbc0007); + wd33c93_init(sgiwd93_host, regs, dma_setup, dma_stop, WD33C93_FS_16_20); hdata = (struct WD33C93_hostdata *)sgiwd93_host->hostdata; hdata->no_sync = 0; @@ -326,15 +273,16 @@ return 1; /* We registered host0 so return success*/ } init_hpc_chain(buf); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); + /* HPC_SCSI_REG1 | 0x03 | KSEG1 */ - wd33c93_init(sgiwd93_host1, (wd33c93_regs *) KSEG1ADDR (0x1fbc8003), - dma_setup, dma_stop, WD33C93_FS_16_20); + regs.SASR = (unsigned char*) KSEG1ADDR(0x1fbc8003); + regs.SCMD = (unsigned char*) KSEG1ADDR(0x1fbc8007); + wd33c93_init(sgiwd93_host1, regs, dma_setup, dma_stop, + WD33C93_FS_16_20); hdata1 = (struct WD33C93_hostdata *)sgiwd93_host1->hostdata; hdata1->no_sync = 0; hdata1->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf)); - dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); if (request_irq(SGI_WD93_1_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host1)) { printk(KERN_WARNING "sgiwd93: Could not allocate irq %d (for host1).\n", SGI_WD93_1_IRQ); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/sr.c linux-2.5/drivers/scsi/sr.c --- linux-2.5.5/drivers/scsi/sr.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/scsi/sr.c Thu Feb 21 01:26:10 2002 @@ -49,6 +49,7 @@ #include #define MAJOR_NR SCSI_CDROM_MAJOR +#define LOCAL_END_REQUEST #include #include "scsi.h" #include "hosts.h" @@ -524,7 +525,7 @@ scsi_CDs[i].needs_sector_size = 1; } else { #if 0 - if (cdrom_get_last_written(MKDEV(MAJOR_NR, i), + if (cdrom_get_last_written(mkdev(MAJOR_NR, i), &scsi_CDs[i].capacity)) #endif scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) | diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/sr_ioctl.c linux-2.5/drivers/scsi/sr_ioctl.c --- linux-2.5.5/drivers/scsi/sr_ioctl.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/scsi/sr_ioctl.c Sun Mar 3 17:54:36 2002 @@ -48,7 +48,7 @@ if (ti->cdti_trk1 == ntracks) ti->cdti_trk1 = CDROM_LEADOUT; - else + else if (ti->cdti_trk1 != CDROM_LEADOUT) ti->cdti_trk1 ++; trk0_te.cdte_track = ti->cdti_trk0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/st.c linux-2.5/drivers/scsi/st.c --- linux-2.5.5/drivers/scsi/st.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/scsi/st.c Fri Feb 8 03:15:29 2002 @@ -12,13 +12,13 @@ Copyright 1992 - 2002 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Wed Jan 23 20:22:42 2002 by makisara + Last modified: Tue Feb 5 21:25:55 2002 by makisara Some small formal changes - aeb, 950809 Last modified: 18-JAN-1998 Richard Gooch Devfs support */ -static char *verstr = "20020123"; +static char *verstr = "20020205"; #include @@ -2112,7 +2112,8 @@ #define MODE_SELECT_PAGE_FORMAT 0x10 /* Read a mode page into the tape buffer. The block descriptors are included - if incl_block_descs is true. */ + if incl_block_descs is true. The page control is ored to the page number + parameter, if necessary. */ static int read_mode_page(Scsi_Tape *STp, int page, int omit_block_descs) { unsigned char cmd[MAX_COMMAND_SIZE]; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/sun3_scsi.c linux-2.5/drivers/scsi/sun3_scsi.c --- linux-2.5.5/drivers/scsi/sun3_scsi.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/scsi/sun3_scsi.c Tue Jan 8 01:17:10 2002 @@ -357,7 +357,7 @@ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); NCR5380_read( RESET_PARITY_INTERRUPT_REG ); - for( end = jiffies + AFTER_RESET_DELAY; jiffies < end; ) + for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); ) barrier(); /* switch on SCSI IRQ again */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/sym53c8xx_2/sym_hipd.c linux-2.5/drivers/scsi/sym53c8xx_2/sym_hipd.c --- linux-2.5.5/drivers/scsi/sym53c8xx_2/sym_hipd.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/scsi/sym53c8xx_2/sym_hipd.c Mon Dec 17 01:03:07 2001 @@ -50,7 +50,7 @@ * SUCH DAMAGE. */ -#define SYM_DRIVER_NAME "sym-2.1.16a" +#define SYM_DRIVER_NAME "sym-2.1.17a" #ifdef __FreeBSD__ #include @@ -5797,6 +5797,13 @@ goto attach_failed; /* + * Allocate the array of lists of CCBs hashed by DSA. + */ + np->ccbh = sym_calloc(sizeof(ccb_p *)*CCB_HASH_SIZE, "CCBH"); + if (!np->ccbh) + goto attach_failed; + + /* * Initialyze the CCB free and busy queues. */ sym_que_init(&np->free_ccbq); @@ -5925,6 +5932,8 @@ np->target[i].head.lun0_sa = cpu_to_scr(vtobus(&np->badlun_sa)); } + if (np->ccbh) + sym_mfree(np->ccbh, sizeof(ccb_p *)*CCB_HASH_SIZE, "CCBH"); /* * Now check the cache handling of the pci chipset. diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/sym53c8xx_defs.h linux-2.5/drivers/scsi/sym53c8xx_defs.h --- linux-2.5.5/drivers/scsi/sym53c8xx_defs.h Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/scsi/sym53c8xx_defs.h Sun Mar 3 17:54:36 2002 @@ -51,6 +51,10 @@ ** NVRAM detection and reading. ** Copyright (C) 1997 Richard Waltham ** +** Added support for MIPS big endian systems. +** Carsten Langgaard, carstenl@mips.com +** Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. +** ******************************************************************************* */ @@ -384,7 +388,16 @@ #define readl_l2b(a) le32_to_cpu(readl(a)) #define writew_b2l(v,a) writew(cpu_to_le16(v),a) #define writel_b2l(v,a) writel(cpu_to_le32(v),a) -#else /* Other bid-endian */ +#elif defined(__mips__) +#define readw_l2b readw +#define readl_l2b readl +#define writew_b2l writew +#define writel_b2l writel +#define inw_l2b inw +#define inl_l2b inl +#define outw_b2l outw +#define outl_b2l outl +#else /* Other big-endian */ #define readw_l2b readw #define readl_l2b readl #define writew_b2l writew diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/t128.c linux-2.5/drivers/scsi/t128.c --- linux-2.5.5/drivers/scsi/t128.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/scsi/t128.c Thu Dec 13 16:32:36 2001 @@ -47,17 +47,12 @@ * increase compared to polled I/O. * * PARITY - enable parity checking. Not supported. - * - * SCSI2 - enable support for SCSI-II tagged queueing. Untested. - * * * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You * only really want to use this if you're having a problem with * dropped characters during high speed communications, and even * then, you're going to be better off twiddling with transfersize. * - * USLEEP - enable support for devices that don't disconnect. Untested. - * * The card is detected and initialized in one of several ways : * 1. Autoprobe (default) - since the board is memory mapped, * a BIOS signature is scanned for to locate the registers. @@ -101,10 +96,6 @@ * 14 10-12 * 15 9-11 */ - -/* - * $Log: t128.c,v $ - */ #include #include @@ -123,276 +114,252 @@ #include static struct override { - unsigned long address; - int irq; -} overrides + unsigned long address; + int irq; +} overrides #ifdef T128_OVERRIDE - [] __initdata = T128_OVERRIDE; +[] __initdata = T128_OVERRIDE; #else - [4] __initdata = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, - {0 ,IRQ_AUTO}, {0, IRQ_AUTO}}; +[4] __initdata = { + { 0, IRQ_AUTO}, + { 0, IRQ_AUTO}, + { 0, IRQ_AUTO}, + { 0, IRQ_AUTO} +}; #endif #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) static struct base { - unsigned int address; - int noauto; + unsigned int address; + int noauto; } bases[] __initdata = { - { 0xcc000, 0}, { 0xc8000, 0}, { 0xdc000, 0}, { 0xd8000, 0} + {0xcc000, 0}, + {0xc8000, 0}, + {0xdc000, 0}, + {0xd8000, 0} }; #define NO_BASES (sizeof (bases) / sizeof (struct base)) static const struct signature { - const char *string; - int offset; + const char *string; + int offset; } signatures[] __initdata = { -{"TSROM: SCSI BIOS, Version 1.12", 0x36}, + {"TSROM: SCSI BIOS, Version 1.12", 0x36}, }; #define NO_SIGNATURES (sizeof (signatures) / sizeof (struct signature)) -/* - * Function : t128_setup(char *str, int *ints) - * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. +/** + * t128_setup + * @str: command line * + * LILO command line initialization of the overrides array, */ -void __init t128_setup(char *str, int *ints){ - static int commandline_current = 0; - int i; - if (ints[0] != 2) - printk("t128_setup : usage t128=address,irq\n"); - else - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].address = ints[1]; - overrides[commandline_current].irq = ints[2]; - for (i = 0; i < NO_BASES; ++i) - if (bases[i].address == ints[1]) { - bases[i].noauto = 1; - break; - } - ++commandline_current; +int __init t128_setup(char *str) +{ + static int commandline_current = 0; + int ints[10]; + int i; + + get_options(str, sizeof(ints) / sizeof(int), ints); + + if (ints[0] != 2) + printk(KERN_ERR "t128_setup : usage t128=address,irq\n"); + else if (commandline_current < NO_OVERRIDES) { + overrides[commandline_current].address = ints[1]; + overrides[commandline_current].irq = ints[2]; + for (i = 0; i < NO_BASES; ++i) + if (bases[i].address == ints[1]) { + bases[i].noauto = 1; + break; + } + ++commandline_current; } + return 1; } -/* - * Function : int t128_detect(Scsi_Host_Template * tpnt) +__setup("t128=", t128_setup); + +/** + * t128_detect - detect controllers + * @tpnt: SCSI template * - * Purpose : detects and initializes T128,T128F, or T228 controllers + * Detects and initializes T128,T128F, or T228 controllers * that were autoprobed, overridden on the LILO command line, * or specified at compile time. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. - * */ -int __init t128_detect(Scsi_Host_Template * tpnt){ - static int current_override = 0, current_base = 0; - struct Scsi_Host *instance; - unsigned long base; - int sig, count; - - tpnt->proc_name = "t128"; - tpnt->proc_info = &t128_proc_info; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - base = 0; - - if (overrides[current_override].address) - base = overrides[current_override].address; - else - for (; !base && (current_base < NO_BASES); ++current_base) { -#if (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : probing address %08x\n", bases[current_base].address); -#endif - for (sig = 0; sig < NO_SIGNATURES; ++sig) - if (!bases[current_base].noauto && - isa_check_signature(bases[current_base].address + - signatures[sig].offset, - signatures[sig].string, - strlen(signatures[sig].string))) { - base = bases[current_base].address; -#if (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : detected board.\n"); -#endif +int __init t128_detect(Scsi_Host_Template * tpnt) +{ + static int current_override = 0, current_base = 0; + struct Scsi_Host *instance; + unsigned long base; + int sig, count; + + tpnt->proc_name = "t128"; + tpnt->proc_info = &t128_proc_info; + + for (count = 0; current_override < NO_OVERRIDES; ++current_override) + { + base = 0; + + if (overrides[current_override].address) + base = overrides[current_override].address; + else + for (; !base && (current_base < NO_BASES); ++current_base) { + for (sig = 0; sig < NO_SIGNATURES; ++sig) + if (!bases[current_base].noauto && + isa_check_signature(bases[current_base].address + signatures[sig].offset, + signatures[sig].string, + strlen(signatures[sig].string))) + { + base = bases[current_base].address; + break; + } + } + + if (!base) break; - } - } -#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : base = %08x\n", (unsigned int) base); -#endif + instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) + break; - if (!base) - break; + instance->base = base; - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - break; - - instance->base = base; - - NCR5380_init(instance, 0); - - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, T128_IRQS); - - if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_t128_intr, SA_INTERRUPT, "t128", instance)) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = IRQ_NONE; - } - - if (instance->irq == IRQ_NONE) { - printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - } + NCR5380_init(instance, 0); -#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT) - printk("scsi%d : irq = %d\n", instance->host_no, instance->irq); -#endif + if (overrides[current_override].irq != IRQ_AUTO) + instance->irq = overrides[current_override].irq; + else + instance->irq = NCR5380_probe_irq(instance, T128_IRQS); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, do_t128_intr, SA_INTERRUPT, "t128", NULL)) + { + printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq == IRQ_NONE) { + printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); + } + + printk(KERN_INFO "scsi%d : at 0x%08lx", instance->host_no,instance->base); + if (instance->irq == IRQ_NONE) + printk(" interrupts disabled"); + else + printk(" irq %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE); + NCR5380_print_options(instance); + printk("\n"); - printk("scsi%d : at 0x%08lx", instance->host_no, instance->base); - if (instance->irq == IRQ_NONE) - printk (" interrupts disabled"); - else - printk (" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; + ++current_override; + ++count; + } + return count; } -/* - * Function : int t128_biosparam(Disk * disk, kdev_t dev, int *ip) +/** + * t128_biosparam - disk geometry + * @disk: device + * @dev: device major/minor + * @ip: array to return results * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for + * Generates a BIOS / DOS compatible H-C-S mapping for * the specified device / size. * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} - * - * Returns : always 0 (success), initializes ip - * + * Most SCSI boards use this mapping, I could be incorrect. Some one + * using hard disks on a trantor should verify that this mapping + * corresponds to that used by the BIOS / ASPI driver by running the + * linux fdisk program and matching the H_C_S coordinates to those + * that DOS uses. */ -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. - */ - -int t128_biosparam(Disk * disk, kdev_t dev, int * ip) +int t128_biosparam(Disk * disk, kdev_t dev, int *ip) { - int size = disk->capacity; - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - return 0; + int size = disk->capacity; + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + return 0; } -/* - * Function : int NCR5380_pread (struct Scsi_Host *instance, - * unsigned char *dst, int len) +/** + * NCR5380_pread - pseudo DMA read + * @instance: controller + * @dst: buffer to write to + * @len: expect/max length * - * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to - * dst - * - * Inputs : dst = destination, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. + * Fast 5380 pseudo-dma read function, transfers len bytes to + * dst from the controller. */ -static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, - int len) { - unsigned long reg = instance->base + T_DATA_REG_OFFSET; - unsigned char *d = dst; - register int i = len; - - -#if 0 - for (; i; --i) { - while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); -#else - while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); - for (; i; --i) { -#endif - *d++ = isa_readb(reg); - } +static inline int NCR5380_pread(struct Scsi_Host *instance, + unsigned char *dst, int len) +{ + unsigned long reg = instance->base + T_DATA_REG_OFFSET; + unsigned char *d = dst; + int i = len; + + while (!(isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_RDY)) + barrier(); + for (; i; --i) { + *d++ = isa_readb(reg); + } - if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) { - unsigned char tmp; - unsigned long foo; - foo = instance->base + T_CONTROL_REG_OFFSET; - tmp = isa_readb(foo); - isa_writeb(tmp | T_CR_CT, foo); - isa_writeb(tmp, foo); - printk("scsi%d : watchdog timer fired in NCR5380_pread()\n", - instance->host_no); - return -1; - } else - return 0; + if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) { + unsigned char tmp; + unsigned long foo; + foo = instance->base + T_CONTROL_REG_OFFSET; + tmp = isa_readb(foo); + isa_writeb(tmp | T_CR_CT, foo); + isa_writeb(tmp, foo); + printk(KERN_ERR "scsi%d : watchdog timer fired in t128 NCR5380_pread.\n", instance->host_no); + return -1; + } else + return 0; } -/* - * Function : int NCR5380_pwrite (struct Scsi_Host *instance, - * unsigned char *src, int len) +/** + * NCR5380_pwrite - pseudo DMA write + * @instance: controller + * @dst: buffer to write to + * @len: expect/max length * - * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from - * src - * - * Inputs : src = source, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. + * Fast 5380 pseudo-dma write function, transfers len bytes from + * dst to the controller. */ -static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src, - int len) { - unsigned long reg = instance->base + T_DATA_REG_OFFSET; - unsigned char *s = src; - register int i = len; - -#if 0 - for (; i; --i) { - while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); -#else - while (!(isa_readb(instance->base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); - for (; i; --i) { -#endif - isa_writeb(*s++, reg); - } - if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) { - unsigned char tmp; - unsigned long foo; - foo = instance->base + T_CONTROL_REG_OFFSET; - tmp = isa_readb(foo); - isa_writeb(tmp | T_CR_CT, foo); - isa_writeb(tmp, foo); - printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n", - instance->host_no); - return -1; - } else - return 0; +static inline int NCR5380_pwrite(struct Scsi_Host *instance, + unsigned char *src, int len) +{ + unsigned long reg = instance->base + T_DATA_REG_OFFSET; + unsigned char *s = src; + int i = len; + + while (!(isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_RDY)) + barrier(); + for (; i; --i) { + isa_writeb(*s++, reg); + } + + if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) { + unsigned char tmp; + unsigned long foo; + foo = instance->base + T_CONTROL_REG_OFFSET; + tmp = isa_readb(foo); + isa_writeb(tmp | T_CR_CT, foo); + isa_writeb(tmp, foo); + printk(KERN_ERR "scsi%d : watchdog timer fired in t128 NCR5380_pwrite()\n", instance->host_no); + return -1; + } else + return 0; } MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/tmscsim.c linux-2.5/drivers/scsi/tmscsim.c --- linux-2.5.5/drivers/scsi/tmscsim.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/scsi/tmscsim.c Mon Feb 18 20:50:38 2002 @@ -1448,7 +1448,7 @@ PACB pACB = (PACB) disk->device->host->hostdata; int ret_code = -1; int size = disk->capacity; - unsigned char *buf; + unsigned char *buf; if ((buf = scsi_bios_ptable(devno))) { @@ -2468,68 +2468,68 @@ * '-' means no change *******************************************************************/ -static int dc390_scanf (char** p1, char** p2, int* var) +static int dc390_scanf (char** buffer, char** pos, char** p0, int* var) { - *p2 = *p1; - *var = simple_strtoul (*p2, p1, 10); - if (*p2 == *p1) return -1; - *p1 = strtok (0, " \t\n:=,;."); + *p0 = *pos; + *var = simple_strtoul (*p0, pos, 10); + if (*p0 == *pos) return -1; + *pos = strsep (buffer, " \t\n:=,;."); return 0; }; -#define SCANF(p1, p2, var, min, max) \ -if (dc390_scanf (&p1, &p2, &var)) goto einv; \ +#define SCANF(buffer, pos, p0, var, min, max) \ +if (dc390_scanf (&buffer, &pos, &p0, &var)) goto einv; \ else if (varmax) goto einv2 -static int dc390_yesno (char** p, char* var, char bmask) +static int dc390_yesno (char** buffer, char** pos, char* var, char bmask) { - switch (**p) + switch (**pos) { case 'Y': *var |= bmask; break; case 'N': *var &= ~bmask; break; case '-': break; default: return -1; } - *p = strtok (0, " \t\n:=,;"); + *pos = strsep (buffer, " \t\n:=,;"); return 0; }; -#define YESNO(p, var, bmask) \ -if (dc390_yesno (&p, &var, bmask)) goto einv; \ +#define YESNO(buffer, pos, var, bmask) \ +if (dc390_yesno (&buffer, &pos, &var, bmask)) goto einv; \ else dc390_updateDCB (pACB, pDCB); \ if (!p) goto ok -static int dc390_search (char **p1, char **p2, char *var, char* txt, int max, int scale, char* ign) +static int dc390_search (char** buffer, char** pos, char** p0, char* var, char* txt, int max, int scale, char* ign) { int dum; - if (! memcmp (*p1, txt, strlen(txt))) + if (! memcmp (*pos, txt, strlen(txt))) { - *p2 = strtok (0, " \t\n:=,;"); - if (!*p2) return -1; - dum = simple_strtoul (*p2, p1, 10); - if (*p2 == *p1) return -1; + *p0 = strsep (buffer, " \t\n:=,;"); + if (!*p0) return -1; + dum = simple_strtoul (*p0, pos, 10); + if (*p0 == *pos) return -1; if (dum >= 0 && dum <= max) { *var = (dum * 100) / scale; } else return -2; - *p1 = strtok (0, " \t\n:=,;"); - if (*ign && *p1 && strlen(*p1) >= strlen(ign) && - !(memcmp (*p1, ign, strlen(ign)))) - *p1 = strtok (0, " \t\n:=,;"); + *pos = strsep (buffer, " \t\n:=,;"); + if (*ign && *pos && strlen(*pos) >= strlen(ign) && + !(memcmp (*pos, ign, strlen(ign)))) + *pos = strsep (buffer, " \t\n:=,;"); } return 0; }; -#define SEARCH(p1, p2, var, txt, max) \ -if (dc390_search (&p1, &p2, (PUCHAR)(&var), txt, max, 100, "")) goto einv2; \ +#define SEARCH(buffer, pos, p0, var, txt, max) \ +if (dc390_search (&buffer, &pos, &p0, (PUCHAR)(&var), txt, max, 100, "")) goto einv2; \ else if (!p1) goto ok2 -#define SEARCH2(p1, p2, var, txt, max, scale) \ -if (dc390_search (&p1, &p2, &var, txt, max, scale, "")) goto einv2; \ +#define SEARCH2(buffer, pos, p0, var, txt, max, scale) \ +if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, "")) goto einv2; \ else if (!p1) goto ok2 -#define SEARCH3(p1, p2, var, txt, max, scale, ign) \ -if (dc390_search (&p1, &p2, &var, txt, max, scale, ign)) goto einv2; \ +#define SEARCH3(buffer, pos, &p0, var, txt, max, scale, ign) \ +if (dc390_search (&buffer, &pos, p0, &var, txt, max, scale, ign)) goto einv2; \ else if (!p1) goto ok2 @@ -2565,12 +2565,9 @@ while (*pos) { if (*pos >='a' && *pos <= 'z') *pos = *pos + 'A' - 'a'; pos++; }; - /* We should protect __strtok ! */ - /* spin_lock (strtok_lock); */ - /* Remove WS */ - pos = strtok (buffer, " \t:\n=,;"); - if (!pos) goto ok; + pos = strsep (&buffer, " \t:\n=,;"); + if (!*pos) goto ok; next: if (!memcmp (pos, "RESET", 5)) goto reset; @@ -2586,10 +2583,10 @@ int dev, id, lun; char* pdec; char olddevmode; - SCANF (pos, p0, dev, 0, pACB->DCBCnt-1); - if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv; - if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv; - if (!pos) goto einv; + SCANF (buffer, pos, p0, dev, 0, pACB->DCBCnt-1); + if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv; + if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv; + if (!*pos) goto einv; PARSEDEBUG(printk (KERN_INFO "DC390: config line %i %i %i:\"%s\"\n", dev, id, lun, prstr (pos, &buffer[length]));) pDCB = pACB->pLinkDCB; @@ -2610,20 +2607,20 @@ }; olddevmode = pDCB->DevMode; - YESNO (pos, pDCB->DevMode, PARITY_CHK_); + YESNO (buffer, pos, pDCB->DevMode, PARITY_CHK_); needs_inquiry++; - YESNO (pos, pDCB->DevMode, SYNC_NEGO_); + YESNO (buffer, pos, pDCB->DevMode, SYNC_NEGO_); if ((olddevmode & SYNC_NEGO_) == (pDCB->DevMode & SYNC_NEGO_)) needs_inquiry--; needs_inquiry++; - YESNO (pos, pDCB->DevMode, EN_DISCONNECT_); + YESNO (buffer, pos, pDCB->DevMode, EN_DISCONNECT_); if ((olddevmode & EN_DISCONNECT_) == (pDCB->DevMode & EN_DISCONNECT_)) needs_inquiry--; - YESNO (pos, pDCB->DevMode, SEND_START_); + YESNO (buffer, pos, pDCB->DevMode, SEND_START_); needs_inquiry++; - YESNO (pos, pDCB->DevMode, TAG_QUEUEING_); + YESNO (buffer, pos, pDCB->DevMode, TAG_QUEUEING_); if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--; dc390_updateDCB (pACB, pDCB); - if (!pos) goto ok; + if (!*pos) goto ok; olddevmode = pDCB->NegoPeriod; /* Look for decimal point (Speed) */ @@ -2632,22 +2629,22 @@ /* NegoPeriod */ if (*pos != '-') { - SCANF (pos, p0, dum, 72, 800); + SCANF (buffer, pos, p0, dum, 72, 800); pDCB->NegoPeriod = dum >> 2; if (pDCB->NegoPeriod != olddevmode) needs_inquiry++; if (!pos) goto ok; - if (memcmp (pos, "NS", 2) == 0) pos = strtok (0, " \t\n:=,;."); + if (memcmp (pos, "NS", 2) == 0) pos = strsep (*pos, " \t\n:=,;."); } - else pos = strtok (0, " \t\n:=,;."); - if (!pos) goto ok; + else pos = strsep (*pos, " \t\n:=,;."); + if (!*pos) goto ok; /* Sync Speed in MHz */ if (*pos != '-') { - SCANF (pos, p0, dum, 1, 13); + SCANF (buffer, pos, p0, dum, 1, 13); pDCB->NegoPeriod = (1000/dum) >> 2; if (pDCB->NegoPeriod != olddevmode && !pos) needs_inquiry++; - if (!pos) goto ok; + if (!*pos) goto ok; /* decimal */ if (pos-1 == pdec) { @@ -2656,38 +2653,38 @@ for (; p0-pos > 1; p0--) dum /= 10; pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2; if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19; - pos = strtok (0, " \t\n:=,;"); - if (!pos) goto ok; + pos = strsep (*pos, " \t\n:=,;"); + if (!*pos) goto ok; }; - if (*pos == 'M') pos = strtok (0, " \t\n:=,;"); + if (*pos == 'M') pos = strsep (*pos, " \t\n:=,;"); if (pDCB->NegoPeriod != olddevmode) needs_inquiry++; } - else pos = strtok (0, " \t\n:=,;"); + else pos = strsep (*pos, " \t\n:=,;"); /* dc390_updateDCB (pACB, pDCB); */ - if (!pos) goto ok; + if (!*pos) goto ok; olddevmode = pDCB->SyncOffset; /* SyncOffs */ if (*pos != '-') { - SCANF (pos, p0, dum, 0, 0x0f); + SCANF (buffer, pos, p0, dum, 0, 0x0f); pDCB->SyncOffset = dum; if (pDCB->SyncOffset > olddevmode) needs_inquiry++; } - else pos = strtok (0, " \t\n:=,;"); - if (!pos) goto ok; + else pos = strsep (*pos, " \t\n:=,;"); + if (!*pos) goto ok; dc390_updateDCB (pACB, pDCB); //olddevmode = pDCB->MaxCommand; /* MaxCommand (Tags) */ if (*pos != '-') { - SCANF (pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/); + SCANF (buffer, pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/); if (pDCB->SyncMode & EN_TAG_QUEUEING) pDCB->MaxCommand = dum; else printk (KERN_INFO "DC390: Can't set MaxCmd larger than one without Tag Queueing!\n"); } - else pos = strtok (0, " \t\n:=,;"); + else pos = strsep (*pos, " \t\n:=,;"); } else @@ -2696,14 +2693,14 @@ PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));) dum = GLITCH_TO_NS (pACB->glitch_cfg); /* Adapter setting */ - SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 8); - SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8); - SEARCH (pos, p0, newadaptid, "ADAPTERID", 7); - SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32); - SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255); - SEARCH3 (pos, p0, dum, "GLITCHEATER", 40, 1000, "NS"); - SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS"); - SEARCH3 (pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S"); + SEARCH (buffer, pos, p0, pACB->pScsiHost->max_id, "MAXID", 8); + SEARCH (buffer, pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8); + SEARCH (buffer, pos, p0, newadaptid, "ADAPTERID", 7); + SEARCH (buffer, pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32); + SEARCH (buffer, pos, p0, pACB->ACBFlag, "ACBFLAG", 255); + SEARCH3 (buffer, pos, p0, dum, "GLITCHEATER", 40, 1000, "NS"); + SEARCH3 (buffer, pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS"); + SEARCH3 (buffer, pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S"); ok2: pACB->glitch_cfg = NS_TO_GLITCH (dum); if (pACB->sel_timeout < 60) pACB->sel_timeout = 60; @@ -2719,10 +2716,9 @@ // All devs should be INQUIRED now if (pos == p1) goto einv; } - if (pos) goto next; + if (*pos) goto next; ok: - /* spin_unlock (strtok_lock); */ DC390_UNLOCK_ACB; if (needs_inquiry) { dc390_updateDCB (pACB, pDCB); dc390_inquiry (pACB, pDCB); }; @@ -2732,7 +2728,6 @@ einv2: pos = p0; einv: - /* spin_unlock (strtok_lock); */ DC390_UNLOCK_ACB; DC390_UNLOCK_IO(pACB.pScsiHost); printk (KERN_WARNING "DC390: parse error near \"%s\"\n", (pos? pos: "NULL")); @@ -2758,7 +2753,7 @@ inquiry: { - pos = strtok (0, " \t\n.:;="); if (!pos) goto einv; + pos = strsep (*pos, " \t\n.:;="); if (!*pos) goto einv; dev = simple_strtoul (pos, &p0, 10); if (dev >= pACB->DCBCnt) goto einv_dev; for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; @@ -2772,7 +2767,7 @@ remove: { - pos = strtok (0, " \t\n.:;="); if (!pos) goto einv; + pos = strsep (*pos, " \t\n.:;="); if (!*pos) goto einv; dev = simple_strtoul (pos, &p0, 10); if (dev >= pACB->DCBCnt) goto einv_dev; for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; @@ -2788,9 +2783,9 @@ add: { int id, lun; - pos = strtok (0, " \t\n.:;="); - if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv; - if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv; + pos = strsep (*pos, " \t\n.:;="); + if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv; + if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv; pDCB = dc390_findDCB (pACB, id, lun); if (pDCB) { printk ("DC390: ADD: Device already existing\n"); goto einv; }; dc390_initDCB (pACB, &pDCB, id, lun); @@ -2803,9 +2798,9 @@ start: { int id, lun; - pos = strtok (0, " \t\n.:;="); - if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv; - if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv; + pos = strsep (*pos, " \t\n.:;="); + if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv; + if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv; pDCB = dc390_findDCB (pACB, id, lun); if (pDCB) printk ("DC390: SendStart: Device already existing ...\n"); else dc390_initDCB (pACB, &pDCB, id, lun); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/u14-34f.c linux-2.5/drivers/scsi/u14-34f.c --- linux-2.5.5/drivers/scsi/u14-34f.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/scsi/u14-34f.c Tue Feb 26 21:24:49 2002 @@ -1,6 +1,10 @@ /* * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. * + * 20 Feb 2002 Rev. 7.22 for linux 2.5.5 + * + Remove any reference to virt_to_bus(). + * + Fix pio hang while detecting multiple HBAs. + * * 01 Jan 2002 Rev. 7.20 for linux 2.5.1 * + Use the dynamic DMA mapping API. * @@ -30,7 +34,7 @@ * + When loaded as a module, accepts the new parameter boot_options * which value is a string with the same format of the kernel boot * command line options. A valid example is: - * modprobe u14-34f boot_options=\"0x230,0x340,lc:y,mq:4\" + * modprobe u14-34f 'boot_options="0x230,0x340,lc:y,mq:4"' * * 22 Jul 1999 Rev. 5.00 for linux 2.2.10 and 2.3.11 * + Removed pre-2.2 source code compatibility. @@ -167,7 +171,7 @@ * Auto detects if U14F boards have an old firmware revision. * Max number of scatter/gather lists set to 16 for all boards * (most installation run fine using 33 sglists, while other - * has problems when using more then 16). + * has problems when using more than 16). * * 16 Jan 1995 rev. 1.13 for linux 1.1.81 * Display a message if check_region detects a port address @@ -275,7 +279,7 @@ * * For U34F boards the latest bios prom is 38008-002 (BIOS rev. 2.01), * the latest firmware prom is 28008-006. Older firmware 28008-005 has - * problems when using more then 16 scatter/gather lists. + * problems when using more than 16 scatter/gather lists. * * The list of i/o ports to be probed can be totally replaced by the * boot command line option: "u14-34f=port0,port1,port2,...", where the @@ -496,11 +500,19 @@ unsigned char adapter_status; /* non-zero indicates HA error */ unsigned char target_status; /* non-zero indicates target error */ unsigned int sense_addr PACKED; + + /* Additional fields begin here. */ Scsi_Cmnd *SCpnt; unsigned int cpp_index; /* cp index */ - struct sg_list *sglist; + + /* All the cp structure is zero filled by queuecommand except the + following CP_TAIL_SIZE bytes, initialized by detect */ + dma_addr_t cp_dma_addr; /* dma handle for this cp structure */ + struct sg_list *sglist; /* pointer to the allocated SG list */ }; +#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t)) + struct hostdata { struct mscp cp[MAX_MAILBOXES]; /* Mailboxes for this board */ unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */ @@ -508,7 +520,6 @@ unsigned int iocount; /* Total i/o done for this board */ int board_number; /* Number of this board */ char board_name[16]; /* Name of this board */ - char board_id[256]; /* data from INQUIRY on this board */ int in_reset; /* True if board is doing a reset */ int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */ int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */ @@ -518,14 +529,13 @@ struct pci_dev *pdev; /* Always NULL */ unsigned char heads; unsigned char sectors; - - /* slot != 0 for the U24F, slot == 0 for both the U14F and U34F */ - unsigned char slot; + char board_id[256]; /* data from INQUIRY on this board */ }; static struct Scsi_Host *sh[MAX_BOARDS + 1]; static const char *driver_name = "Ux4F"; static char sha[MAX_BOARDS]; +static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; /* Initialize num_boards so that ihdlr can work while detect is in progress */ static unsigned int num_boards = MAX_BOARDS; @@ -550,8 +560,6 @@ #define H2DEV(x) cpu_to_le32(x) #define DEV2H(x) le32_to_cpu(x) -#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0) - static void do_interrupt_handler(int, void *, struct pt_regs *); static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int); static int do_trace = FALSE; @@ -644,13 +652,18 @@ static int board_inquiry(unsigned int j) { struct mscp *cpp; + dma_addr_t id_dma_addr; unsigned int time, limit = 0; + id_dma_addr = pci_map_single(HD(j)->pdev, HD(j)->board_id, + sizeof(HD(j)->board_id), PCI_DMA_BIDIRECTIONAL); cpp = &HD(j)->cp[0]; - memset(cpp, 0, sizeof(struct mscp)); + cpp->cp_dma_addr = pci_map_single(HD(j)->pdev, cpp, sizeof(struct mscp), + PCI_DMA_BIDIRECTIONAL); + memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE); cpp->opcode = OP_HOST_ADAPTER; cpp->xdir = DTD_IN; - cpp->data_address = V2DEV(HD(j)->board_id); + cpp->data_address = H2DEV(id_dma_addr); cpp->data_len = H2DEV(sizeof(HD(j)->board_id)); cpp->cdb_len = 6; cpp->cdb[0] = HA_CMD_INQUIRY; @@ -666,13 +679,15 @@ outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR); /* Store pointer in OGM address bytes */ - outl(V2DEV(cpp), sh[j]->io_port + REG_OGM); + outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM); /* Issue OGM interrupt */ outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR); + spin_unlock_irq(&driver_lock); time = jiffies; while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L); + spin_lock_irq(&driver_lock); if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) { HD(j)->cp_stat[0] = FREE; @@ -680,6 +695,10 @@ return TRUE; } + pci_unmap_single(HD(j)->pdev, cpp->cp_dma_addr, sizeof(struct mscp), + PCI_DMA_BIDIRECTIONAL); + pci_unmap_single(HD(j)->pdev, id_dma_addr, sizeof(HD(j)->board_id), + PCI_DMA_BIDIRECTIONAL); return FALSE; } @@ -817,6 +836,7 @@ HD(j)->heads = mapping_table[config_2.mapping_mode].heads; HD(j)->sectors = mapping_table[config_2.mapping_mode].sectors; HD(j)->subversion = subversion; + HD(j)->pdev = NULL; HD(j)->board_number = j; if (have_old_firmware) sh[j]->sg_tablesize = MAX_SAFE_SGLIST; @@ -864,6 +884,10 @@ else sprintf(dma_name, "DMA %u", dma_channel); for (i = 0; i < sh[j]->can_queue; i++) + HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev, + &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); + + for (i = 0; i < sh[j]->can_queue; i++) if (! ((&HD(j)->cp[i])->sglist = kmalloc( sh[j]->sg_tablesize * sizeof(struct sg_list), (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) { @@ -950,6 +974,9 @@ int u14_34f_detect(Scsi_Host_Template *tpnt) { unsigned int j = 0, k; + unsigned long spin_flags; + + spin_lock_irqsave(&driver_lock, spin_flags); tpnt->proc_name = "u14-34f"; @@ -973,6 +1000,7 @@ } num_boards = j; + spin_unlock_irqrestore(&driver_lock, spin_flags); return j; } @@ -994,10 +1022,10 @@ if (!SCpnt->use_sg) { - if (!SCpnt->request_bufflen) - cpp->data_address = V2DEV(SCpnt->request_buffer); + /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */ + if (!SCpnt->request_bufflen) pci_dir = PCI_DMA_BIDIRECTIONAL; - else if (SCpnt->request_buffer) + if (SCpnt->request_buffer) cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir)); @@ -1016,7 +1044,8 @@ cpp->sg = TRUE; cpp->use_sg = SCpnt->use_sg; - cpp->data_address = V2DEV(cpp->sglist); + cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist, + SCpnt->use_sg * sizeof(struct sg_list), pci_dir)); cpp->data_len = H2DEV(data_len); } @@ -1032,13 +1061,14 @@ pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr), DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - if (SCpnt->use_sg) + if (SCpnt->use_sg) pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); - else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) - pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); + if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; + if (DEV2H(cpp->data_address)) + pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); } static void sync_dma(unsigned int i, unsigned int j) { @@ -1053,14 +1083,15 @@ pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr), DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - if (SCpnt->use_sg) - pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, + if (SCpnt->use_sg) + pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); - else if (DEV2H(cpp->data_address) && DEV2H(cpp->data_len)) - pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); + if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; + if (DEV2H(cpp->data_address)) + pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); } static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) { @@ -1096,7 +1127,7 @@ return; } - if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) + if (SCpnt->sc_data_direction != SCSI_DATA_UNKNOWN) panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j)); cpp->xdir = DTD_IN; @@ -1149,7 +1180,7 @@ /* Set pointer to control packet structure */ cpp = &HD(j)->cp[i]; - memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *)); + memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE); SCpnt->scsi_done = done; cpp->cpp_index = i; SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index; @@ -1188,7 +1219,7 @@ } /* Store pointer in OGM address bytes */ - outl(V2DEV(cpp), sh[j]->io_port + REG_OGM); + outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM); /* Issue OGM interrupt */ outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR); @@ -1598,7 +1629,7 @@ continue; } - outl(V2DEV(cpp), sh[j]->io_port + REG_OGM); + outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM); outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR); HD(j)->cp_stat[k] = IN_USE; } @@ -1636,11 +1667,11 @@ /* Find the mailbox to be serviced on this board */ for (i = 0; i < sh[j]->can_queue; i++) - if (V2DEV(&(HD(j)->cp[i])) == ret) break; + if (H2DEV(HD(j)->cp[i].cp_dma_addr) == ret) break; if (i >= sh[j]->can_queue) panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j), - (void *)ret, (void *)V2DEV(HD(j)->cp)); + (void *)ret, (void *)H2DEV(HD(j)->cp[0].cp_dma_addr)); cpp = &(HD(j)->cp[i]); spp = cpp; @@ -1839,6 +1870,10 @@ for (i = 0; i < sh[j]->can_queue; i++) if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist); + + for (i = 0; i < sh[j]->can_queue; i++) + pci_unmap_single(HD(j)->pdev, HD(j)->cp[i].cp_dma_addr, + sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); free_irq(sh[j]->irq, &sha[j]); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/u14-34f.h linux-2.5/drivers/scsi/u14-34f.h --- linux-2.5.5/drivers/scsi/u14-34f.h Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/scsi/u14-34f.h Tue Feb 26 21:24:49 2002 @@ -13,7 +13,7 @@ int u14_34f_reset(Scsi_Cmnd *); int u14_34f_biosparam(Disk *, kdev_t, int *); -#define U14_34F_VERSION "7.20.00" +#define U14_34F_VERSION "7.22.00" #define ULTRASTOR_14_34F { \ name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/scsi/wd33c93.c linux-2.5/drivers/scsi/wd33c93.c --- linux-2.5.5/drivers/scsi/wd33c93.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/scsi/wd33c93.c Sun Mar 3 17:54:36 2002 @@ -1407,11 +1407,31 @@ -static void reset_wd33c93(struct Scsi_Host *instance) +void reset_wd33c93(struct Scsi_Host *instance) { struct WD33C93_hostdata *hostdata = (struct WD33C93_hostdata *)instance->hostdata; const wd33c93_regs regs = hostdata->regs; uchar sr; + +#ifdef CONFIG_SGI_IP22 +{ +int busycount = 0; +extern void sgiwd93_reset(unsigned long); + /* wait 'til the chip gets some time for us */ + while ((READ_AUX_STAT() & ASR_BSY) && busycount++ < 100) + udelay (10); + /* + * there are scsi devices out there, which manage to lock up + * the wd33c93 in a busy condition. In this state it won't + * accept the reset command. The only way to solve this is to + * give the chip a hardware reset (if possible). The code below + * does this for the SGI Indy, where this is possible + */ + /* still busy ? */ + if (READ_AUX_STAT() & ASR_BSY) + sgiwd93_reset(instance->base); /* yeah, give it the hard one */ +} +#endif write_wd33c93(regs, WD_OWN_ID, OWNID_EAF | OWNID_RAF | instance->this_id | hostdata->clock_freq); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/sgi/char/Makefile linux-2.5/drivers/sgi/char/Makefile --- linux-2.5.5/drivers/sgi/char/Makefile Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/sgi/char/Makefile Sun Mar 3 17:54:36 2002 @@ -9,7 +9,7 @@ O_TARGET := sgichar.o -export-objs := newport.o shmiq.o sgicons.o usema.o +export-objs := newport.o rrm.o shmiq.o sgicons.o usema.o obj-y := newport.o shmiq.o sgicons.o usema.o streamable.o obj-$(CONFIG_SGI_SERIAL) += sgiserial.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/sgi/char/ds1286.c linux-2.5/drivers/sgi/char/ds1286.c --- linux-2.5.5/drivers/sgi/char/ds1286.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/sgi/char/ds1286.c Sun Mar 3 17:54:36 2002 @@ -61,8 +61,9 @@ static unsigned int ds1286_poll(struct file *file, poll_table *wait); -void get_rtc_time (struct rtc_time *rtc_tm); -void get_rtc_alm_time (struct rtc_time *alm_tm); +void ds1286_get_alm_time (struct rtc_time *alm_tm); +void ds1286_get_time(struct rtc_time *rtc_tm); +int ds1286_set_time(struct rtc_time *rtc_tm); void set_rtc_irq_bit(unsigned char bit); void clear_rtc_irq_bit(unsigned char bit); @@ -173,7 +174,7 @@ * tm_min, and tm_sec values are filled in. */ - get_rtc_alm_time(&wtime); + ds1286_get_alm_time(&wtime); break; } case RTC_ALM_SET: /* Store a time into the alarm */ @@ -215,15 +216,12 @@ } case RTC_RD_TIME: /* Read the time/date from RTC */ { - get_rtc_time(&wtime); + ds1286_get_time(&wtime); break; } case RTC_SET_TIME: /* Set the RTC */ { struct rtc_time rtc_tm; - unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned char save_control; - unsigned int yrs, flags; if (!capable(CAP_SYS_TIME)) return -EACCES; @@ -231,57 +229,8 @@ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) return -EFAULT; - - yrs = rtc_tm.tm_year + 1900; - mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ - day = rtc_tm.tm_mday; - hrs = rtc_tm.tm_hour; - min = rtc_tm.tm_min; - sec = rtc_tm.tm_sec; - - if (yrs < 1970) - return -EINVAL; - - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); - - if ((mon > 12) || (day == 0)) - return -EINVAL; - - if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) - return -EINVAL; - - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; - - if ((yrs -= 1940) > 255) /* They are unsigned */ - return -EINVAL; - - if (yrs >= 100) - yrs -= 100; - - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(yrs); - - spin_lock_irqsave(&ds1286_lock, flags); - save_control = CMOS_READ(RTC_CMD); - CMOS_WRITE((save_control|RTC_TE), RTC_CMD); - - CMOS_WRITE(yrs, RTC_YEAR); - CMOS_WRITE(mon, RTC_MONTH); - CMOS_WRITE(day, RTC_DATE); - CMOS_WRITE(hrs, RTC_HOURS); - CMOS_WRITE(min, RTC_MINUTES); - CMOS_WRITE(sec, RTC_SECONDS); - CMOS_WRITE(0, RTC_HUNDREDTH_SECOND); - - CMOS_WRITE(save_control, RTC_CMD); - spin_unlock_irqrestore(&ds1286_lock, flags); - - return 0; + + return ds1286_set_time(&rtc_tm); } default: return -EINVAL; @@ -369,7 +318,7 @@ p = buf; - get_rtc_time(&tm); + ds1286_get_time(&tm); hundredth = CMOS_READ(RTC_HUNDREDTH_SECOND); BCD_TO_BIN(hundredth); @@ -384,7 +333,7 @@ * match any value for that particular field. Values that are * greater than a valid time, but less than 0xc0 shouldn't appear. */ - get_rtc_alm_time(&tm); + ds1286_get_alm_time(&tm); p += sprintf(p, "alarm\t\t: %s ", days[tm.tm_wday]); if (tm.tm_hour <= 24) p += sprintf(p, "%02d:", tm.tm_hour); @@ -441,12 +390,13 @@ return CMOS_READ(RTC_CMD) & RTC_TE; } -void get_rtc_time(struct rtc_time *rtc_tm) + +void ds1286_get_time(struct rtc_time *rtc_tm) { - unsigned long uip_watchdog = jiffies; unsigned char save_control; unsigned int flags; - + unsigned long uip_watchdog = jiffies; + /* * read RTC once any update in progress is done. The update * can take just over 2ms. We wait 10 to 20ms. There is no need to @@ -500,7 +450,66 @@ rtc_tm->tm_mon--; } -void get_rtc_alm_time(struct rtc_time *alm_tm) +int ds1286_set_time(struct rtc_time *rtc_tm) +{ + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned char save_control; + unsigned int yrs, flags; + + + yrs = rtc_tm->tm_year + 1900; + mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm->tm_mday; + hrs = rtc_tm->tm_hour; + min = rtc_tm->tm_min; + sec = rtc_tm->tm_sec; + + if (yrs < 1970) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ((yrs -= 1940) > 255) /* They are unsigned */ + return -EINVAL; + + if (yrs >= 100) + yrs -= 100; + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + + spin_lock_irqsave(&ds1286_lock, flags); + save_control = CMOS_READ(RTC_CMD); + CMOS_WRITE((save_control|RTC_TE), RTC_CMD); + + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DATE); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); + CMOS_WRITE(0, RTC_HUNDREDTH_SECOND); + + CMOS_WRITE(save_control, RTC_CMD); + spin_unlock_irqrestore(&ds1286_lock, flags); + + return 0; +} + +void ds1286_get_alm_time(struct rtc_time *alm_tm) { unsigned char cmd; unsigned int flags; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/sgi/char/sgiserial.c linux-2.5/drivers/sgi/char/sgiserial.c --- linux-2.5.5/drivers/sgi/char/sgiserial.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/sgi/char/sgiserial.c Sun Mar 3 17:54:36 2002 @@ -98,6 +98,7 @@ DECLARE_TASK_QUEUE(tq_serial); struct tty_driver serial_driver, callout_driver; +struct console sgi_console_driver; struct console *sgisercon; static int serial_refcount; @@ -1886,7 +1887,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sgi_console_driver; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -1912,9 +1915,9 @@ callout_driver.subtype = SERIAL_TYPE_CALLOUT; if (tty_register_driver(&serial_driver)) - panic("Couldn't register serial driver\n"); + panic("Couldn't register serial driver"); if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); + panic("Couldn't register callout driver"); save_flags(flags); cli(); @@ -2013,7 +2016,7 @@ if (request_irq(zilog_irq, rs_interrupt, (SA_INTERRUPT), "Zilog8530", zs_chain)) - panic("Unable to attach zs intr\n"); + panic("Unable to attach zs intr"); restore_flags(flags); return 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/tc/lk201.c linux-2.5/drivers/tc/lk201.c --- linux-2.5.5/drivers/tc/lk201.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/tc/lk201.c Sun Mar 3 17:54:36 2002 @@ -4,13 +4,22 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * + * Copyright (C) 2001 Maciej W. Rozycki */ + +#include + #include +#include #include #include #include #include #include +#include +#include + +#include #include #include #include @@ -27,6 +36,8 @@ */ unsigned char lk201_sysrq_xlate[128]; unsigned char *kbd_sysrq_xlate = lk201_sysrq_xlate; + +unsigned char kbd_sysrq_key = -1; #endif #define KEYB_LINE 3 @@ -71,6 +82,8 @@ LK_CMD_LEDS_OFF, LK_PARAM_LED_MASK(0xf) }; +static struct dec_serial* lk201kbd_info; + static int __init lk201_reset(struct dec_serial *info) { int i; @@ -83,9 +96,115 @@ return 0; } +#define DEFAULT_KEYB_REP_DELAY (250/5) /* [5ms] */ +#define DEFAULT_KEYB_REP_RATE 30 /* [cps] */ + +static struct kbd_repeat kbdrate = { + DEFAULT_KEYB_REP_DELAY, + DEFAULT_KEYB_REP_RATE +}; + +static void parse_kbd_rate(struct kbd_repeat *r) +{ + if (r->delay <= 0) + r->delay = kbdrate.delay; + if (r->rate <= 0) + r->rate = kbdrate.rate; + + if (r->delay < 5) + r->delay = 5; + if (r->delay > 630) + r->delay = 630; + if (r->rate < 12) + r->rate = 12; + if (r->rate > 127) + r->rate = 127; + if (r->rate == 125) + r->rate = 124; +} + +static int write_kbd_rate(struct kbd_repeat *rep) +{ + struct dec_serial* info = lk201kbd_info; + int delay, rate; + int i; + + delay = rep->delay / 5; + rate = rep->rate; + for (i = 0; i < 4; i++) { + if (info->hook->poll_tx_char(info, LK_CMD_RPT_RATE(i))) + return 1; + if (info->hook->poll_tx_char(info, LK_PARAM_DELAY(delay))) + return 1; + if (info->hook->poll_tx_char(info, LK_PARAM_RATE(rate))) + return 1; + } + return 0; +} + +static int lk201kbd_rate(struct kbd_repeat *rep) +{ + if (rep == NULL) + return -EINVAL; + + parse_kbd_rate(rep); + + if (write_kbd_rate(rep)) { + memcpy(rep, &kbdrate, sizeof(struct kbd_repeat)); + return -EIO; + } + + memcpy(&kbdrate, rep, sizeof(struct kbd_repeat)); + + return 0; +} + +static void lk201kd_mksound(unsigned int hz, unsigned int ticks) +{ + struct dec_serial* info = lk201kbd_info; + + if (!ticks) + return; + + /* + * Can't set frequency and we "approximate" + * duration by volume. ;-) + */ + ticks /= HZ / 32; + if (ticks > 7) + ticks = 7; + ticks = 7 - ticks; + + if (info->hook->poll_tx_char(info, LK_CMD_ENB_BELL)) + return; + if (info->hook->poll_tx_char(info, LK_PARAM_VOLUME(ticks))) + return; + if (info->hook->poll_tx_char(info, LK_CMD_BELL)) + return; +} + void kbd_leds(unsigned char leds) { - return; + struct dec_serial* info = lk201kbd_info; + unsigned char l = 0; + + if (!info) /* FIXME */ + return; + + /* FIXME -- Only Hold and Lock LEDs for now. --macro */ + if (leds & LED_SCR) + l |= LK_LED_HOLD; + if (leds & LED_CAP) + l |= LK_LED_LOCK; + + if (info->hook->poll_tx_char(info, LK_CMD_LEDS_ON)) + return; + if (info->hook->poll_tx_char(info, LK_PARAM_LED_MASK(l))) + return; + if (info->hook->poll_tx_char(info, LK_CMD_LEDS_OFF)) + return; + if (info->hook->poll_tx_char(info, LK_PARAM_LED_MASK(~l))) + return; } int kbd_setkeycode(unsigned int scancode, unsigned int keycode) @@ -118,7 +237,12 @@ if (!stat || stat == 4) { switch (ch) { - case LK_KEY_ACK: + case LK_STAT_RESUME_ERR: + case LK_STAT_ERROR: + case LK_STAT_INHIBIT_ACK: + case LK_STAT_TEST_ACK: + case LK_STAT_MODE_KEYDOWN: + case LK_STAT_MODE_ACK: break; case LK_KEY_LOCK: shift_state ^= LK_LOCK; @@ -157,6 +281,7 @@ } } else printk("Error reading LKx01 keyboard: 0x%02x\n", stat); + tasklet_schedule(&keyboard_tasklet); } static void __init lk201_info(struct dec_serial *info) @@ -200,6 +325,10 @@ */ info->hook->rx_char = lk201_kbd_rx_char; + lk201kbd_info = info; + kbd_rate = lk201kbd_rate; + kd_mksound = lk201kd_mksound; + return 0; } @@ -231,7 +360,3 @@ printk("LK201 Support for DS3100 not yet ready ...\n"); } } - - - - diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/tc/lk201.h linux-2.5/drivers/tc/lk201.h --- linux-2.5.5/drivers/tc/lk201.h Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/tc/lk201.h Sun Mar 3 17:54:36 2002 @@ -2,52 +2,121 @@ * Commands to the keyboard processor */ -#define LK_PARAM 0x80 /* start/end parameter list */ +#define LK_PARAM 0x80 /* start/end parameter list */ -#define LK_CMD_RESUME 0x8b -#define LK_CMD_INHIBIT 0xb9 -#define LK_CMD_LEDS_ON 0x13 /* 1 param: led bitmask */ -#define LK_CMD_LEDS_OFF 0x11 /* 1 param: led bitmask */ -#define LK_CMD_DIS_KEYCLK 0x99 -#define LK_CMD_ENB_KEYCLK 0x1b /* 1 param: volume */ -#define LK_CMD_DIS_CTLCLK 0xb9 -#define LK_CMD_ENB_CTLCLK 0xbb -#define LK_CMD_SOUND_CLK 0x9f -#define LK_CMD_DIS_BELL 0xa1 -#define LK_CMD_ENB_BELL 0x23 /* 1 param: volume */ -#define LK_CMD_BELL 0xa7 -#define LK_CMD_TMP_NORPT 0xc1 -#define LK_CMD_ENB_RPT 0xe3 -#define LK_CMD_DIS_RPT 0xe1 -#define LK_CMD_RPT_TO_DOWN 0xd9 -#define LK_CMD_REQ_ID 0xab -#define LK_CMD_POWER_UP 0xfd -#define LK_CMD_TEST_MODE 0xcb -#define LK_CMD_SET_DEFAULTS 0xd3 +#define LK_CMD_RESUME 0x8b /* resume transmission to the host */ +#define LK_CMD_INHIBIT 0x89 /* stop transmission to the host */ +#define LK_CMD_LEDS_ON 0x13 /* light LEDs */ + /* 1st param: led bitmask */ +#define LK_CMD_LEDS_OFF 0x11 /* turn off LEDs */ + /* 1st param: led bitmask */ +#define LK_CMD_DIS_KEYCLK 0x99 /* disable the keyclick */ +#define LK_CMD_ENB_KEYCLK 0x1b /* enable the keyclick */ + /* 1st param: volume */ +#define LK_CMD_DIS_CTLCLK 0xb9 /* disable the Ctrl keyclick */ +#define LK_CMD_ENB_CTLCLK 0xbb /* enable the Ctrl keyclick */ +#define LK_CMD_SOUND_CLK 0x9f /* emit a keyclick */ +#define LK_CMD_DIS_BELL 0xa1 /* disable the bell */ +#define LK_CMD_ENB_BELL 0x23 /* enable the bell */ + /* 1st param: volume */ +#define LK_CMD_BELL 0xa7 /* emit a bell */ +#define LK_CMD_TMP_NORPT 0xc1 /* disable typematic */ + /* for the currently pressed key */ +#define LK_CMD_ENB_RPT 0xe3 /* enable typematic */ + /* for RPT_DOWN groups */ +#define LK_CMD_DIS_RPT 0xe1 /* disable typematic */ + /* for RPT_DOWN groups */ +#define LK_CMD_RPT_TO_DOWN 0xd9 /* set RPT_DOWN groups to DOWN */ +#define LK_CMD_REQ_ID 0xab /* request the keyboard ID */ +#define LK_CMD_POWER_UP 0xfd /* init power-up sequence */ +#define LK_CMD_TEST_MODE 0xcb /* enter the factory test mode */ +#define LK_CMD_TEST_EXIT 0x80 /* exit the factory test mode */ +#define LK_CMD_SET_DEFAULTS 0xd3 /* set power-up defaults */ + +#define LK_CMD_MODE(m,div) (LK_PARAM|(((div)&0xf)<<3)|m) + /* select the repeat mode */ + /* for the selected key group */ +#define LK_CMD_MODE_AR(m,div) ((((div)&0xf)<<3)|m) + /* select the repeat mode */ + /* and the repeat register */ + /* for the selected key group */ + /* 1st param: register number */ +#define LK_CMD_RPT_RATE(r) (0x04|((((r)&0x3)<<1))) + /* set the delay and repeat rate */ + /* for the selected repeat register */ + /* 1st param: initial delay */ + /* 2nd param: repeat rate */ /* there are 4 leds, represent them in the low 4 bits of a byte */ -#define LK_PARAM_LED_MASK(ledbmap) (LK_PARAM|(ledbmap)) +#define LK_PARAM_LED_MASK(ledbmap) (LK_PARAM|((ledbmap)&0xf)) +#define LK_LED_WAIT 0x1 /* Wait LED */ +#define LK_LED_COMP 0x2 /* Compose LED */ +#define LK_LED_LOCK 0x4 /* Lock LED */ +#define LK_LED_HOLD 0x8 /* Hold Screen LED */ /* max volume is 0, lowest is 0x7 */ -#define LK_PARAM_VOLUME(v) (LK_PARAM|((v)&0x7)) +#define LK_PARAM_VOLUME(v) (LK_PARAM|((v)&0x7)) -/* mode set command(s) details */ -#define LK_MODE_DOWN 0x0 -#define LK_MODE_RPT_DOWN 0x2 -#define LK_MODE_DOWN_UP 0x6 -#define LK_CMD_MODE(m,div) (LK_PARAM|(div<<3)|m) +/* mode set command details, div is a key group number */ +#define LK_MODE_DOWN 0x0 /* make only */ +#define LK_MODE_RPT_DOWN 0x2 /* make and typematic */ +#define LK_MODE_DOWN_UP 0x6 /* make and release */ + +/* there are 4 repeat registers */ +#define LK_PARAM_AR(r) (LK_PARAM|((v)&0x3)) + +/* + * Mappings between key groups and keycodes are as follows: + * + * 1: 0xbf - 0xfb -- alphanumeric, + * 2: 0x92 - 0xa4 -- numeric keypad, + * 3: 0xbc -- Backspace, + * 4: 0xbd - 0xbe -- Tab, Return, + * 5: 0xb0 - 0xb1 -- Lock, Compose Character, + * 6: 0xae - 0xaf -- Ctrl, Shift, + * 7: 0xa7 - 0xa8 -- Left Arrow, Right Arrow, + * 8: 0xa9 - 0xab -- Up Arrow, Down Arrow, Right Shift, + * 9: 0x8a - 0x8f -- editor keypad, + * 10: 0x56 - 0x5a -- F1 - F5, + * 11: 0x64 - 0x68 -- F6 - F10, + * 12: 0x71 - 0x74 -- F11 - F14, + * 13: 0x7c - 0x7d -- Help, Do, + * 14: 0x80 - 0x83 -- F17 - F20. + * + * Others, i.e. 0x55, 0xac, 0xad, 0xb2, are undiscovered. + */ + +/* delay is 5 - 630 ms; 0x00 and 0x7f are reserved */ +#define LK_PARAM_DELAY(t) ((t)&0x7f) + +/* rate is 12 - 127 Hz; 0x00 - 0x0b and 0x7d (power-up!) are reserved */ +#define LK_PARAM_RATE(r) (LK_PARAM|((r)&0x7f)) #define LK_SHIFT 1<<0 #define LK_CTRL 1<<1 #define LK_LOCK 1<<2 #define LK_COMP 1<<3 -#define LK_KEY_SHIFT 174 -#define LK_KEY_CTRL 175 -#define LK_KEY_LOCK 176 -#define LK_KEY_COMP 177 -#define LK_KEY_RELEASE 179 -#define LK_KEY_REPEAT 180 -#define LK_KEY_ACK 186 +#define LK_KEY_SHIFT 0xae +#define LK_KEY_CTRL 0xaf +#define LK_KEY_LOCK 0xb0 +#define LK_KEY_COMP 0xb1 + +#define LK_KEY_RELEASE 0xb3 /* all keys released */ +#define LK_KEY_REPEAT 0xb4 /* repeat the last key */ + +/* status responses */ +#define LK_STAT_RESUME_ERR 0xb5 /* keystrokes lost while inhibited */ +#define LK_STAT_ERROR 0xb6 /* an invalid command received */ +#define LK_STAT_INHIBIT_ACK 0xb7 /* transmission inhibited */ +#define LK_STAT_TEST_ACK 0xb8 /* the factory test mode entered */ +#define LK_STAT_MODE_KEYDOWN 0xb9 /* a key is down on a change */ + /* to the DOWN_UP mode; */ + /* the keycode follows */ +#define LK_STAT_MODE_ACK 0xba /* the mode command succeeded */ + +#define LK_STAT_PWRUP_OK 0x00 /* the power-up self test OK */ +#define LK_STAT_PWRUP_KDOWN 0x3d /* a key was down during the test */ +#define LK_STAT_PWRUP_ERROR 0x3e /* keyboard self test failure */ -extern unsigned char scancodeRemap[256]; \ No newline at end of file +extern unsigned char scancodeRemap[256]; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/tc/zs.c linux-2.5/drivers/tc/zs.c --- linux-2.5.5/drivers/tc/zs.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/tc/zs.c Sun Mar 3 23:50:42 2002 @@ -443,7 +443,7 @@ if (break_pressed && info->line == sercons.index) { if (ch != 0 && time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); break_pressed = 0; goto ignore_char; } @@ -1472,7 +1472,7 @@ schedule_timeout(char_time); if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } current->state = TASK_RUNNING; @@ -1892,7 +1892,9 @@ serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; - +#ifdef CONFIG_SERIAL_CONSOLE + serial_driver.console = &sercons; +#endif serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; @@ -1924,9 +1926,9 @@ callout_driver.subtype = SERIAL_TYPE_CALLOUT; if (tty_register_driver(&serial_driver)) - panic("Couldn't register serial driver\n"); + panic("Couldn't register serial driver"); if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); + panic("Couldn't register callout driver"); save_flags(flags); cli(); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/telephony/Config.help linux-2.5/drivers/telephony/Config.help --- linux-2.5.5/drivers/telephony/Config.help Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/telephony/Config.help Mon Mar 4 01:21:23 2002 @@ -26,3 +26,8 @@ If you do not have any Quicknet telephony cards, you can safely say N here. +CONFIG_PHONE_IXJ_PCMCIA + Say Y here to configure in PCMCIA service support for the Quicknet + cards manufactured by Quicknet Technologies, Inc. This changes the + card initialization code to work with the card manager daemon. + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/telephony/ixj.c linux-2.5/drivers/telephony/ixj.c --- linux-2.5.5/drivers/telephony/ixj.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/telephony/ixj.c Sun Mar 3 17:54:36 2002 @@ -274,8 +274,8 @@ #include "ixj.h" -#define TYPE(dev) (MINOR(dev) >> 4) -#define NUM(dev) (MINOR(dev) & 0xf) +#define TYPE(dev) (minor(dev) >> 4) +#define NUM(dev) (minor(dev) & 0xf) static int ixjdebug; static int hertz = HZ; @@ -386,7 +386,7 @@ #ifdef PERFMON_STATS #define ixj_perfmon(x) ((x)++) #else -#define ixj_perfmon(x) do {} while(0); +#define ixj_perfmon(x) do { } while(0) #endif static int ixj_convert_loaded; @@ -3450,7 +3450,7 @@ j->cidcw_wait = 0; if(!j->flags.cidcw_ack) { if(ixjdebug & 0x0200) { - printk("IXJ cidcw phone%d did not recieve ACK from display %ld\n", j->board, jiffies); + printk("IXJ cidcw phone%d did not receive ACK from display %ld\n", j->board, jiffies); } ixj_post_cid(j); if(j->cid_play_flag) { @@ -6202,7 +6202,7 @@ IXJ_FILTER_RAW jfr; unsigned int raise, mant; - unsigned int minor = MINOR(inode->i_rdev); + unsigned int minor = minor(inode->i_rdev); int board = NUM(inode->i_rdev); IXJ *j = get_ixj(NUM(inode->i_rdev)); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/Config.help linux-2.5/drivers/usb/Config.help --- linux-2.5.5/drivers/usb/Config.help Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/usb/Config.help Thu Feb 14 02:57:58 2002 @@ -151,6 +151,20 @@ The module will be called wacom.o. If you want to compile it as a module, say M here and read . +CONFIG_USB_POWERMATE + Say Y here if you want to use the Griffin Technology, Inc. USB + PowerMate device. This device is a stainless steel dial which + can measure clockwise and anticlockwise rotation. The dial also + acts as a pushbutton. The base contains an LED which can be + instructed to pulse or to switch to a particular intensity. + + You can download userspace tools from http://sowerbutts.com/powermate/ + + This driver 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 powermate.o. If you want to compile it as a + module, say M here and read . + CONFIG_USB_SCANNER Say Y here if you want to connect a USB scanner to your computer's USB port. Please read and diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/Config.in linux-2.5/drivers/usb/Config.in --- linux-2.5.5/drivers/usb/Config.in Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/usb/Config.in Thu Feb 14 02:57:58 2002 @@ -59,6 +59,7 @@ dep_tristate ' USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT fi dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT + dep_tristate ' Griffin Technology PowerMate support' CONFIG_USB_POWERMATE $CONFIG_USB $CONFIG_INPUT fi comment 'USB Imaging devices' diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/Makefile linux-2.5/drivers/usb/Makefile --- linux-2.5.5/drivers/usb/Makefile Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/usb/Makefile Thu Feb 14 02:57:58 2002 @@ -58,6 +58,7 @@ obj-$(CONFIG_USB_HID) += hid.o obj-$(CONFIG_USB_KBD) += usbkbd.o obj-$(CONFIG_USB_WACOM) += wacom.o +obj-$(CONFIG_USB_POWERMATE) += powermate.o obj-$(CONFIG_USB_SCANNER) += scanner.o obj-$(CONFIG_USB_ACM) += acm.o diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/audio.c linux-2.5/drivers/usb/audio.c --- linux-2.5.5/drivers/usb/audio.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/usb/audio.c Fri Mar 1 15:07:38 2002 @@ -124,9 +124,7 @@ * conversions. We never do sample rate conversion; these are too * expensive to be performed in the kernel. * - * Current status: - * - Pretty stable on UHCI-Acher/Fliegl/Sailer - * - Does not work on OHCI due to lack of OHCI driver supporting URB's + * Current status: no known HCD-specific issues. * * Generally: Due to the brokenness of the Audio Class spec * it seems generally impossible to write a generic Audio Class driver, @@ -298,12 +296,10 @@ struct my_data_urb { struct urb *urb; - struct usb_iso_packet_descriptor isoframe[DESCFRAMES]; }; struct my_sync_urb { struct urb *urb; - struct usb_iso_packet_descriptor isoframe[SYNCFRAMES]; }; @@ -2349,6 +2345,7 @@ if (vma->vm_pgoff != 0) goto out; + vma->vm_flags &= ~VM_IO; ret = dmabuf_mmap(vma, db, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot); out: unlock_kernel(); @@ -2829,14 +2826,14 @@ init_waitqueue_head(&as->usbin.dma.wait); init_waitqueue_head(&as->usbout.dma.wait); spin_lock_init(&as->lock); - as->usbin.durb[0].urb = usb_alloc_urb(0, GFP_KERNEL); - as->usbin.durb[1].urb = usb_alloc_urb(0, GFP_KERNEL); - as->usbin.surb[0].urb = usb_alloc_urb(0, GFP_KERNEL); - as->usbin.surb[1].urb = usb_alloc_urb(0, GFP_KERNEL); - as->usbout.durb[0].urb = usb_alloc_urb(0, GFP_KERNEL); - as->usbout.durb[1].urb = usb_alloc_urb(0, GFP_KERNEL); - as->usbout.surb[0].urb = usb_alloc_urb(0, GFP_KERNEL); - as->usbout.surb[1].urb = usb_alloc_urb(0, GFP_KERNEL); + as->usbin.durb[0].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL); + as->usbin.durb[1].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL); + as->usbin.surb[0].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL); + as->usbin.surb[1].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL); + as->usbout.durb[0].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL); + as->usbout.durb[1].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL); + as->usbout.surb[0].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL); + as->usbout.surb[1].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL); if ((!as->usbin.durb[0].urb) || (!as->usbin.durb[1].urb) || (!as->usbin.surb[0].urb) || diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/auerswald.c linux-2.5/drivers/usb/auerswald.c --- linux-2.5.5/drivers/usb/auerswald.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/usb/auerswald.c Fri Mar 1 15:07:38 2002 @@ -61,7 +61,7 @@ #define ID_AUERSWALD 0x09BF #ifndef AUER_MINOR_BASE /* allow external override */ -#define AUER_MINOR_BASE 80 /* auerswald driver minor number */ +#define AUER_MINOR_BASE 112 /* auerswald driver minor number */ #endif /* we can have up to this number of device plugged in at once */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/devices.c linux-2.5/drivers/usb/devices.c --- linux-2.5.5/drivers/usb/devices.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/usb/devices.c Fri Mar 1 15:07:38 2002 @@ -4,8 +4,6 @@ * (C) Copyright 1999,2000 Thomas Sailer . (proc file per device) * (C) Copyright 1999 Deti Fliegl (new USB architecture) * - * $id$ - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -61,6 +59,8 @@ #include #include +#include "hcd.h" + #define MAX_TOPO_LEVEL 6 /* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */ @@ -429,6 +429,10 @@ * count = device count at this level */ /* If this is the root hub, display the bandwidth information */ + /* FIXME high speed reserves 20% frametime for non-periodic, + * while full/low speed reserves only 10% ... so this is wrong + * for high speed busses. also, change how bandwidth is recorded. + */ if (level == 0) data_end += sprintf(data_end, format_bandwidth, bus->bandwidth_allocated, FRAME_TIME_MAX_USECS_ALLOC, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/hcd/Config.help linux-2.5/drivers/usb/hcd/Config.help --- linux-2.5.5/drivers/usb/hcd/Config.help Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/usb/hcd/Config.help Tue Feb 26 21:24:49 2002 @@ -21,7 +21,6 @@ The module will be called ehci-hcd.o. If you want to compile it as a module, say M here and read . -OHCI (most USB hosts except VIA, Intel PIIX) support CONFIG_USB_OHCI_HCD The Open Host Controller Interface (OHCI) is a standard for accessing USB 1.1 host controller hardware. It does more in hardware than Intel's diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/hcd/ehci-hcd.c linux-2.5/drivers/usb/hcd/ehci-hcd.c --- linux-2.5.5/drivers/usb/hcd/ehci-hcd.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/usb/hcd/ehci-hcd.c Fri Mar 1 15:07:38 2002 @@ -44,6 +44,7 @@ #include #include "../hcd.h" +#include #include #include #include diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/hcd/ehci-hub.c linux-2.5/drivers/usb/hcd/ehci-hub.c --- linux-2.5.5/drivers/usb/hcd/ehci-hub.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/usb/hcd/ehci-hub.c Fri Mar 1 15:07:38 2002 @@ -18,8 +18,6 @@ /* this file is part of ehci-hcd.c */ -#include - /*-------------------------------------------------------------------------*/ /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/hcd/ehci-mem.c linux-2.5/drivers/usb/hcd/ehci-mem.c --- linux-2.5.5/drivers/usb/hcd/ehci-mem.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/usb/hcd/ehci-mem.c Fri Mar 1 15:07:38 2002 @@ -18,8 +18,6 @@ /* this file is part of ehci-hcd.c */ -#include - /*-------------------------------------------------------------------------*/ /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/hcd/ehci-q.c linux-2.5/drivers/usb/hcd/ehci-q.c --- linux-2.5.5/drivers/usb/hcd/ehci-q.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/usb/hcd/ehci-q.c Fri Mar 1 15:07:38 2002 @@ -18,8 +18,6 @@ /* this file is part of ehci-hcd.c */ -#include - /*-------------------------------------------------------------------------*/ /* diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/hcd/ehci-sched.c linux-2.5/drivers/usb/hcd/ehci-sched.c --- linux-2.5.5/drivers/usb/hcd/ehci-sched.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/usb/hcd/ehci-sched.c Fri Mar 1 15:07:38 2002 @@ -20,8 +20,6 @@ /*-------------------------------------------------------------------------*/ -#include "ehci.h" - /* * EHCI scheduled transaction support: interrupt, iso, split iso * These are called "periodic" transactions in the EHCI spec. @@ -394,6 +392,9 @@ } frame += period; } while (frame < ehci->periodic_size); + + /* update bandwidth utilization records (for usbfs) */ + usb_claim_bandwidth (urb->dev, urb, usecs, 0); /* maybe enable periodic schedule processing */ if (!ehci->periodic_urbs++) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/hcd/ohci-hcd.c linux-2.5/drivers/usb/hcd/ohci-hcd.c --- linux-2.5.5/drivers/usb/hcd/ohci-hcd.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/usb/hcd/ohci-hcd.c Sat Feb 16 13:01:38 2002 @@ -476,7 +476,7 @@ // FIXME cleanup return -ENODEV; } - + return 0; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/hcd/ohci-q.c linux-2.5/drivers/usb/hcd/ohci-q.c --- linux-2.5.5/drivers/usb/hcd/ohci-q.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/usb/hcd/ohci-q.c Fri Mar 1 15:07:38 2002 @@ -8,8 +8,6 @@ * $Id: ohci-q.c,v 1.6 2002/01/19 00:23:15 dbrownell Exp $ */ -#include - static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) { int last = urb_priv->length - 1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/hcd.c linux-2.5/drivers/usb/hcd.c --- linux-2.5.5/drivers/usb/hcd.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/usb/hcd.c Fri Mar 1 15:07:38 2002 @@ -1,5 +1,11 @@ /* - * Copyright (c) 2001 by David Brownell + * (C) Copyright Linus Torvalds 1999 + * (C) Copyright Johannes Erdfelt 1999-2001 + * (C) Copyright Andreas Gal 1999 + * (C) Copyright Gregory P. Smith 1999 + * (C) Copyright Deti Fliegl 1999 + * (C) Copyright Randy Dunlap 2000 + * (C) Copyright David Brownell 2000-2002 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -33,9 +39,6 @@ #include #include /* for UTS_SYSNAME */ -#ifndef CONFIG_USB_DEBUG - #define CONFIG_USB_DEBUG /* this is experimental! */ -#endif #ifdef CONFIG_USB_DEBUG #define DEBUG @@ -53,6 +56,8 @@ #include +// #define USB_BANDWIDTH_MESSAGES + /*-------------------------------------------------------------------------*/ /* @@ -78,19 +83,28 @@ * usb client device drivers. * * Contributors of ideas or unattributed patches include: David Brownell, - * Roman Weissgaerber, Rory Bolt, ... + * Roman Weissgaerber, Rory Bolt, Greg Kroah-Hartman, ... * * HISTORY: + * 2002-02-21 Pull in most of the usb_bus support from usb.c; some + * associated cleanup. "usb_hcd" still != "usb_bus". * 2001-12-12 Initial patch version for Linux 2.5.1 kernel. */ /*-------------------------------------------------------------------------*/ /* host controllers we manage */ -static LIST_HEAD (hcd_list); +LIST_HEAD (usb_bus_list); + +/* used when allocating bus numbers */ +#define USB_MAXBUS 64 +struct usb_busmap { + unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))]; +}; +static struct usb_busmap busmap; /* used when updating list of hcds */ -static DECLARE_MUTEX (hcd_list_lock); +DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */ /* used when updating hcd data */ static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; @@ -105,6 +119,9 @@ /*-------------------------------------------------------------------------*/ +#define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff) +#define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff) + /* usb 2.0 root hub device descriptor */ static const u8 usb2_rh_dev_descriptor [18] = { 0x12, /* __u8 bLength; */ @@ -118,7 +135,7 @@ 0x00, 0x00, /* __u16 idVendor; */ 0x00, 0x00, /* __u16 idProduct; */ - 0x40, 0x02, /* __u16 bcdDevice; (v2.4) */ + KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ 0x03, /* __u8 iManufacturer; */ 0x02, /* __u8 iProduct; */ @@ -141,7 +158,7 @@ 0x00, 0x00, /* __u16 idVendor; */ 0x00, 0x00, /* __u16 idProduct; */ - 0x40, 0x02, /* __u16 bcdDevice; (v2.4) */ + KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ 0x03, /* __u8 iManufacturer; */ 0x02, /* __u8 iProduct; */ @@ -506,6 +523,346 @@ /*-------------------------------------------------------------------------*/ +/* exported only within usbcore */ +void usb_bus_get (struct usb_bus *bus) +{ + atomic_inc (&bus->refcnt); +} + +/* exported only within usbcore */ +void usb_bus_put (struct usb_bus *bus) +{ + if (atomic_dec_and_test (&bus->refcnt)) + kfree (bus); +} + +/*-------------------------------------------------------------------------*/ + +/* shared initialization code */ +static void usb_init_bus (struct usb_bus *bus) +{ + memset (&bus->devmap, 0, sizeof(struct usb_devmap)); + +#ifdef DEVNUM_ROUND_ROBIN + bus->devnum_next = 1; +#endif /* DEVNUM_ROUND_ROBIN */ + + bus->root_hub = NULL; + bus->hcpriv = NULL; + bus->busnum = -1; + bus->bandwidth_allocated = 0; + bus->bandwidth_int_reqs = 0; + bus->bandwidth_isoc_reqs = 0; + + INIT_LIST_HEAD (&bus->bus_list); + + atomic_set (&bus->refcnt, 1); +} + +/** + * usb_alloc_bus - creates a new USB host controller structure + * @op: pointer to a struct usb_operations that this bus structure should use + * Context: !in_interrupt() + * + * Creates a USB host controller bus structure with the specified + * usb_operations and initializes all the necessary internal objects. + * + * If no memory is available, NULL is returned. + * + * The caller should call usb_free_bus() when it is finished with the structure. + */ +struct usb_bus *usb_alloc_bus (struct usb_operations *op) +{ + struct usb_bus *bus; + + bus = kmalloc (sizeof *bus, GFP_KERNEL); + if (!bus) + return NULL; + usb_init_bus (bus); + bus->op = op; + return bus; +} +EXPORT_SYMBOL (usb_alloc_bus); + +/** + * usb_free_bus - frees the memory used by a bus structure + * @bus: pointer to the bus to free + * + * To be invoked by a HCD, only as the last step of decoupling from + * hardware. It is an error to call this if the reference count is + * anything but one. That would indicate that some system component + * did not correctly shut down, and thought the hardware was still + * accessible. + */ +void usb_free_bus (struct usb_bus *bus) +{ + if (!bus) + return; + if (atomic_read (&bus->refcnt) != 1) + err ("usb_free_bus #%d, count != 1", bus->busnum); + usb_bus_put (bus); +} +EXPORT_SYMBOL (usb_free_bus); + +/*-------------------------------------------------------------------------*/ + +/** + * usb_register_bus - registers the USB host controller with the usb core + * @bus: pointer to the bus to register + * Context: !in_interrupt() + * + * Assigns a bus number, and links the controller into usbcore data + * structures so that it can be seen by scanning the bus list. + */ +void usb_register_bus(struct usb_bus *bus) +{ + int busnum; + + down (&usb_bus_list_lock); + busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); + if (busnum < USB_MAXBUS) { + set_bit (busnum, busmap.busmap); + bus->busnum = busnum; + } else + warn ("too many buses"); + + usb_bus_get (bus); + + /* Add it to the list of buses */ + list_add (&bus->bus_list, &usb_bus_list); + up (&usb_bus_list_lock); + + usbfs_add_bus (bus); + + info ("new USB bus registered, assigned bus number %d", bus->busnum); +} +EXPORT_SYMBOL (usb_register_bus); + +/** + * usb_deregister_bus - deregisters the USB host controller + * @bus: pointer to the bus to deregister + * Context: !in_interrupt() + * + * Recycles the bus number, and unlinks the controller from usbcore data + * structures so that it won't be seen by scanning the bus list. + */ +void usb_deregister_bus (struct usb_bus *bus) +{ + info ("USB bus %d deregistered", bus->busnum); + + /* + * NOTE: make sure that all the devices are removed by the + * controller code, as well as having it call this when cleaning + * itself up + */ + down (&usb_bus_list_lock); + list_del (&bus->bus_list); + up (&usb_bus_list_lock); + + usbfs_remove_bus (bus); + + clear_bit (bus->busnum, busmap.busmap); + + usb_bus_put (bus); +} +EXPORT_SYMBOL (usb_deregister_bus); + +/** + * usb_register_root_hub - called by HCD to register its root hub + * @usb_dev: the usb root hub device to be registered. + * @parent_dev: the parent device of this root hub. + * + * The USB host controller calls this function to register the root hub + * properly with the USB subsystem. It sets up the device properly in + * the driverfs tree, and then calls usb_new_device() to register the + * usb device. + */ +int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev) +{ + int retval; + + usb_dev->dev.parent = parent_dev; + strcpy (&usb_dev->dev.name[0], "usb_name"); + strcpy (&usb_dev->dev.bus_id[0], "usb_bus"); + retval = usb_new_device (usb_dev); + if (retval) + put_device (&usb_dev->dev); + return retval; +} +EXPORT_SYMBOL (usb_register_root_hub); + + +/*-------------------------------------------------------------------------*/ + +/* + * usb_calc_bus_time: + * Returns approximate bus time in nanoseconds for a periodic transaction. + * See USB 2.0 spec section 5.11.3 + */ +static long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount) +{ + unsigned long tmp; + + switch (speed) { + case USB_SPEED_LOW: /* INTR only */ + if (is_input) { + tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + } else { + tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + } + case USB_SPEED_FULL: /* ISOC or INTR */ + if (isoc) { + tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); + } else { + tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (9107L + BW_HOST_DELAY + tmp); + } + case USB_SPEED_HIGH: /* ISOC or INTR */ + // FIXME merge from EHCI code; caller will need to handle + // each part of a split separately. + return 0; + default: + dbg ("bogus device speed!"); + return -1; + } +} + +/* + * usb_check_bandwidth(): + * + * old_alloc is from host_controller->bandwidth_allocated in microseconds; + * bustime is from calc_bus_time(), but converted to microseconds. + * + * returns if successful, + * or -ENOSPC if bandwidth request fails. + * + * FIXME: + * This initial implementation does not use Endpoint.bInterval + * in managing bandwidth allocation. + * It probably needs to be expanded to use Endpoint.bInterval. + * This can be done as a later enhancement (correction). + * + * This will also probably require some kind of + * frame allocation tracking...meaning, for example, + * that if multiple drivers request interrupts every 10 USB frames, + * they don't all have to be allocated at + * frame numbers N, N+10, N+20, etc. Some of them could be at + * N+11, N+21, N+31, etc., and others at + * N+12, N+22, N+32, etc. + * + * Similarly for isochronous transfers... + * + * Individual HCDs can schedule more directly ... this logic + * is not correct for high speed transfers. + */ +int usb_check_bandwidth (struct usb_device *dev, struct urb *urb) +{ + unsigned int pipe = urb->pipe; + long bustime; + int is_in = usb_pipein (pipe); + int is_iso = usb_pipeisoc (pipe); + int old_alloc = dev->bus->bandwidth_allocated; + int new_alloc; + + + bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso, + usb_maxpacket (dev, pipe, !is_in))); + if (is_iso) + bustime /= urb->number_of_packets; + + new_alloc = old_alloc + (int) bustime; + if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) { +#ifdef DEBUG + char *mode = +#ifdef CONFIG_USB_BANDWIDTH + ""; +#else + "would have "; +#endif + dbg ("usb_check_bandwidth %sFAILED: %d + %ld = %d usec", + mode, old_alloc, bustime, new_alloc); +#endif +#ifdef CONFIG_USB_BANDWIDTH + bustime = -ENOSPC; /* report error */ +#endif + } + + return bustime; +} +EXPORT_SYMBOL (usb_check_bandwidth); + + +/** + * usb_claim_bandwidth - records bandwidth for a periodic transfer + * @dev: source/target of request + * @urb: request (urb->dev == dev) + * @bustime: bandwidth consumed, in (average) microseconds per frame + * @isoc: true iff the request is isochronous + * + * Bus bandwidth reservations are recorded purely for diagnostic purposes. + * HCDs are expected not to overcommit periodic bandwidth, and to record such + * reservations whenever endpoints are added to the periodic schedule. + * + * FIXME averaging per-frame is suboptimal. Better to sum over the HCD's + * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable + * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how + * large its periodic schedule is. + */ +void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc) +{ + dev->bus->bandwidth_allocated += bustime; + if (isoc) + dev->bus->bandwidth_isoc_reqs++; + else + dev->bus->bandwidth_int_reqs++; + urb->bandwidth = bustime; + +#ifdef USB_BANDWIDTH_MESSAGES + dbg ("bandwidth alloc increased by %d (%s) to %d for %d requesters", + bustime, + isoc ? "ISOC" : "INTR", + dev->bus->bandwidth_allocated, + dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); +#endif +} +EXPORT_SYMBOL (usb_claim_bandwidth); + + +/** + * usb_release_bandwidth - reverses effect of usb_claim_bandwidth() + * @dev: source/target of request + * @urb: request (urb->dev == dev) + * @isoc: true iff the request is isochronous + * + * This records that previously allocated bandwidth has been released. + * Bandwidth is released when endpoints are removed from the host controller's + * periodic schedule. + */ +void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc) +{ + dev->bus->bandwidth_allocated -= urb->bandwidth; + if (isoc) + dev->bus->bandwidth_isoc_reqs--; + else + dev->bus->bandwidth_int_reqs--; + +#ifdef USB_BANDWIDTH_MESSAGES + dbg ("bandwidth alloc reduced by %d (%s) to %d for %d requesters", + urb->bandwidth, + isoc ? "ISOC" : "INTR", + dev->bus->bandwidth_allocated, + dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); +#endif + urb->bandwidth = 0; +} +EXPORT_SYMBOL (usb_release_bandwidth); + + +/*-------------------------------------------------------------------------*/ + #ifdef CONFIG_PCI /* PCI-based HCs are normal, but custom bus glue should be ok */ @@ -522,6 +879,7 @@ * usb_hcd_pci_probe - initialize PCI-based HCDs * @dev: USB Host Controller being probed * @id: pci hotplug id connecting controller to HCD framework + * Context: !in_interrupt() * * Allocates basic PCI resources for this USB host controller, and * then invokes the start() method for the HCD associated with it @@ -535,7 +893,6 @@ unsigned long resource, len; void *base; u8 latency, limit; - struct usb_bus *bus; struct usb_hcd *hcd; int retval, region; char buf [8], *bufp = buf; @@ -631,7 +988,6 @@ != 0) { err ("request interrupt %s failed", bufp); retval = -EBUSY; -clean_3: driver->hcd_free (hcd); goto clean_2; } @@ -643,26 +999,15 @@ (driver->flags & HCD_MEMORY) ? "pci mem" : "io base", base); -// FIXME simpler: make "bus" be that data, not pointer to it. - bus = usb_alloc_bus (&hcd_operations); - if (bus == NULL) { - dbg ("usb_alloc_bus fail"); - retval = -ENOMEM; - free_irq (dev->irq, hcd); - goto clean_3; - } - hcd->bus = bus; + usb_init_bus (&hcd->self); + hcd->self.op = &hcd_operations; + hcd->self.hcpriv = (void *) hcd; + hcd->bus = &hcd->self; hcd->bus_name = dev->slot_name; - bus->hcpriv = (void *) hcd; INIT_LIST_HEAD (&hcd->dev_list); - INIT_LIST_HEAD (&hcd->hcd_list); - down (&hcd_list_lock); - list_add (&hcd->hcd_list, &hcd_list); - up (&hcd_list_lock); - - usb_register_bus (bus); + usb_register_bus (&hcd->self); if ((retval = driver->start (hcd)) < 0) usb_hcd_pci_remove (dev); @@ -678,6 +1023,7 @@ /** * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs * @dev: USB Host Controller being removed + * Context: !in_interrupt() * * Reverses the effect of usb_hcd_pci_probe(), first invoking * the HCD's stop() method. It is always called from a thread @@ -717,12 +1063,9 @@ pci_resource_len (dev, hcd->region)); } - down (&hcd_list_lock); - list_del (&hcd->hcd_list); - up (&hcd_list_lock); - usb_deregister_bus (hcd->bus); - usb_free_bus (hcd->bus); + if (atomic_read (&hcd->self.refcnt) != 1) + err ("usb_hcd_pci_remove %s, count != 1", hcd->bus_name); hcd->bus = NULL; hcd->driver->hcd_free (hcd); @@ -1257,6 +1600,7 @@ * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB * @urb: urb being returned to the USB device driver. + * Context: in_interrupt() * * This hands the URB from HCD to its USB device driver, using its * completion function. The HCD has freed all per-urb resources @@ -1279,16 +1623,9 @@ struct usb_device *dev; /* Release periodic transfer bandwidth */ - if (urb->bandwidth) { - switch (usb_pipetype (urb->pipe)) { - case PIPE_INTERRUPT: - usb_release_bandwidth (urb->dev, urb, 0); - break; - case PIPE_ISOCHRONOUS: - usb_release_bandwidth (urb->dev, urb, 1); - break; - } - } + if (urb->bandwidth) + usb_release_bandwidth (urb->dev, urb, + usb_pipeisoc (urb->pipe)); /* clear all state linking urb to this dev (and hcd) */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/hcd.h linux-2.5/drivers/usb/hcd.h --- linux-2.5.5/drivers/usb/hcd.h Thu Feb 21 17:47:31 2002 +++ linux-2.5/drivers/usb/hcd.h Tue Mar 5 13:43:54 2002 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2001 by David Brownell - * + * Copyright (c) 2001-2002 by David Brownell + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -17,6 +17,8 @@ */ +#ifdef __KERNEL__ + /*-------------------------------------------------------------------------*/ /* @@ -33,8 +35,8 @@ /* * housekeeping */ - struct usb_bus *bus; /* hcd is-a bus */ - struct list_head hcd_list; + struct usb_bus *bus; /* FIXME only use "self" */ + struct usb_bus self; /* hcd is-a bus */ const char *bus_name; @@ -98,6 +100,19 @@ /*-------------------------------------------------------------------------*/ +/* + * FIXME usb_operations should vanish or become hc_driver, + * when usb_bus and usb_hcd become the same thing. + */ + +struct usb_operations { + int (*allocate)(struct usb_device *); + int (*deallocate)(struct usb_device *); + int (*get_frame_number) (struct usb_device *usb_dev); + int (*submit_urb) (struct urb *urb, int mem_flags); + int (*unlink_urb) (struct urb *urb); +}; + /* each driver provides one of these, and hardware init support */ struct hc_driver { @@ -126,8 +141,6 @@ /* return current frame number */ int (*get_frame_number) (struct usb_hcd *hcd); -// FIXME: rework generic-to-specific HCD linkage (specific contains generic) - /* memory lifecycle */ struct usb_hcd *(*hcd_alloc) (void); void (*hcd_free) (struct usb_hcd *hcd); @@ -152,7 +165,8 @@ extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb); #ifdef CONFIG_PCI - +struct pci_dev; +struct pci_device_id; extern int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id); extern void usb_hcd_pci_remove (struct pci_dev *dev); @@ -206,6 +220,59 @@ /*-------------------------------------------------------------------------*/ +/* + * Generic bandwidth allocation constants/support + */ +#define FRAME_TIME_USECS 1000L +#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */ + /* Trying not to use worst-case bit-stuffing + of (7/6 * 8 * bytecount) = 9.33 * bytecount */ + /* bytecount = data payload byte count */ + +#define NS_TO_US(ns) ((ns + 500L) / 1000L) + /* convert & round nanoseconds to microseconds */ + +extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, + int bustime, int isoc); +extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, + int isoc); + +/* + * Full/low speed bandwidth allocation constants/support. + */ +#define BW_HOST_DELAY 1000L /* nanoseconds */ +#define BW_HUB_LS_SETUP 333L /* nanoseconds */ + /* 4 full-speed bit times (est.) */ + +#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */ +#define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L) +#define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L) + +extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb); + +/*-------------------------------------------------------------------------*/ + +extern struct usb_bus *usb_alloc_bus (struct usb_operations *); +extern void usb_free_bus (struct usb_bus *); + +extern void usb_register_bus (struct usb_bus *); +extern void usb_deregister_bus (struct usb_bus *); + +extern int usb_register_root_hub (struct usb_device *usb_dev, + struct device *parent_dev); + +/*-------------------------------------------------------------------------*/ + +/* exported only within usbcore */ + +extern struct list_head usb_bus_list; +extern struct semaphore usb_bus_list_lock; + +extern void usb_bus_get (struct usb_bus *bus); +extern void usb_bus_put (struct usb_bus *bus); + +/*-------------------------------------------------------------------------*/ + /* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */ // bleech -- resurfaced in 2.4.11 or 2.4.12 #define bitmap DeviceRemovable @@ -217,3 +284,7 @@ #define RUN_CONTEXT (in_irq () ? "in_irq" \ : (in_interrupt () ? "in_interrupt" : "can sleep")) + + +#endif /* __KERNEL__ */ + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/hid-core.c linux-2.5/drivers/usb/hid-core.c --- linux-2.5.5/drivers/usb/hid-core.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/usb/hid-core.c Fri Mar 1 15:07:38 2002 @@ -1431,10 +1431,15 @@ { struct hid_device *hid = ptr; + dbg("cleanup called"); usb_unlink_urb(hid->urbin); usb_unlink_urb(hid->urbout); usb_unlink_urb(hid->urbctrl); + usb_free_urb(hid->urbin); + usb_free_urb(hid->urbctrl); + if (hid->urbout) + usb_free_urb(hid->urbout); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(hid); @@ -1442,17 +1447,12 @@ if (hid->claimed & HID_CLAIMED_HIDDEV) hiddev_disconnect(hid); #endif - - usb_free_urb(hid->urbin); - usb_free_urb(hid->urbctrl); - if (hid->urbout) - usb_free_urb(hid->urbout); - hid_free_device(hid); } static struct usb_device_id hid_usb_ids [] = { - { bInterfaceClass: USB_INTERFACE_CLASS_HID }, + { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS, + bInterfaceClass: USB_INTERFACE_CLASS_HID }, { } /* Terminating entry */ }; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/hub.c linux-2.5/drivers/usb/hub.c --- linux-2.5.5/drivers/usb/hub.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/usb/hub.c Tue Feb 26 21:24:49 2002 @@ -644,6 +644,49 @@ port + 1, hub->devpath, ret); } +/* USB 2.0 spec, 7.1.7.3 / fig 7-29: + * + * Between connect detection and reset signaling there must be a delay + * of 100ms at least for debounce and power-settling. The corresponding + * timer shall restart whenever the downstream port detects a disconnect. + * + * Apparently there are some bluetooth and irda-dongles and a number + * of low-speed devices which require longer delays of about 200-400ms. + * Not covered by the spec - but easy to deal with. + * + * This implementation uses 400ms minimum debounce timeout and checks + * every 10ms for transient disconnects to restart the delay. + */ + +#define HUB_DEBOUNCE_TIMEOUT 400 +#define HUB_DEBOUNCE_STEP 10 + +/* return: -1 on error, 0 on success, 1 on disconnect. */ +static int usb_hub_port_debounce(struct usb_device *hub, int port) +{ + int ret; + unsigned delay_time; + u16 portchange, portstatus; + + for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; /* empty */ ) { + + /* wait debounce step increment */ + wait_ms(HUB_DEBOUNCE_STEP); + + ret = usb_hub_port_status(hub, port, &portstatus, &portchange); + if (ret < 0) + return -1; + + if ((portchange & USB_PORT_STAT_C_CONNECTION)) { + usb_clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION); + delay_time = 0; + } + else + delay_time += HUB_DEBOUNCE_STEP; + } + return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1; +} + static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port, u16 portstatus, u16 portchange) { @@ -671,12 +714,16 @@ return; } + if (usb_hub_port_debounce(hub, port)) { + err("connect-debounce failed, port %d disabled", port+1); + usb_hub_port_disable(hub, port); + return; + } + /* Some low speed devices have problems with the quick delay, so */ /* be a bit pessimistic with those devices. RHbug #23670 */ - if (portstatus & USB_PORT_STAT_LOW_SPEED) { - wait_ms(400); + if (portstatus & USB_PORT_STAT_LOW_SPEED) delay = HUB_LONG_RESET_TIME; - } down(&usb_address0_sem); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/hub.h linux-2.5/drivers/usb/hub.h --- linux-2.5.5/drivers/usb/hub.h Thu Feb 21 17:47:30 2002 +++ linux-2.5/drivers/usb/hub.h Tue Mar 5 13:43:54 2002 @@ -9,6 +9,7 @@ */ #include +#include /* likely()/unlikely() */ /* * Hub request types diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/inode.c linux-2.5/drivers/usb/inode.c --- linux-2.5.5/drivers/usb/inode.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/usb/inode.c Thu Feb 21 01:26:10 2002 @@ -65,9 +65,9 @@ { char *curopt = NULL, *value; - if (data) - curopt = strtok(data, ","); - for (; curopt; curopt = strtok(NULL, ",")) { + while ((curopt = strsep(&data, ",")) != NULL) { + if (!*curopt) + continue; if ((value = strchr(curopt, '=')) != NULL) *value++ = 0; if (!strcmp(curopt, "devuid")) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/ov511.c linux-2.5/drivers/usb/ov511.c --- linux-2.5.5/drivers/usb/ov511.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/usb/ov511.c Tue Feb 26 21:24:49 2002 @@ -58,7 +58,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.48a for Linux 2.4" +#define DRIVER_VERSION "v1.49 for Linux 2.5" #define EMAIL "mmcclell@bigfoot.com" #define DRIVER_AUTHOR "Mark McClelland & Bret Wallach \ & Orion Sky Lawlor & Kevin Moore & Charl P. Botha \ @@ -309,7 +309,7 @@ static inline int sensor_get_picture(struct usb_ov511 *, struct video_picture *); static int sensor_get_exposure(struct usb_ov511 *, unsigned char *); -static int ov511_control_ioctl(struct inode *, struct file *, unsigned int, +static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int, unsigned long); /********************************************************************** @@ -332,6 +332,7 @@ { 100, "Lifeview RoboCam" }, { 102, "AverMedia InterCam Elite" }, { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */ + { 192, "Webeye 2000B" }, { -1, NULL } }; @@ -373,17 +374,20 @@ static unsigned char yQuanTable518[] = OV518_YQUANTABLE; static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE; +/********************************************************************** + * Memory management + **********************************************************************/ + /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); return ret; } @@ -392,12 +396,9 @@ rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (!mem) return NULL; @@ -405,13 +406,9 @@ memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; @@ -420,23 +417,16 @@ static void rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - adr=(unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + adr = (unsigned long) mem; + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree(mem); } @@ -452,7 +442,7 @@ extern struct proc_dir_entry *video_proc_entry; static struct file_operations ov511_control_fops = { - ioctl: ov511_control_ioctl, + ioctl: ov51x_control_ioctl, }; #define YES_NO(x) ((x) ? "yes" : "no") @@ -464,29 +454,29 @@ { char *out = page; int i, j, len; - struct usb_ov511 *ov511 = data; + struct usb_ov511 *ov = data; struct video_picture p; unsigned char exp; - if (!ov511 || !ov511->dev) + if (!ov || !ov->dev) return -ENODEV; - sensor_get_picture(ov511, &p); - sensor_get_exposure(ov511, &exp); + sensor_get_picture(ov, &p); + sensor_get_exposure(ov, &exp); /* IMPORTANT: This output MUST be kept under PAGE_SIZE * or we need to get more sophisticated. */ out += sprintf(out, "driver_version : %s\n", DRIVER_VERSION); - out += sprintf(out, "custom_id : %d\n", ov511->customid); - out += sprintf(out, "model : %s\n", ov511->desc ? - clist[ov511->desc].description : "unknown"); - out += sprintf(out, "streaming : %s\n", YES_NO(ov511->streaming)); - out += sprintf(out, "grabbing : %s\n", YES_NO(ov511->grabbing)); - out += sprintf(out, "compress : %s\n", YES_NO(ov511->compress)); - out += sprintf(out, "subcapture : %s\n", YES_NO(ov511->sub_flag)); + out += sprintf(out, "custom_id : %d\n", ov->customid); + out += sprintf(out, "model : %s\n", ov->desc ? + clist[ov->desc].description : "unknown"); + out += sprintf(out, "streaming : %s\n", YES_NO(ov->streaming)); + out += sprintf(out, "grabbing : %s\n", YES_NO(ov->grabbing)); + out += sprintf(out, "compress : %s\n", YES_NO(ov->compress)); + out += sprintf(out, "subcapture : %s\n", YES_NO(ov->sub_flag)); out += sprintf(out, "sub_size : %d %d %d %d\n", - ov511->subx, ov511->suby, ov511->subw, ov511->subh); + ov->subx, ov->suby, ov->subw, ov->subh); out += sprintf(out, "data_format : %s\n", force_rgb ? "RGB" : "BGR"); out += sprintf(out, "brightness : %d\n", p.brightness >> 8); @@ -498,12 +488,12 @@ for (i = 0; i < OV511_NUMFRAMES; i++) { out += sprintf(out, "frame : %d\n", i); out += sprintf(out, " depth : %d\n", - ov511->frame[i].depth); + ov->frame[i].depth); out += sprintf(out, " size : %d %d\n", - ov511->frame[i].width, ov511->frame[i].height); + ov->frame[i].width, ov->frame[i].height); out += sprintf(out, " format : "); for (j = 0; plist[j].num >= 0; j++) { - if (plist[j].num == ov511->frame[i].format) { + if (plist[j].num == ov->frame[i].format) { out += sprintf(out, "%s\n", plist[j].name); break; } @@ -511,29 +501,28 @@ if (plist[j].num < 0) out += sprintf(out, "unknown\n"); out += sprintf(out, " data_buffer : 0x%p\n", - ov511->frame[i].data); + ov->frame[i].data); } - out += sprintf(out, "snap_enabled : %s\n", - YES_NO(ov511->snap_enabled)); + out += sprintf(out, "snap_enabled : %s\n", YES_NO(ov->snap_enabled)); out += sprintf(out, "bridge : %s\n", - ov511->bridge == BRG_OV511 ? "OV511" : - ov511->bridge == BRG_OV511PLUS ? "OV511+" : - ov511->bridge == BRG_OV518 ? "OV518" : - ov511->bridge == BRG_OV518PLUS ? "OV518+" : + ov->bridge == BRG_OV511 ? "OV511" : + ov->bridge == BRG_OV511PLUS ? "OV511+" : + ov->bridge == BRG_OV518 ? "OV518" : + ov->bridge == BRG_OV518PLUS ? "OV518+" : "unknown"); out += sprintf(out, "sensor : %s\n", - ov511->sensor == SEN_OV6620 ? "OV6620" : - ov511->sensor == SEN_OV6630 ? "OV6630" : - ov511->sensor == SEN_OV7610 ? "OV7610" : - ov511->sensor == SEN_OV7620 ? "OV7620" : - ov511->sensor == SEN_OV7620AE ? "OV7620AE" : - ov511->sensor == SEN_OV8600 ? "OV8600" : - ov511->sensor == SEN_KS0127 ? "KS0127" : - ov511->sensor == SEN_KS0127B ? "KS0127B" : - ov511->sensor == SEN_SAA7111A ? "SAA7111A" : + ov->sensor == SEN_OV6620 ? "OV6620" : + ov->sensor == SEN_OV6630 ? "OV6630" : + ov->sensor == SEN_OV7610 ? "OV7610" : + ov->sensor == SEN_OV7620 ? "OV7620" : + ov->sensor == SEN_OV7620AE ? "OV7620AE" : + ov->sensor == SEN_OV8600 ? "OV8600" : + ov->sensor == SEN_KS0127 ? "KS0127" : + ov->sensor == SEN_KS0127B ? "KS0127B" : + ov->sensor == SEN_SAA7111A ? "SAA7111A" : "unknown"); - out += sprintf(out, "packet_size : %d\n", ov511->packet_size); - out += sprintf(out, "framebuffer : 0x%p\n", ov511->fbuf); + out += sprintf(out, "packet_size : %d\n", ov->packet_size); + out += sprintf(out, "framebuffer : 0x%p\n", ov->fbuf); len = out - page; len -= off; @@ -566,16 +555,16 @@ { char *out = page; int len, status; - struct usb_ov511 *ov511 = data; + struct usb_ov511 *ov = data; - if (!ov511 || !ov511->dev) + if (!ov || !ov->dev) return -ENODEV; - status = ov51x_check_snapshot(ov511); + status = ov51x_check_snapshot(ov); out += sprintf(out, "%d", status); if (status) - ov51x_clear_snapshot(ov511); + ov51x_clear_snapshot(ov); len = out - page; len -= off; @@ -717,18 +706,22 @@ * **********************************************************************/ +/* Write an OV51x register */ static int -ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value) +reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { int rc; PDEBUG(5, "0x%02X:0x%02X", reg, value); - rc = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), + down(&ov->cbuf_lock); + ov->cbuf[0] = value; + rc = usb_control_msg(ov->dev, + usb_sndctrlpipe(ov->dev, 0), 2 /* REG_IO */, USB_TYPE_CLASS | USB_RECIP_DEVICE, - 0, (__u16)reg, &value, 1, HZ); + 0, (__u16)reg, &ov->cbuf[0], 1, HZ); + up(&ov->cbuf_lock); if (rc < 0) err("reg write: error %d", rc); @@ -736,45 +729,48 @@ return rc; } +/* Read from an OV51x register */ /* returns: negative is error, pos or zero is data */ static int -ov511_reg_read(struct usb_device *dev, unsigned char reg) +reg_r(struct usb_ov511 *ov, unsigned char reg) { int rc; - unsigned char buffer[1]; - rc = usb_control_msg(dev, - usb_rcvctrlpipe(dev, 0), + down(&ov->cbuf_lock); + rc = usb_control_msg(ov->dev, + usb_rcvctrlpipe(ov->dev, 0), 2 /* REG_IO */, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE, - 0, (__u16)reg, buffer, 1, HZ); + 0, (__u16)reg, &ov->cbuf[0], 1, HZ); - PDEBUG(5, "0x%02X:0x%02X", reg, buffer[0]); + PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]); - if (rc < 0) { + if (rc < 0) err("reg read: error %d", rc); - return rc; - } else { - return buffer[0]; - } + else + rc = ov->cbuf[0]; + + up(&ov->cbuf_lock); + + return rc; } /* - * Writes bits at positions specified by mask to a reg. Bits that are in + * Writes bits at positions specified by mask to an OV51x reg. Bits that are in * the same position as 1's in "mask" are cleared and set to "value". Bits * that are in the same position as 0's in "mask" are preserved, regardless * of their respective state in "value". */ static int -ov511_reg_write_mask(struct usb_device *dev, - unsigned char reg, - unsigned char value, - unsigned char mask) +reg_w_mask(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value, + unsigned char mask) { int ret; unsigned char oldval, newval; - ret = ov511_reg_read(dev, reg); + ret = reg_r(ov, reg); if (ret < 0) return ret; @@ -783,31 +779,30 @@ value &= mask; /* Enforce mask on value */ newval = oldval | value; /* Set the desired bits */ - return (ov511_reg_write(dev, reg, newval)); + return (reg_w(ov, reg, newval)); } -/* Writes multiple (n) values to a single register. Only valid with certain - * registers (0x30 and 0xc4 - 0xce). Used for writing 16 and 24-bit values. */ +/* + * Writes multiple (n) byte value to a single register. Only valid with certain + * registers (0x30 and 0xc4 - 0xce). + */ static int -ov518_reg_write_multi(struct usb_device *dev, - unsigned char reg, - unsigned char *values, - int n) +ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n) { int rc; - PDEBUG(5, "0x%02X:[multiple], n=%d", reg, n); // FIXME + PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n); - if (values == NULL) { - err("reg write multiple: NULL buffer"); - return -EINVAL; - } + down(&ov->cbuf_lock); - rc = usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), + *((u32 *)ov->cbuf) = __cpu_to_le32(val); + + rc = usb_control_msg(ov->dev, + usb_sndctrlpipe(ov->dev, 0), 2 /* REG_IO */, USB_TYPE_CLASS | USB_RECIP_DEVICE, - 0, (__u16)reg, values, n, HZ); + 0, (__u16)reg, ov->cbuf, n, HZ); + up(&ov->cbuf_lock); if (rc < 0) err("reg write multiple: error %d", rc); @@ -816,12 +811,12 @@ } static int -ov511_upload_quan_tables(struct usb_device *dev) +ov511_upload_quan_tables(struct usb_ov511 *ov) { unsigned char *pYTable = yQuanTable511; unsigned char *pUVTable = uvQuanTable511; unsigned char val0, val1; - int i, rc, reg = OV511_OMNICE_Y_LUT_BEGIN; + int i, rc, reg = R511_COMP_LUT_BEGIN; PDEBUG(4, "Uploading quantization tables"); @@ -834,7 +829,7 @@ val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; - rc = ov511_reg_write(dev, reg, val0); + rc = reg_w(ov, reg, val0); if (rc < 0) return rc; } @@ -846,8 +841,7 @@ val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; - rc = ov511_reg_write(dev, reg + OV511_QUANTABLESIZE / 2, - val0); + rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0); if (rc < 0) return rc; } @@ -860,12 +854,12 @@ /* OV518 quantization tables are 8x4 (instead of 8x8) */ static int -ov518_upload_quan_tables(struct usb_device *dev) +ov518_upload_quan_tables(struct usb_ov511 *ov) { unsigned char *pYTable = yQuanTable518; unsigned char *pUVTable = uvQuanTable518; unsigned char val0, val1; - int i, rc, reg = OV511_OMNICE_Y_LUT_BEGIN; + int i, rc, reg = R511_COMP_LUT_BEGIN; PDEBUG(4, "Uploading quantization tables"); @@ -878,7 +872,7 @@ val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; - rc = ov511_reg_write(dev, reg, val0); + rc = reg_w(ov, reg, val0); if (rc < 0) return rc; } @@ -890,8 +884,7 @@ val0 &= 0x0f; val1 &= 0x0f; val0 |= val1 << 4; - rc = ov511_reg_write(dev, reg + OV518_QUANTABLESIZE / 2, - val0); + rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0); if (rc < 0) return rc; } @@ -902,13 +895,39 @@ return 0; } +static int +ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type) +{ + int rc; + + /* Setting bit 0 not allowed on 518/518Plus */ + if (ov->bclass == BCL_OV518) + reset_type &= 0xfe; + + PDEBUG(4, "Reset: type=0x%X", reset_type); + + rc = reg_w(ov, R51x_SYS_RESET, reset_type); + rc = reg_w(ov, R51x_SYS_RESET, 0); + + if (rc < 0) + err("reset: command failed"); + + return rc; +} + +/********************************************************************** + * + * I2C (sensor) I/O + * + **********************************************************************/ + /* NOTE: Do not call this function directly! * The OV518 I2C I/O procedure is different, hence, this function. - * This is normally only called from ov51x_i2c_write(). Note that this function + * This is normally only called from i2c_w(). Note that this function * always succeeds regardless of whether the sensor is present and working. */ static int -ov518_i2c_write_internal(struct usb_device *dev, +ov518_i2c_write_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { @@ -917,15 +936,15 @@ PDEBUG(5, "0x%02X:0x%02X", reg, value); /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg); + rc = reg_w(ov, R51x_I2C_SADDR_3, reg); if (rc < 0) goto error; /* Write "value" to I2C data port of OV511 */ - rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); + rc = reg_w(ov, R51x_I2C_DATA, value); if (rc < 0) goto error; /* Initiate 3-byte write cycle */ - rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x01); + rc = reg_w(ov, R518_I2C_CTL, 0x01); if (rc < 0) goto error; return 0; @@ -937,7 +956,7 @@ /* NOTE: Do not call this function directly! */ static int -ov511_i2c_write_internal(struct usb_device *dev, +ov511_i2c_write_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { @@ -948,19 +967,18 @@ /* Three byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, - reg); + rc = reg_w(ov, R51x_I2C_SADDR_3, reg); if (rc < 0) goto error; /* Write "value" to I2C data port of OV511 */ - rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); + rc = reg_w(ov, R51x_I2C_DATA, value); if (rc < 0) goto error; /* Initiate 3-byte write cycle */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01); + rc = reg_w(ov, R511_I2C_CTL, 0x01); if (rc < 0) goto error; - do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); + do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) goto error; @@ -968,7 +986,7 @@ break; #if 0 /* I2C abort */ - ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); + reg_w(ov, R511_I2C_CTL, 0x10); #endif if (--retries < 0) { err("i2c write retries exhausted"); @@ -986,27 +1004,27 @@ /* NOTE: Do not call this function directly! * The OV518 I2C I/O procedure is different, hence, this function. - * This is normally only called from ov51x_i2c_read(). Note that this function + * This is normally only called from i2c_r(). Note that this function * always succeeds regardless of whether the sensor is present and working. */ static int -ov518_i2c_read_internal(struct usb_device *dev, unsigned char reg) +ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) { int rc, value; /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg); + rc = reg_w(ov, R51x_I2C_SADDR_2, reg); if (rc < 0) goto error; /* Initiate 2-byte write cycle */ - rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x03); + rc = reg_w(ov, R518_I2C_CTL, 0x03); if (rc < 0) goto error; /* Initiate 2-byte read cycle */ - rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x05); + rc = reg_w(ov, R518_I2C_CTL, 0x05); if (rc < 0) goto error; - value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); + value = reg_r(ov, R51x_I2C_DATA); PDEBUG(5, "0x%02X:0x%02X", reg, value); @@ -1020,22 +1038,21 @@ /* NOTE: Do not call this function directly! * returns: negative is error, pos or zero is data */ static int -ov511_i2c_read_internal(struct usb_device *dev, unsigned char reg) +ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) { int rc, value, retries; /* Two byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ - rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, - reg); + rc = reg_w(ov, R51x_I2C_SADDR_2, reg); if (rc < 0) goto error; /* Initiate 2-byte write cycle */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03); + rc = reg_w(ov, R511_I2C_CTL, 0x03); if (rc < 0) goto error; - do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); + do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) goto error; @@ -1043,7 +1060,7 @@ break; /* I2C abort */ - ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); + reg_w(ov, R511_I2C_CTL, 0x10); if (--retries < 0) { err("i2c write retries exhausted"); @@ -1055,10 +1072,10 @@ /* Two byte read cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Initiate 2-byte read cycle */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); + rc = reg_w(ov, R511_I2C_CTL, 0x05); if (rc < 0) goto error; - do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); + do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) goto error; @@ -1066,7 +1083,7 @@ break; /* I2C abort */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); + rc = reg_w(ov, R511_I2C_CTL, 0x10); if (rc < 0) goto error; if (--retries < 0) { @@ -1076,12 +1093,12 @@ } } - value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); + value = reg_r(ov, R51x_I2C_DATA); PDEBUG(5, "0x%02X:0x%02X", reg, value); - /* This is needed to make ov51x_i2c_write() work */ - rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); + /* This is needed to make i2c_w() work */ + rc = reg_w(ov, R511_I2C_CTL, 0x05); if (rc < 0) goto error; @@ -1094,48 +1111,42 @@ /* returns: negative is error, pos or zero is data */ static int -ov51x_i2c_read(struct usb_ov511 *ov511, unsigned char reg) +i2c_r(struct usb_ov511 *ov, unsigned char reg) { int rc; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); + down(&ov->i2c_lock); - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - rc = ov518_i2c_read_internal(dev, reg); + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_read_internal(ov, reg); else - rc = ov511_i2c_read_internal(dev, reg); + rc = ov511_i2c_read_internal(ov, reg); - up(&ov511->i2c_lock); + up(&ov->i2c_lock); return rc; } static int -ov51x_i2c_write(struct usb_ov511 *ov511, - unsigned char reg, - unsigned char value) +i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { int rc; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); + down(&ov->i2c_lock); - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - rc = ov518_i2c_write_internal(dev, reg, value); + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_write_internal(ov, reg, value); else - rc = ov511_i2c_write_internal(dev, reg, value); + rc = ov511_i2c_write_internal(ov, reg, value); - up(&ov511->i2c_lock); + up(&ov->i2c_lock); return rc; } /* Do not call this function directly! */ static int -ov51x_i2c_write_mask_internal(struct usb_device *dev, +ov51x_i2c_write_mask_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value, unsigned char mask) @@ -1146,11 +1157,10 @@ if (mask == 0xff) { newval = value; } else { - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - rc = ov518_i2c_read_internal(dev, reg); + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_read_internal(ov, reg); else - rc = ov511_i2c_read_internal(dev, reg); + rc = ov511_i2c_read_internal(ov, reg); if (rc < 0) return rc; @@ -1160,11 +1170,10 @@ newval = oldval | value; /* Set the desired bits */ } - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - return (ov518_i2c_write_internal(dev, reg, newval)); + if (ov->bclass == BCL_OV518) + return (ov518_i2c_write_internal(ov, reg, newval)); else - return (ov511_i2c_write_internal(dev, reg, newval)); + return (ov511_i2c_write_internal(ov, reg, newval)); } /* Writes bits at positions specified by mask to an I2C reg. Bits that are in @@ -1173,126 +1182,138 @@ * of their respective state in "value". */ static int -ov51x_i2c_write_mask(struct usb_ov511 *ov511, - unsigned char reg, - unsigned char value, - unsigned char mask) +i2c_w_mask(struct usb_ov511 *ov, + unsigned char reg, + unsigned char value, + unsigned char mask) { int rc; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); - rc = ov51x_i2c_write_mask_internal(dev, reg, value, mask); - up(&ov511->i2c_lock); + down(&ov->i2c_lock); + rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); + up(&ov->i2c_lock); return rc; } /* Write to a specific I2C slave ID and register, using the specified mask */ static int -ov51x_i2c_write_slave(struct usb_ov511 *ov511, - unsigned char slave, - unsigned char reg, - unsigned char value, - unsigned char mask) +i2c_w_slave(struct usb_ov511 *ov, + unsigned char slave, + unsigned char reg, + unsigned char value, + unsigned char mask) { int rc = 0; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); + down(&ov->i2c_lock); /* Set new slave IDs */ - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) { rc = -EIO; goto out; } - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) { rc = -EIO; goto out; } - rc = ov51x_i2c_write_mask_internal(dev, reg, value, mask); + rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); /* Don't bail out yet if error; IDs must be restored */ /* Restore primary IDs */ - slave = ov511->primary_i2c_slave; - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + slave = ov->primary_i2c_slave; + if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) { rc = -EIO; goto out; } - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) { rc = -EIO; goto out; } out: - up(&ov511->i2c_lock); + up(&ov->i2c_lock); return rc; } /* Read from a specific I2C slave ID and register */ static int -ov51x_i2c_read_slave(struct usb_ov511 *ov511, - unsigned char slave, - unsigned char reg) +i2c_r_slave(struct usb_ov511 *ov, + unsigned char slave, + unsigned char reg) { int rc; - struct usb_device *dev = ov511->dev; - down(&ov511->i2c_lock); + down(&ov->i2c_lock); /* Set new slave IDs */ - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) { rc = -EIO; goto out; } - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) { rc = -EIO; goto out; } - if (dev->descriptor.idProduct == PROD_OV518 || - dev->descriptor.idProduct == PROD_OV518PLUS) - rc = ov518_i2c_read_internal(dev, reg); + if (ov->bclass == BCL_OV518) + rc = ov518_i2c_read_internal(ov, reg); else - rc = ov511_i2c_read_internal(dev, reg); + rc = ov511_i2c_read_internal(ov, reg); /* Don't bail out yet if error; IDs must be restored */ /* Restore primary IDs */ - slave = ov511->primary_i2c_slave; - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { + slave = ov->primary_i2c_slave; + if (reg_w(ov, R51x_I2C_W_SID, slave) < 0) { rc = -EIO; goto out; } - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { + if (reg_w(ov, R51x_I2C_R_SID, slave + 1) < 0) { rc = -EIO; goto out; } out: - up(&ov511->i2c_lock); + up(&ov->i2c_lock); return rc; } +/* Sets I2C read and write slave IDs. Returns <0 for error */ +static int +ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid) +{ + down(&ov->i2c_lock); + + if (reg_w(ov, R51x_I2C_W_SID, sid) < 0) + return -EIO; + + if (reg_w(ov, R51x_I2C_R_SID, sid + 1) < 0) + return -EIO; + + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) + return -EIO; + + up(&ov->i2c_lock); + + return 0; +} + static int -ov511_write_regvals(struct usb_ov511 *ov511, - struct ov511_regvals * pRegvals) +write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals) { int rc; - struct usb_device *dev = ov511->dev; while (pRegvals->bus != OV511_DONE_BUS) { if (pRegvals->bus == OV511_REG_BUS) { - if ((rc = ov511_reg_write(dev, pRegvals->reg, - pRegvals->val)) < 0) + if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0) goto error; } else if (pRegvals->bus == OV511_I2C_BUS) { - if ((rc = ov51x_i2c_write(ov511, pRegvals->reg, - pRegvals->val)) < 0) + if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0) goto error; } else { err("Bad regval array"); @@ -1310,57 +1331,60 @@ #ifdef OV511_DEBUG static void -ov511_dump_i2c_range(struct usb_ov511 *ov511, int reg1, int regn) +dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn) { int i; int rc; + for (i = reg1; i <= regn; i++) { - rc = ov51x_i2c_read(ov511, i); + rc = i2c_r(ov, i); info("OV7610[0x%X] = 0x%X", i, rc); } } static void -ov51x_dump_i2c_regs(struct usb_ov511 *ov511) +dump_i2c_regs(struct usb_ov511 *ov) { info("I2C REGS"); - ov511_dump_i2c_range(ov511, 0x00, 0x7C); + dump_i2c_range(ov, 0x00, 0x7C); } static void -ov511_dump_reg_range(struct usb_device *dev, int reg1, int regn) +dump_reg_range(struct usb_ov511 *ov, int reg1, int regn) { int i; int rc; + for (i = reg1; i <= regn; i++) { - rc = ov511_reg_read(dev, i); - info("OV511[0x%X] = 0x%X", i, rc); + rc = reg_r(ov, i); + info("OV511[0x%X] = 0x%X", i, rc); } } +/* FIXME: Should there be an OV518 version of this? */ static void -ov511_dump_regs(struct usb_device *dev) +ov511_dump_regs(struct usb_ov511 *ov) { info("CAMERA INTERFACE REGS"); - ov511_dump_reg_range(dev, 0x10, 0x1f); + dump_reg_range(ov, 0x10, 0x1f); info("DRAM INTERFACE REGS"); - ov511_dump_reg_range(dev, 0x20, 0x23); + dump_reg_range(ov, 0x20, 0x23); info("ISO FIFO REGS"); - ov511_dump_reg_range(dev, 0x30, 0x31); + dump_reg_range(ov, 0x30, 0x31); info("PIO REGS"); - ov511_dump_reg_range(dev, 0x38, 0x39); - ov511_dump_reg_range(dev, 0x3e, 0x3e); + dump_reg_range(ov, 0x38, 0x39); + dump_reg_range(ov, 0x3e, 0x3e); info("I2C REGS"); - ov511_dump_reg_range(dev, 0x40, 0x49); + dump_reg_range(ov, 0x40, 0x49); info("SYSTEM CONTROL REGS"); - ov511_dump_reg_range(dev, 0x50, 0x55); - ov511_dump_reg_range(dev, 0x5e, 0x5f); + dump_reg_range(ov, 0x50, 0x55); + dump_reg_range(ov, 0x5e, 0x5f); info("OmniCE REGS"); - ov511_dump_reg_range(dev, 0x70, 0x79); + dump_reg_range(ov, 0x70, 0x79); /* NOTE: Quantization tables are not readable. You will get the value * in reg. 0x79 for every table register */ - ov511_dump_reg_range(dev, 0x80, 0x9f); - ov511_dump_reg_range(dev, 0xa0, 0xbf); + dump_reg_range(ov, 0x80, 0x9f); + dump_reg_range(ov, 0xa0, 0xbf); } #endif @@ -1373,7 +1397,7 @@ /* For as-yet unimplemented I2C interface */ static void -call_i2c_clients(struct usb_ov511 *ov511, unsigned int cmd, +call_i2c_clients(struct usb_ov511 *ov, unsigned int cmd, void *arg) { /* Do nothing */ @@ -1381,59 +1405,33 @@ /*****************************************************************************/ -static int -ov511_reset(struct usb_ov511 *ov511, unsigned char reset_type) -{ - int rc; - - /* Setting bit 0 not allowed on 518/518Plus */ - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - reset_type &= 0xfe; - - PDEBUG(4, "Reset: type=0x%X", reset_type); - - rc = ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, reset_type); - rc = ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0); - - if (rc < 0) - err("reset: command failed"); - - return rc; -} - /* Temporarily stops OV511 from functioning. Must do this before changing * registers while the camera is streaming */ static inline int -ov511_stop(struct usb_ov511 *ov511) +ov51x_stop(struct usb_ov511 *ov) { PDEBUG(4, "stopping"); - ov511->stopped = 1; - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, - 0x3a)); + ov->stopped = 1; + if (ov->bclass == BCL_OV518) + return (reg_w(ov, R51x_SYS_RESET, 0x3a)); else - return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, - 0x3d)); + return (reg_w(ov, R51x_SYS_RESET, 0x3d)); } /* Restarts OV511 after ov511_stop() is called. Has no effect if it is not * actually stopped (for performance). */ static inline int -ov511_restart(struct usb_ov511 *ov511) +ov51x_restart(struct usb_ov511 *ov) { - if (ov511->stopped) { + if (ov->stopped) { PDEBUG(4, "restarting"); - ov511->stopped = 0; + ov->stopped = 0; /* Reinitialize the stream */ - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - ov511_reg_write(ov511->dev, 0x2f, 0x80); + if (ov->bclass == BCL_OV518) + reg_w(ov, 0x2f, 0x80); - return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, - 0x00)); + return (reg_w(ov, R51x_SYS_RESET, 0x00)); } return 0; @@ -1441,14 +1439,13 @@ /* Resets the hardware snapshot button */ static void -ov51x_clear_snapshot(struct usb_ov511 *ov511) +ov51x_clear_snapshot(struct usb_ov511 *ov) { - if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03); - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + if (ov->bclass == BCL_OV511) { + reg_w(ov, R51x_SYS_SNAP, 0x01); + reg_w(ov, R51x_SYS_SNAP, 0x03); + reg_w(ov, R51x_SYS_SNAP, 0x01); + } else if (ov->bclass == BCL_OV518) { warn("snapshot reset not supported yet on OV518(+)"); } else { err("clear snap: invalid bridge type"); @@ -1459,19 +1456,18 @@ /* Checks the status of the snapshot button. Returns 1 if it was pressed since * it was last cleared, and zero in all other cases (including errors) */ static int -ov51x_check_snapshot(struct usb_ov511 *ov511) +ov51x_check_snapshot(struct usb_ov511 *ov) { int ret, status = 0; - if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { - ret = ov511_reg_read(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT); + if (ov->bclass == BCL_OV511) { + ret = reg_r(ov, R51x_SYS_SNAP); if (ret < 0) { err("Error checking snspshot status (%d)", ret); } else if (ret & 0x08) { status = 1; } - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + } else if (ov->bclass == BCL_OV518) { warn("snapshot check not supported yet on OV518(+)"); } else { err("check snap: invalid bridge type"); @@ -1480,53 +1476,33 @@ return status; } -/* Sets I2C read and write slave IDs. Returns <0 for error */ -static int -ov51x_set_slave_ids(struct usb_ov511 *ov511, - unsigned char write_id, - unsigned char read_id) -{ - struct usb_device *dev = ov511->dev; - - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, write_id) < 0) - return -EIO; - - if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, read_id) < 0) - return -EIO; - - if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0) - return -EIO; - - return 0; -} - /* This does an initial reset of an OmniVision sensor and ensures that I2C * is synchronized. Returns <0 for failure. */ static int -ov51x_init_ov_sensor(struct usb_ov511 *ov511) +init_ov_sensor(struct usb_ov511 *ov) { int i, success; /* Reset the sensor */ - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -EIO; + if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; /* Wait for it to initialize */ schedule_timeout (1 + 150 * HZ / 1000); for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { - if ((ov51x_i2c_read(ov511, OV7610_REG_ID_HIGH) == 0x7F) && - (ov51x_i2c_read(ov511, OV7610_REG_ID_LOW) == 0xA2)) { + if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && + (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { success = 1; continue; } /* Reset the sensor */ - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -EIO; + if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; /* Wait for it to initialize */ schedule_timeout(1 + 150 * HZ / 1000); /* Dummy read to sync I2C */ - if (ov51x_i2c_read(ov511, 0x00) < 0) return -EIO; + if (i2c_r(ov, 0x00) < 0) return -EIO; } if (!success) @@ -1538,16 +1514,16 @@ } static int -ov511_set_packet_size(struct usb_ov511 *ov511, int size) +ov51x_set_packet_size(struct usb_ov511 *ov, int size) { int alt, mult; - if (ov511_stop(ov511) < 0) + if (ov51x_stop(ov) < 0) return -EIO; mult = size >> 5; - if (ov511->bridge == BRG_OV511) { + if (ov->bridge == BRG_OV511) { if (size == 0) alt = OV511_ALT_SIZE_0; else if (size == 257) alt = OV511_ALT_SIZE_257; else if (size == 513) alt = OV511_ALT_SIZE_513; @@ -1557,7 +1533,7 @@ err("Set packet size: invalid size (%d)", size); return -EINVAL; } - } else if (ov511->bridge == BRG_OV511PLUS) { + } else if (ov->bridge == BRG_OV511PLUS) { if (size == 0) alt = OV511PLUS_ALT_SIZE_0; else if (size == 33) alt = OV511PLUS_ALT_SIZE_33; else if (size == 129) alt = OV511PLUS_ALT_SIZE_129; @@ -1570,8 +1546,7 @@ err("Set packet size: invalid size (%d)", size); return -EINVAL; } - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + } else if (ov->bclass == BCL_OV518) { if (size == 0) alt = OV518_ALT_SIZE_0; else if (size == 128) alt = OV518_ALT_SIZE_128; else if (size == 256) alt = OV518_ALT_SIZE_256; @@ -1592,32 +1567,30 @@ PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt); // FIXME: Don't know how to do this on OV518 yet - if (ov511->bridge != BRG_OV518 && - ov511->bridge != BRG_OV518PLUS) { - if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE, + if (ov->bclass == BCL_OV511) { + if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0) { return -EIO; } } - if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) { + if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { err("Set packet size: set interface error"); return -EBUSY; } /* Initialize the stream */ - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - if (ov511_reg_write(ov511->dev, 0x2f, 0x80) < 0) + if (ov->bclass == BCL_OV518) + if (reg_w(ov, 0x2f, 0x80) < 0) return -EIO; // FIXME - Should we only reset the FIFO? - if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0) + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) return -EIO; - ov511->packet_size = size; + ov->packet_size = size; - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return 0; @@ -1625,51 +1598,49 @@ /* Upload compression params and quantization tables. Returns 0 for success. */ static int -ov511_init_compression(struct usb_ov511 *ov511) +ov511_init_compression(struct usb_ov511 *ov) { - struct usb_device *dev = ov511->dev; int rc = 0; - if (!ov511->compress_inited) { + if (!ov->compress_inited) { - ov511_reg_write(dev, 0x70, phy); - ov511_reg_write(dev, 0x71, phuv); - ov511_reg_write(dev, 0x72, pvy); - ov511_reg_write(dev, 0x73, pvuv); - ov511_reg_write(dev, 0x74, qhy); - ov511_reg_write(dev, 0x75, qhuv); - ov511_reg_write(dev, 0x76, qvy); - ov511_reg_write(dev, 0x77, qvuv); + reg_w(ov, 0x70, phy); + reg_w(ov, 0x71, phuv); + reg_w(ov, 0x72, pvy); + reg_w(ov, 0x73, pvuv); + reg_w(ov, 0x74, qhy); + reg_w(ov, 0x75, qhuv); + reg_w(ov, 0x76, qvy); + reg_w(ov, 0x77, qvuv); - if (ov511_upload_quan_tables(dev) < 0) { + if (ov511_upload_quan_tables(ov) < 0) { err("Error uploading quantization tables"); rc = -EIO; goto out; } } - ov511->compress_inited = 1; + ov->compress_inited = 1; out: return rc; } /* Upload compression params and quantization tables. Returns 0 for success. */ static int -ov518_init_compression(struct usb_ov511 *ov511) +ov518_init_compression(struct usb_ov511 *ov) { - struct usb_device *dev = ov511->dev; int rc = 0; - if (!ov511->compress_inited) { + if (!ov->compress_inited) { - if (ov518_upload_quan_tables(dev) < 0) { + if (ov518_upload_quan_tables(ov) < 0) { err("Error uploading quantization tables"); rc = -EIO; goto out; } } - ov511->compress_inited = 1; + ov->compress_inited = 1; out: return rc; } @@ -1678,22 +1649,22 @@ /* Sets sensor's contrast setting to "val" */ static int -sensor_set_contrast(struct usb_ov511 *ov511, unsigned short val) +sensor_set_contrast(struct usb_ov511 *ov, unsigned short val) { int rc; PDEBUG(3, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: { - rc = ov51x_i2c_write(ov511, OV7610_REG_CNT, val >> 8); + rc = i2c_w(ov, OV7610_REG_CNT, val >> 8); if (rc < 0) goto out; break; @@ -1706,14 +1677,14 @@ }; /* Use Y gamma control instead. Bit 0 enables it. */ - rc = ov51x_i2c_write(ov511, 0x64, ctab[val>>12]); + rc = i2c_w(ov, 0x64, ctab[val>>12]); if (rc < 0) goto out; break; } case SEN_SAA7111A: { - rc = ov51x_i2c_write(ov511, 0x0b, val >> 9); + rc = i2c_w(ov, 0x0b, val >> 9); if (rc < 0) goto out; break; @@ -1727,9 +1698,9 @@ } rc = 0; /* Success */ - ov511->contrast = val; + ov->contrast = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -1737,15 +1708,15 @@ /* Gets sensor's contrast setting */ static int -sensor_get_contrast(struct usb_ov511 *ov511, unsigned short *val) +sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_read(ov511, OV7610_REG_CNT); + rc = i2c_r(ov, OV7610_REG_CNT); if (rc < 0) return rc; else @@ -1753,14 +1724,14 @@ break; case SEN_OV7620: /* Use Y gamma reg instead. Bit 0 is the enable bit. */ - rc = ov51x_i2c_read(ov511, 0x64); + rc = i2c_r(ov, 0x64); if (rc < 0) return rc; else *val = (rc & 0xfe) << 8; break; case SEN_SAA7111A: - *val = ov511->contrast; + *val = ov->contrast; break; default: PDEBUG(3, "Unsupported with this sensor"); @@ -1768,7 +1739,7 @@ } PDEBUG(3, "%d", *val); - ov511->contrast = *val; + ov->contrast = *val; return 0; } @@ -1777,35 +1748,35 @@ /* Sets sensor's brightness setting to "val" */ static int -sensor_set_brightness(struct usb_ov511 *ov511, unsigned short val) +sensor_set_brightness(struct usb_ov511 *ov, unsigned short val) { int rc; PDEBUG(4, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_write(ov511, OV7610_REG_BRT, val >> 8); + rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); if (rc < 0) goto out; break; case SEN_OV7620: /* 7620 doesn't like manual changes when in auto mode */ - if (!ov511->auto_brt) { - rc = ov51x_i2c_write(ov511, OV7610_REG_BRT, val >> 8); + if (!ov->auto_brt) { + rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); if (rc < 0) goto out; } break; case SEN_SAA7111A: - rc = ov51x_i2c_write(ov511, 0x0a, val >> 8); + rc = i2c_w(ov, 0x0a, val >> 8); if (rc < 0) goto out; break; @@ -1816,9 +1787,9 @@ } rc = 0; /* Success */ - ov511->brightness = val; + ov->brightness = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -1826,24 +1797,24 @@ /* Gets sensor's brightness setting */ static int -sensor_get_brightness(struct usb_ov511 *ov511, unsigned short *val) +sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: case SEN_OV7620: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_read(ov511, OV7610_REG_BRT); + rc = i2c_r(ov, OV7610_REG_BRT); if (rc < 0) return rc; else *val = rc << 8; break; case SEN_SAA7111A: - *val = ov511->brightness; + *val = ov->brightness; break; default: PDEBUG(3, "Unsupported with this sensor"); @@ -1851,7 +1822,7 @@ } PDEBUG(3, "%d", *val); - ov511->brightness = *val; + ov->brightness = *val; return 0; } @@ -1860,36 +1831,36 @@ /* Sets sensor's saturation (color intensity) setting to "val" */ static int -sensor_set_saturation(struct usb_ov511 *ov511, unsigned short val) +sensor_set_saturation(struct usb_ov511 *ov, unsigned short val) { int rc; PDEBUG(3, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_write(ov511, OV7610_REG_SAT, val >> 8); + rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); if (rc < 0) goto out; break; case SEN_OV7620: // /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ -// rc = ov511_i2c_write(ov511->dev, 0x62, (val >> 9) & 0x7e); +// rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e); // if (rc < 0) // goto out; - rc = ov51x_i2c_write(ov511, OV7610_REG_SAT, val >> 8); + rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); if (rc < 0) goto out; break; case SEN_SAA7111A: - rc = ov51x_i2c_write(ov511, 0x0c, val >> 9); + rc = i2c_w(ov, 0x0c, val >> 9); if (rc < 0) goto out; break; @@ -1900,9 +1871,9 @@ } rc = 0; /* Success */ - ov511->colour = val; + ov->colour = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -1910,16 +1881,16 @@ /* Gets sensor's saturation (color intensity) setting */ static int -sensor_get_saturation(struct usb_ov511 *ov511, unsigned short *val) +sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_read(ov511, OV7610_REG_SAT); + rc = i2c_r(ov, OV7610_REG_SAT); if (rc < 0) return rc; else @@ -1927,19 +1898,19 @@ break; case SEN_OV7620: // /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */ -// rc = ov51x_i2c_read(ov511, 0x62); +// rc = i2c_r(ov, 0x62); // if (rc < 0) // return rc; // else // *val = (rc & 0x7e) << 9; - rc = ov51x_i2c_read(ov511, OV7610_REG_SAT); + rc = i2c_r(ov, OV7610_REG_SAT); if (rc < 0) return rc; else *val = rc << 8; break; case SEN_SAA7111A: - *val = ov511->colour; + *val = ov->colour; break; default: PDEBUG(3, "Unsupported with this sensor"); @@ -1947,7 +1918,7 @@ } PDEBUG(3, "%d", *val); - ov511->colour = *val; + ov->colour = *val; return 0; } @@ -1956,44 +1927,42 @@ /* Sets sensor's hue (red/blue balance) setting to "val" */ static int -sensor_set_hue(struct usb_ov511 *ov511, unsigned short val) +sensor_set_hue(struct usb_ov511 *ov, unsigned short val) { int rc; PDEBUG(3, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_write(ov511, OV7610_REG_RED, 0xFF - (val >> 8)); + rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8)); if (rc < 0) goto out; - rc = ov51x_i2c_write(ov511, OV7610_REG_BLUE, val >> 8); + rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8); if (rc < 0) goto out; break; case SEN_OV7620: // Hue control is causing problems. I will enable it once it's fixed. #if 0 - rc = ov51x_i2c_write(ov511, 0x7a, - (unsigned char)(val >> 8) + 0xb); + rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb); if (rc < 0) goto out; - rc = ov51x_i2c_write(ov511, 0x79, - (unsigned char)(val >> 8) + 0xb); + rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb); if (rc < 0) goto out; #endif break; case SEN_SAA7111A: - rc = ov51x_i2c_write(ov511, 0x0d, (val + 32768) >> 8); + rc = i2c_w(ov, 0x0d, (val + 32768) >> 8); if (rc < 0) goto out; break; @@ -2004,9 +1973,9 @@ } rc = 0; /* Success */ - ov511->hue = val; + ov->hue = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -2014,29 +1983,29 @@ /* Gets sensor's hue (red/blue balance) setting */ static int -sensor_get_hue(struct usb_ov511 *ov511, unsigned short *val) +sensor_get_hue(struct usb_ov511 *ov, unsigned short *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: - rc = ov51x_i2c_read(ov511, OV7610_REG_BLUE); + rc = i2c_r(ov, OV7610_REG_BLUE); if (rc < 0) return rc; else *val = rc << 8; break; case SEN_OV7620: - rc = ov51x_i2c_read(ov511, 0x7a); + rc = i2c_r(ov, 0x7a); if (rc < 0) return rc; else *val = rc << 8; break; case SEN_SAA7111A: - *val = ov511->hue; + *val = ov->hue; break; default: PDEBUG(3, "Unsupported with this sensor"); @@ -2044,7 +2013,7 @@ } PDEBUG(3, "%d", *val); - ov511->hue = *val; + ov->hue = *val; return 0; } @@ -2052,30 +2021,30 @@ /* -------------------------------------------------------------------------- */ static inline int -sensor_set_picture(struct usb_ov511 *ov511, struct video_picture *p) +sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p) { int rc; PDEBUG(4, "sensor_set_picture"); - ov511->whiteness = p->whiteness; + ov->whiteness = p->whiteness; /* Don't return error if a setting is unsupported, or rest of settings * will not be performed */ - rc = sensor_set_contrast(ov511, p->contrast); + rc = sensor_set_contrast(ov, p->contrast); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_brightness(ov511, p->brightness); + rc = sensor_set_brightness(ov, p->brightness); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_saturation(ov511, p->colour); + rc = sensor_set_saturation(ov, p->colour); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_hue(ov511, p->hue); + rc = sensor_set_hue(ov, p->hue); if (FATAL_ERROR(rc)) return rc; @@ -2083,7 +2052,7 @@ } static inline int -sensor_get_picture(struct usb_ov511 *ov511, struct video_picture *p) +sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p) { int rc; @@ -2092,27 +2061,27 @@ /* Don't return error if a setting is unsupported, or rest of settings * will not be performed */ - rc = sensor_get_contrast(ov511, &(p->contrast)); + rc = sensor_get_contrast(ov, &(p->contrast)); if (FATAL_ERROR(rc)) return rc; - rc = sensor_get_brightness(ov511, &(p->brightness)); + rc = sensor_get_brightness(ov, &(p->brightness)); if (FATAL_ERROR(rc)) return rc; - rc = sensor_get_saturation(ov511, &(p->colour)); + rc = sensor_get_saturation(ov, &(p->colour)); if (FATAL_ERROR(rc)) return rc; - rc = sensor_get_hue(ov511, &(p->hue)); + rc = sensor_get_hue(ov, &(p->hue)); if (FATAL_ERROR(rc)) return rc; p->whiteness = 105 << 8; /* Can we get these from frame[0]? -claudio? */ - p->depth = ov511->frame[0].depth; - p->palette = ov511->frame[0].format; + p->depth = ov->frame[0].depth; + p->palette = ov->frame[0].format; return 0; } @@ -2121,24 +2090,24 @@ /* Sets current exposure for sensor. This only has an effect if auto-exposure * is off */ static inline int -sensor_set_exposure(struct usb_ov511 *ov511, unsigned char val) +sensor_set_exposure(struct usb_ov511 *ov, unsigned char val) { int rc; PDEBUG(3, "%d", val); - if (ov511->stop_during_set) - if (ov511_stop(ov511) < 0) + if (ov->stop_during_set) + if (ov51x_stop(ov) < 0) return -EIO; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV6620: case SEN_OV6630: case SEN_OV7610: case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: - rc = ov51x_i2c_write(ov511, 0x10, val); + rc = i2c_w(ov, 0x10, val); if (rc < 0) goto out; @@ -2154,9 +2123,9 @@ } rc = 0; /* Success */ - ov511->exposure = val; + ov->exposure = val; out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -2165,18 +2134,18 @@ /* Gets current exposure level from sensor, regardless of whether it is under * manual control. */ static int -sensor_get_exposure(struct usb_ov511 *ov511, unsigned char *val) +sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val) { int rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV6620: case SEN_OV6630: case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: - rc = ov51x_i2c_read(ov511, 0x10); + rc = i2c_r(ov, 0x10); if (rc < 0) return rc; else @@ -2194,24 +2163,22 @@ } PDEBUG(3, "%d", *val); - ov511->exposure = *val; + ov->exposure = *val; return 0; } /* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */ static inline void -ov51x_led_control(struct usb_ov511 *ov511, int enable) +ov51x_led_control(struct usb_ov511 *ov, int enable) { PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - if (ov511->bridge == BRG_OV511PLUS) - ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_LED_CTL, - enable ? 1 : 0); - else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - ov511_reg_write_mask(ov511->dev, OV518_REG_GPIO_OUT, - enable ? 0x02 : 0x00, 0x02); + if (ov->bridge == BRG_OV511PLUS) + reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0); + else if (ov->bclass == BCL_OV518) + reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02); + return; } @@ -2225,7 +2192,7 @@ * Returns: 0 for success */ static int -sensor_set_light_freq(struct usb_ov511 *ov511, int freq) +sensor_set_light_freq(struct usb_ov511 *ov, int freq) { int sixty; @@ -2240,24 +2207,24 @@ return -EINVAL; } - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: - ov51x_i2c_write_mask(ov511, 0x2a, sixty?0x00:0x80, 0x80); - ov51x_i2c_write(ov511, 0x2b, sixty?0x00:0xac); - ov51x_i2c_write_mask(ov511, 0x13, 0x10, 0x10); - ov51x_i2c_write_mask(ov511, 0x13, 0x00, 0x10); + i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); + i2c_w(ov, 0x2b, sixty?0x00:0xac); + i2c_w_mask(ov, 0x13, 0x10, 0x10); + i2c_w_mask(ov, 0x13, 0x00, 0x10); break; case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: - ov51x_i2c_write_mask(ov511, 0x2a, sixty?0x00:0x80, 0x80); - ov51x_i2c_write(ov511, 0x2b, sixty?0x00:0xac); - ov51x_i2c_write_mask(ov511, 0x76, 0x01, 0x01); + i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); + i2c_w(ov, 0x2b, sixty?0x00:0xac); + i2c_w_mask(ov, 0x76, 0x01, 0x01); break; case SEN_OV6620: case SEN_OV6630: - ov51x_i2c_write(ov511, 0x2b, sixty?0xa8:0x28); - ov51x_i2c_write(ov511, 0x2a, sixty?0x84:0xa4); + i2c_w(ov, 0x2b, sixty?0xa8:0x28); + i2c_w(ov, 0x2a, sixty?0x84:0xa4); break; case SEN_KS0127: case SEN_KS0127B: @@ -2269,7 +2236,7 @@ return -EINVAL; } - ov511->lightfreq = freq; + ov->lightfreq = freq; return 0; } @@ -2284,23 +2251,23 @@ * Returns: 0 for success */ static inline int -sensor_set_banding_filter(struct usb_ov511 *ov511, int enable) +sensor_set_banding_filter(struct usb_ov511 *ov, int enable) { int rc; PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - if (ov511->sensor == SEN_KS0127 || ov511->sensor == SEN_KS0127B - || ov511->sensor == SEN_SAA7111A) { + if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B + || ov->sensor == SEN_SAA7111A) { PDEBUG(5, "Unsupported with this sensor"); return -EPERM; } - rc = ov51x_i2c_write_mask(ov511, 0x2d, enable?0x04:0x00, 0x04); + rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04); if (rc < 0) return rc; - ov511->bandfilt = enable; + ov->bandfilt = enable; return 0; } @@ -2312,23 +2279,23 @@ * Returns: 0 for success */ static inline int -sensor_set_auto_brightness(struct usb_ov511 *ov511, int enable) +sensor_set_auto_brightness(struct usb_ov511 *ov, int enable) { int rc; PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - if (ov511->sensor == SEN_KS0127 || ov511->sensor == SEN_KS0127B - || ov511->sensor == SEN_SAA7111A) { + if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B + || ov->sensor == SEN_SAA7111A) { PDEBUG(5, "Unsupported with this sensor"); return -EPERM; } - rc = ov51x_i2c_write_mask(ov511, 0x2d, enable?0x10:0x00, 0x10); + rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10); if (rc < 0) return rc; - ov511->auto_brt = enable; + ov->auto_brt = enable; return 0; } @@ -2340,22 +2307,22 @@ * Returns: 0 for success */ static inline int -sensor_set_auto_exposure(struct usb_ov511 *ov511, int enable) +sensor_set_auto_exposure(struct usb_ov511 *ov, int enable) { PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: - ov51x_i2c_write_mask(ov511, 0x29, enable?0x00:0x80, 0x80); + i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80); break; case SEN_OV6620: case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: - ov51x_i2c_write_mask(ov511, 0x13, enable?0x01:0x00, 0x01); + i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01); break; case SEN_OV6630: - ov51x_i2c_write_mask(ov511, 0x28, enable?0x00:0x10, 0x10); + i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10); break; case SEN_KS0127: case SEN_KS0127B: @@ -2367,7 +2334,7 @@ return -EINVAL; } - ov511->auto_exp = enable; + ov->auto_exp = enable; return 0; } @@ -2380,27 +2347,27 @@ * Returns: 0 for success */ static int -sensor_set_backlight(struct usb_ov511 *ov511, int enable) +sensor_set_backlight(struct usb_ov511 *ov, int enable) { PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7620: case SEN_OV8600: - ov51x_i2c_write_mask(ov511, 0x68, enable?0xe0:0xc0, 0xe0); - ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08); - ov51x_i2c_write_mask(ov511, 0x28, enable?0x02:0x00, 0x02); + i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); break; case SEN_OV6620: - ov51x_i2c_write_mask(ov511, 0x4e, enable?0xe0:0xc0, 0xe0); - ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08); - ov51x_i2c_write_mask(ov511, 0x0e, enable?0x80:0x00, 0x80); + i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80); break; case SEN_OV6630: - ov51x_i2c_write_mask(ov511, 0x4e, enable?0x80:0x60, 0xe0); - ov51x_i2c_write_mask(ov511, 0x29, enable?0x08:0x00, 0x08); - ov51x_i2c_write_mask(ov511, 0x28, enable?0x02:0x00, 0x02); + i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0); + i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); + i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); break; case SEN_OV7610: case SEN_OV7620AE: @@ -2414,7 +2381,7 @@ return -EINVAL; } - ov511->backlight = enable; + ov->backlight = enable; return 0; } @@ -2423,7 +2390,7 @@ * planar or not), or zero for unsupported format. */ static inline int -ov511_get_depth(int palette) +get_depth(int palette) { switch (palette) { case VIDEO_PALETTE_GREY: return 8; @@ -2446,55 +2413,55 @@ return 0; else return ((frame->width * frame->height - * ov511_get_depth(frame->format)) >> 3); + * get_depth(frame->format)) >> 3); } static int -mode_init_ov_sensor_regs(struct usb_ov511 *ov511, int width, int height, +mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag, int qvga) { int clock; /******** Mode (VGA/QVGA) and sensor specific regs ********/ - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: - ov51x_i2c_write(ov511, 0x14, qvga?0x24:0x04); + i2c_w(ov, 0x14, qvga?0x24:0x04); // FIXME: Does this improve the image quality or frame rate? #if 0 - ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20); - ov51x_i2c_write(ov511, 0x24, 0x10); - ov51x_i2c_write(ov511, 0x25, qvga?0x40:0x8a); - ov51x_i2c_write(ov511, 0x2f, qvga?0x30:0xb0); - ov51x_i2c_write(ov511, 0x35, qvga?0x1c:0x9c); + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, 0x10); + i2c_w(ov, 0x25, qvga?0x40:0x8a); + i2c_w(ov, 0x2f, qvga?0x30:0xb0); + i2c_w(ov, 0x35, qvga?0x1c:0x9c); #endif break; case SEN_OV7620: -// ov51x_i2c_write(ov511, 0x2b, 0x00); - ov51x_i2c_write(ov511, 0x14, qvga?0xa4:0x84); - ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20); - ov51x_i2c_write(ov511, 0x24, qvga?0x20:0x3a); - ov51x_i2c_write(ov511, 0x25, qvga?0x30:0x60); - ov51x_i2c_write_mask(ov511, 0x2d, qvga?0x40:0x00, 0x40); - ov51x_i2c_write_mask(ov511, 0x67, qvga?0xf0:0x90, 0xf0); - ov51x_i2c_write_mask(ov511, 0x74, qvga?0x20:0x00, 0x20); +// i2c_w(ov, 0x2b, 0x00); + i2c_w(ov, 0x14, qvga?0xa4:0x84); + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, qvga?0x20:0x3a); + i2c_w(ov, 0x25, qvga?0x30:0x60); + i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); + i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0); + i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); break; case SEN_OV7620AE: -// ov51x_i2c_write(ov511, 0x2b, 0x00); - ov51x_i2c_write(ov511, 0x14, qvga?0xa4:0x84); +// i2c_w(ov, 0x2b, 0x00); + i2c_w(ov, 0x14, qvga?0xa4:0x84); // FIXME: Enable this once 7620AE uses 7620 initial settings #if 0 - ov51x_i2c_write_mask(ov511, 0x28, qvga?0x00:0x20, 0x20); - ov51x_i2c_write(ov511, 0x24, qvga?0x20:0x3a); - ov51x_i2c_write(ov511, 0x25, qvga?0x30:0x60); - ov51x_i2c_write_mask(ov511, 0x2d, qvga?0x40:0x00, 0x40); - ov51x_i2c_write_mask(ov511, 0x67, qvga?0xb0:0x90, 0xf0); - ov51x_i2c_write_mask(ov511, 0x74, qvga?0x20:0x00, 0x20); + i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); + i2c_w(ov, 0x24, qvga?0x20:0x3a); + i2c_w(ov, 0x25, qvga?0x30:0x60); + i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); + i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0); + i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); #endif break; case SEN_OV6620: case SEN_OV6630: - ov51x_i2c_write(ov511, 0x14, qvga?0x24:0x04); + i2c_w(ov, 0x14, qvga?0x24:0x04); /* No special settings yet */ break; default: @@ -2505,19 +2472,17 @@ /******** Palette-specific regs ********/ if (mode == VIDEO_PALETTE_GREY) { - if (ov511->sensor == SEN_OV7610 - || ov511->sensor == SEN_OV7620AE) { + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) { /* these aren't valid on the OV6620/OV7620/6630? */ - ov51x_i2c_write_mask(ov511, 0x0e, 0x40, 0x40); + i2c_w_mask(ov, 0x0e, 0x40, 0x40); } - ov51x_i2c_write_mask(ov511, 0x13, 0x20, 0x20); + i2c_w_mask(ov, 0x13, 0x20, 0x20); } else { - if (ov511->sensor == SEN_OV7610 - || ov511->sensor == SEN_OV7620AE) { + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) { /* not valid on the OV6620/OV7620/6630? */ - ov51x_i2c_write_mask(ov511, 0x0e, 0x00, 0x40); + i2c_w_mask(ov, 0x0e, 0x00, 0x40); } - ov51x_i2c_write_mask(ov511, 0x13, 0x00, 0x20); + i2c_w_mask(ov, 0x13, 0x00, 0x20); } /******** Clock programming ********/ @@ -2526,13 +2491,13 @@ /* The OV6620 needs special handling. This prevents the * severe banding that normally occurs */ - if (ov511->sensor == SEN_OV6620 || ov511->sensor == SEN_OV6630) + if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) { /* Clock down */ - ov51x_i2c_write(ov511, 0x2a, 0x04); + i2c_w(ov, 0x2a, 0x04); - if (ov511->compress) { + if (ov->compress) { // clock = 0; /* This ensures the highest frame rate */ clock = 3; } else if (clockdiv == -1) { /* If user didn't override it */ @@ -2543,21 +2508,21 @@ PDEBUG(4, "Setting clock divisor to %d", clock); - ov51x_i2c_write(ov511, 0x11, clock); + i2c_w(ov, 0x11, clock); - ov51x_i2c_write(ov511, 0x2a, 0x84); + i2c_w(ov, 0x2a, 0x84); /* This next setting is critical. It seems to improve * the gain or the contrast. The "reserved" bits seem * to have some effect in this case. */ - ov51x_i2c_write(ov511, 0x2d, 0x85); + i2c_w(ov, 0x2d, 0x85); } else { - if (ov511->compress) { + if (ov->compress) { clock = 1; /* This ensures the highest frame rate */ } else if (clockdiv == -1) { /* If user didn't override it */ /* Calculate and set the clock divisor */ - clock = ((sub_flag ? ov511->subw * ov511->subh + clock = ((sub_flag ? ov->subw * ov->subh : width * height) * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2) / 66000; @@ -2567,45 +2532,44 @@ PDEBUG(4, "Setting clock divisor to %d", clock); - ov51x_i2c_write(ov511, 0x11, clock); + i2c_w(ov, 0x11, clock); } /******** Special Features ********/ if (framedrop >= 0) - ov51x_i2c_write(ov511, 0x16, framedrop); + i2c_w(ov, 0x16, framedrop); /* We only have code to convert GBR -> RGB24 */ if ((mode == VIDEO_PALETTE_RGB24) && sensor_gbr) - ov51x_i2c_write_mask(ov511, 0x12, 0x08, 0x08); + i2c_w_mask(ov, 0x12, 0x08, 0x08); else - ov51x_i2c_write_mask(ov511, 0x12, 0x00, 0x08); + i2c_w_mask(ov, 0x12, 0x00, 0x08); /* Test Pattern */ - ov51x_i2c_write_mask(ov511, 0x12, (testpat?0x02:0x00), 0x02); + i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02); /* Auto white balance */ // if (awb) - ov51x_i2c_write_mask(ov511, 0x12, 0x04, 0x04); + i2c_w_mask(ov, 0x12, 0x04, 0x04); // else -// ov51x_i2c_write_mask(ov511, 0x12, 0x00, 0x04); +// i2c_w_mask(ov, 0x12, 0x00, 0x04); - // This will go away as soon as ov511_mode_init_sensor_regs() + // This will go away as soon as ov51x_mode_init_sensor_regs() // is fully tested. /* 7620/6620/6630? don't have register 0x35, so play it safe */ - if (ov511->sensor == SEN_OV7610 || - ov511->sensor == SEN_OV7620AE) { + if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV7620AE) { if (width == 640 && height == 480) - ov51x_i2c_write(ov511, 0x35, 0x9e); + i2c_w(ov, 0x35, 0x9e); else - ov51x_i2c_write(ov511, 0x35, 0x1e); + i2c_w(ov, 0x35, 0x1e); } return 0; } static int -set_ov_sensor_window(struct usb_ov511 *ov511, int width, int height, int mode, +set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag) { int ret; @@ -2614,7 +2578,7 @@ /* The different sensor ICs handle setting up of window differently. * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */ - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620AE: hwsbase = 0x38; @@ -2638,9 +2602,9 @@ return -EINVAL; } - if (ov511->sensor == SEN_OV6620 || ov511->sensor == SEN_OV6630) { + if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) { if (width > 176 && height > 144) { /* CIF */ - ret = mode_init_ov_sensor_regs(ov511, width, height, + ret = mode_init_ov_sensor_regs(ov, width, height, mode, sub_flag, 0); if (ret < 0) return ret; @@ -2652,7 +2616,7 @@ err("Illegal dimensions"); return -EINVAL; } else { /* QCIF */ - ret = mode_init_ov_sensor_regs(ov511, width, height, + ret = mode_init_ov_sensor_regs(ov, width, height, mode, sub_flag, 1); if (ret < 0) return ret; @@ -2661,7 +2625,7 @@ } } else { if (width > 320 && height > 240) { /* VGA */ - ret = mode_init_ov_sensor_regs(ov511, width, height, + ret = mode_init_ov_sensor_regs(ov, width, height, mode, sub_flag, 0); if (ret < 0) return ret; @@ -2673,7 +2637,7 @@ err("Illegal dimensions"); return -EINVAL; } else { /* QVGA */ - ret = mode_init_ov_sensor_regs(ov511, width, height, + ret = mode_init_ov_sensor_regs(ov, width, height, mode, sub_flag, 1); if (ret < 0) return ret; @@ -2689,24 +2653,20 @@ /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */ if (sub_flag) { - ov51x_i2c_write(ov511, 0x17, hwsbase+(ov511->subx>>hwscale)); - ov51x_i2c_write(ov511, 0x18, - hwebase+((ov511->subx+ov511->subw)>>hwscale)); - ov51x_i2c_write(ov511, 0x19, vwsbase+(ov511->suby>>vwscale)); - ov51x_i2c_write(ov511, 0x1a, - vwebase+((ov511->suby+ov511->subh)>>vwscale)); + i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale)); + i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale)); + i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale)); + i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale)); } else { - ov51x_i2c_write(ov511, 0x17, hwsbase + hoffset); - ov51x_i2c_write(ov511, 0x18, - hwebase + hoffset + (hwsize>>hwscale)); - ov51x_i2c_write(ov511, 0x19, vwsbase + voffset); - ov51x_i2c_write(ov511, 0x1a, - vwebase + voffset + (vwsize>>vwscale)); + i2c_w(ov, 0x17, hwsbase + hoffset); + i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale)); + i2c_w(ov, 0x19, vwsbase + voffset); + i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale)); } #ifdef OV511_DEBUG if (dump_sensor) - ov51x_dump_i2c_regs(ov511); + dump_i2c_regs(ov); #endif return 0; @@ -2717,18 +2677,14 @@ * Do not put any sensor-specific code in here (including I2C I/O functions) */ static int -ov511_mode_init_regs(struct usb_ov511 *ov511, +ov511_mode_init_regs(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag) { int lncnt, pxcnt, rc = 0; - struct usb_device *dev = ov511->dev; - - if (!ov511 || !dev) - return -EFAULT; if (sub_flag) { - width = ov511->subw; - height = ov511->subh; + width = ov->subw; + height = ov->subh; } PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", @@ -2736,7 +2692,7 @@ // FIXME: This should be moved to a 7111a-specific function once // subcapture is dealt with properly - if (ov511->sensor == SEN_SAA7111A) { + if (ov->sensor == SEN_SAA7111A) { if (width == 320 && height == 240) { /* No need to do anything special */ } else if (width == 640 && height == 480) { @@ -2755,26 +2711,22 @@ return -EINVAL; } - if (width < ov511->minwidth || height < ov511->minheight) { + if (width < ov->minwidth || height < ov->minheight) { err("Requested dimensions are too small"); return -EINVAL; } - if (ov511_stop(ov511) < 0) + if (ov51x_stop(ov) < 0) return -EIO; if (mode == VIDEO_PALETTE_GREY) { - ov511_reg_write(dev, 0x16, 0x00); - - /* For snapshot */ - ov511_reg_write(dev, 0x1e, 0x00); - ov511_reg_write(dev, 0x1f, 0x01); + reg_w(ov, R511_CAM_UV_EN, 0x00); + reg_w(ov, R511_SNAP_UV_EN, 0x00); + reg_w(ov, R511_SNAP_OPTS, 0x01); } else { - ov511_reg_write(dev, 0x16, 0x01); - - /* For snapshot */ - ov511_reg_write(dev, 0x1e, 0x01); - ov511_reg_write(dev, 0x1f, 0x03); + reg_w(ov, R511_CAM_UV_EN, 0x01); + reg_w(ov, R511_SNAP_UV_EN, 0x01); + reg_w(ov, R511_SNAP_OPTS, 0x03); } /* Here I'm assuming that snapshot size == image size. @@ -2783,25 +2735,28 @@ pxcnt = (width >> 3) - 1; lncnt = (height >> 3) - 1; - ov511_reg_write(dev, 0x12, pxcnt); - ov511_reg_write(dev, 0x13, lncnt); - ov511_reg_write(dev, 0x14, 0x00); - ov511_reg_write(dev, 0x15, 0x00); - ov511_reg_write(dev, 0x18, 0x03); /* YUV420, low pass filer on */ + reg_w(ov, R511_CAM_PXCNT, pxcnt); + reg_w(ov, R511_CAM_LNCNT, lncnt); + reg_w(ov, R511_CAM_PXDIV, 0x00); + reg_w(ov, R511_CAM_LNDIV, 0x00); + + /* YUV420, low pass filer on */ + reg_w(ov, R511_CAM_OPTS, 0x03); /* Snapshot additions */ - ov511_reg_write(dev, 0x1a, pxcnt); - ov511_reg_write(dev, 0x1b, lncnt); - ov511_reg_write(dev, 0x1c, 0x00); - ov511_reg_write(dev, 0x1d, 0x00); - - if (ov511->compress) { - ov511_reg_write(dev, 0x78, 0x07); // Turn on Y & UV compression - ov511_reg_write(dev, 0x79, 0x03); // Enable LUTs - ov511_reset(ov511, OV511_RESET_OMNICE); + reg_w(ov, R511_SNAP_PXCNT, pxcnt); + reg_w(ov, R511_SNAP_LNCNT, lncnt); + reg_w(ov, R511_SNAP_PXDIV, 0x00); + reg_w(ov, R511_SNAP_LNDIV, 0x00); + + if (ov->compress) { + /* Enable Y and UV quantization and compression */ + reg_w(ov, R511_COMP_EN, 0x07); + reg_w(ov, R511_COMP_LUT_EN, 0x03); + ov51x_reset(ov, OV511_RESET_OMNICE); } //out: - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; return rc; @@ -2825,17 +2780,15 @@ * Do not put any sensor-specific code in here (including I2C I/O functions) */ static int -ov518_mode_init_regs(struct usb_ov511 *ov511, +ov518_mode_init_regs(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag) { int i; - struct usb_device *dev = ov511->dev; - unsigned char b[3]; /* Multiple-value reg buffer */ PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", width, height, mode, sub_flag); - if (ov511_stop(ov511) < 0) + if (ov51x_stop(ov) < 0) return -EIO; for (i = 0; mlist518[i].width; i++) { @@ -2853,113 +2806,94 @@ // pxcnt = sub_flag ? (ov511->subw >> 3) - 1 : mlist[i].pxcnt; // lncnt = sub_flag ? (ov511->subh >> 3) - 1 : mlist[i].lncnt; // -// ov511_reg_write(dev, 0x12, pxcnt); -// ov511_reg_write(dev, 0x13, lncnt); +// reg_w(ov511, 0x12, pxcnt); +// reg_w(ov511, 0x13, lncnt); /******** Set the mode ********/ /* Mode independent regs */ - ov511_reg_write(dev, 0x2b, 0x00); - ov511_reg_write(dev, 0x2d, 0x00); - ov511_reg_write(dev, 0x3b, 0x00); - ov511_reg_write(dev, 0x3d, 0x00); + reg_w(ov, 0x2b, 0x00); + reg_w(ov, 0x2d, 0x00); + reg_w(ov, 0x3b, 0x00); + reg_w(ov, 0x3d, 0x00); /* Mode dependent regs. Regs 38 - 3e are always the same as * regs 28 - 2e */ - ov511_reg_write_mask(dev, 0x28, mlist518[i].reg28 + reg_w_mask(ov, 0x28, mlist518[i].reg28 | (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f); - ov511_reg_write(dev, 0x29, mlist518[i].reg29); - ov511_reg_write(dev, 0x2a, mlist518[i].reg2a); - ov511_reg_write(dev, 0x2c, mlist518[i].reg2c); - ov511_reg_write(dev, 0x2e, mlist518[i].reg2e); - ov511_reg_write_mask(dev, 0x38, mlist518[i].reg28 + reg_w(ov, 0x29, mlist518[i].reg29); + reg_w(ov, 0x2a, mlist518[i].reg2a); + reg_w(ov, 0x2c, mlist518[i].reg2c); + reg_w(ov, 0x2e, mlist518[i].reg2e); + reg_w_mask(ov, 0x38, mlist518[i].reg28 | (mode == VIDEO_PALETTE_GREY) ? 0x80:0x00, 0x8f); - ov511_reg_write(dev, 0x39, mlist518[i].reg29); - ov511_reg_write(dev, 0x3a, mlist518[i].reg2a); - ov511_reg_write(dev, 0x3c, mlist518[i].reg2c); - ov511_reg_write(dev, 0x3e, mlist518[i].reg2e); - ov511_reg_write(dev, 0x24, mlist518[i].reg24); - ov511_reg_write(dev, 0x25, mlist518[i].reg25); + reg_w(ov, 0x39, mlist518[i].reg29); + reg_w(ov, 0x3a, mlist518[i].reg2a); + reg_w(ov, 0x3c, mlist518[i].reg2c); + reg_w(ov, 0x3e, mlist518[i].reg2e); + reg_w(ov, 0x24, mlist518[i].reg24); + reg_w(ov, 0x25, mlist518[i].reg25); /* Windows driver does this here; who knows why */ - ov511_reg_write(dev, 0x2f, 0x80); + reg_w(ov, 0x2f, 0x80); /******** Set the framerate (to 15 FPS) ********/ /* Mode independent, but framerate dependent, regs */ /* These are for 15 FPS only */ - ov511_reg_write(dev, 0x51, 0x08); - ov511_reg_write(dev, 0x22, 0x18); - ov511_reg_write(dev, 0x23, 0xff); - ov511_reg_write(dev, 0x71, 0x19); /* Compression-related? */ + reg_w(ov, 0x51, 0x08); + reg_w(ov, 0x22, 0x18); + reg_w(ov, 0x23, 0xff); + reg_w(ov, 0x71, 0x19); /* Compression-related? */ // FIXME: Sensor-specific /* Bit 5 is what matters here. Of course, it is "reserved" */ - ov51x_i2c_write(ov511, 0x54, 0x23); + i2c_w(ov, 0x54, 0x23); - ov511_reg_write(dev, 0x2f, 0x80); + reg_w(ov, 0x2f, 0x80); /* Mode dependent regs */ if ((width == 352 && height == 288) || (width == 320 && height == 240)) { - b[0]=0x80; b[1]=0x02; - ov518_reg_write_multi(dev, 0x30, b, 2); - b[0]=0x90; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc4, b, 2); - b[0]=0xf4; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc6, b, 2); - b[0]=0xf4; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc7, b, 2); - b[0]=0x8e; b[1]=0x00; - ov518_reg_write_multi(dev, 0xc8, b, 2); - b[0]=0x1a; b[1]=0x00; b[2]=0x02; - ov518_reg_write_multi(dev, 0xca, b, 3); - b[0]=0x14; b[1]=0x02; - ov518_reg_write_multi(dev, 0xcb, b, 2); - b[0]=0xd0; b[1]=0x07; - ov518_reg_write_multi(dev, 0xcc, b, 2); - b[0]=0x20; b[1]=0x00; - ov518_reg_write_multi(dev, 0xcd, b, 2); - b[0]=0x60; b[1]=0x02; - ov518_reg_write_multi(dev, 0xce, b, 2); - + /* 640 (280h) byte iso packets */ + ov518_reg_w32(ov, 0x30, 640, 2); /* 280h */ + ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ + ov518_reg_w32(ov, 0xc6, 500, 2); /* 1f4h */ + ov518_reg_w32(ov, 0xc7, 500, 2); /* 1f4h */ + ov518_reg_w32(ov, 0xc8, 142, 2); /* 8eh */ + ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ + ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ + ov518_reg_w32(ov, 0xcc, 2000, 2); /* 7d0h */ + ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ + ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ } else if ((width == 176 && height == 144) || (width == 160 && height == 120)) { - b[0]=0x80; b[1]=0x01; - ov518_reg_write_multi(dev, 0x30, b, 2); - b[0]=0xc8; b[1]=0x00; - ov518_reg_write_multi(dev, 0xc4, b, 2); - b[0]=0x40; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc6, b, 2); - b[0]=0x40; b[1]=0x01; - ov518_reg_write_multi(dev, 0xc7, b, 2); - b[0]=0x60; b[1]=0x00; - ov518_reg_write_multi(dev, 0xc8, b, 2); - b[0]=0x0f; b[1]=0x33; b[2]=0x01; - ov518_reg_write_multi(dev, 0xca, b, 3); - b[0]=0x40; b[1]=0x01; - ov518_reg_write_multi(dev, 0xcb, b, 2); - b[0]=0xec; b[1]=0x04; - ov518_reg_write_multi(dev, 0xcc, b, 2); - b[0]=0x13; b[1]=0x00; - ov518_reg_write_multi(dev, 0xcd, b, 2); - b[0]=0x6d; b[1]=0x01; - ov518_reg_write_multi(dev, 0xce, b, 2); + /* 384 (180h) byte iso packets */ + ov518_reg_w32(ov, 0x30, 384, 2); /* 180h */ + ov518_reg_w32(ov, 0xc4, 200, 2); /* c8h */ + ov518_reg_w32(ov, 0xc6, 320, 2); /* 140h */ + ov518_reg_w32(ov, 0xc7, 320, 2); /* 140h */ + ov518_reg_w32(ov, 0xc8, 96, 2); /* 60h */ + ov518_reg_w32(ov, 0xca, 78607, 3); /* 1330fh */ + ov518_reg_w32(ov, 0xcb, 320, 2); /* 140h */ + ov518_reg_w32(ov, 0xcc, 1260, 2); /* 4ech */ + ov518_reg_w32(ov, 0xcd, 19, 2); /* 13h */ + ov518_reg_w32(ov, 0xce, 365, 2); /* 16dh */ } else { /* Can't happen, since we already handled this case */ err("ov518_mode_init_regs(): **** logic error ****"); } - ov511_reg_write(dev, 0x2f, 0x80); + reg_w(ov, 0x2f, 0x80); break; } - if (ov511_restart(ov511) < 0) + if (ov51x_restart(ov) < 0) return -EIO; /* Reset it just for good measure */ - if (ov511_reset(ov511, OV511_RESET_NOREGS) < 0) + if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) return -EIO; if (mlist518[i].width == 0) { @@ -2972,29 +2906,31 @@ /* This is a wrapper around the OV511, OV518, and sensor specific functions */ static int -mode_init_regs(struct usb_ov511 *ov511, +mode_init_regs(struct usb_ov511 *ov, int width, int height, int mode, int sub_flag) { int rc = 0; - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { - rc = ov518_mode_init_regs(ov511, width, height, mode, sub_flag); + if (!ov || !ov->dev) + return -EFAULT; + + if (ov->bclass == BCL_OV518) { + rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag); } else { - rc = ov511_mode_init_regs(ov511, width, height, mode, sub_flag); + rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag); } if (FATAL_ERROR(rc)) return rc; - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_OV7610: case SEN_OV7620: case SEN_OV7620AE: case SEN_OV8600: case SEN_OV6620: case SEN_OV6630: - rc = set_ov_sensor_window(ov511, width, height, mode, sub_flag); + rc = set_ov_sensor_window(ov, width, height, mode, sub_flag); break; case SEN_KS0127: case SEN_KS0127B: @@ -3002,10 +2938,10 @@ rc = -EINVAL; break; case SEN_SAA7111A: -// rc = mode_init_saa_sensor_regs(ov511, width, height, mode, +// rc = mode_init_saa_sensor_regs(ov, width, height, mode, // sub_flag); - PDEBUG(1, "SAA status = 0X%x", ov51x_i2c_read(ov511, 0x1f)); + PDEBUG(1, "SAA status = 0X%x", i2c_r(ov, 0x1f)); break; default: err("Unknown sensor"); @@ -3016,25 +2952,25 @@ return rc; /* Sensor-independent settings */ - rc = sensor_set_auto_brightness(ov511, ov511->auto_brt); + rc = sensor_set_auto_brightness(ov, ov->auto_brt); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_auto_exposure(ov511, ov511->auto_exp); + rc = sensor_set_auto_exposure(ov, ov->auto_exp); if (FATAL_ERROR(rc)) return rc; - rc = sensor_set_banding_filter(ov511, bandingfilter); + rc = sensor_set_banding_filter(ov, bandingfilter); if (FATAL_ERROR(rc)) return rc; - if (ov511->lightfreq) { - rc = sensor_set_light_freq(ov511, lightfreq); + if (ov->lightfreq) { + rc = sensor_set_light_freq(ov, lightfreq); if (FATAL_ERROR(rc)) return rc; } - rc = sensor_set_backlight(ov511, ov511->backlight); + rc = sensor_set_backlight(ov, ov->backlight); if (FATAL_ERROR(rc)) return rc; @@ -3045,28 +2981,28 @@ * useful for apps that use read() and do not set these. */ static int -ov51x_set_default_params(struct usb_ov511 *ov511) +ov51x_set_default_params(struct usb_ov511 *ov) { int i; - PDEBUG(3, "%dx%d, RGB24", ov511->maxwidth, ov511->maxheight); + PDEBUG(3, "%dx%d, RGB24", ov->maxwidth, ov->maxheight); /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used * (using read() instead). */ for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].width = ov511->maxwidth; - ov511->frame[i].height = ov511->maxheight; - ov511->frame[i].bytes_read = 0; + ov->frame[i].width = ov->maxwidth; + ov->frame[i].height = ov->maxheight; + ov->frame[i].bytes_read = 0; if (force_palette) - ov511->frame[i].format = force_palette; + ov->frame[i].format = force_palette; else - ov511->frame[i].format = VIDEO_PALETTE_RGB24; - ov511->frame[i].depth = ov511_get_depth(ov511->frame[i].format); + ov->frame[i].format = VIDEO_PALETTE_RGB24; + ov->frame[i].depth = get_depth(ov->frame[i].format); } /* Initialize to max width/height, RGB24 */ - if (mode_init_regs(ov511, ov511->maxwidth, ov511->maxheight, - ov511->frame[0].format, 0) < 0) + if (mode_init_regs(ov, ov->maxwidth, ov->maxheight, + ov->frame[0].format, 0) < 0) return -EINVAL; return 0; @@ -3080,18 +3016,17 @@ /* Set analog input port of decoder */ static int -decoder_set_input(struct usb_ov511 *ov511, int input) +decoder_set_input(struct usb_ov511 *ov, int input) { PDEBUG(4, "port %d", input); - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_SAA7111A: { /* Select mode */ - ov51x_i2c_write_mask(ov511, 0x02, input, 0x07); + i2c_w_mask(ov, 0x02, input, 0x07); /* Bypass chrominance trap for modes 4..7 */ - ov51x_i2c_write_mask(ov511, 0x09, - (input > 3) ? 0x80:0x00, 0x80); + i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80); break; } default: @@ -3103,9 +3038,9 @@ /* Get ASCII name of video input */ static int -decoder_get_input_name(struct usb_ov511 *ov511, int input, char *name) +decoder_get_input_name(struct usb_ov511 *ov, int input, char *name) { - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_SAA7111A: { if (input < 0 || input > 7) @@ -3126,11 +3061,11 @@ /* Set norm (NTSC, PAL, SECAM, AUTO) */ static int -decoder_set_norm(struct usb_ov511 *ov511, int norm) +decoder_set_norm(struct usb_ov511 *ov, int norm) { PDEBUG(4, "%d", norm); - switch (ov511->sensor) { + switch (ov->sensor) { case SEN_SAA7111A: { int reg_8, reg_e; @@ -3151,8 +3086,8 @@ return -EINVAL; } - ov51x_i2c_write_mask(ov511, 0x08, reg_8, 0xc0); - ov51x_i2c_write_mask(ov511, 0x0e, reg_e, 0x70); + i2c_w_mask(ov, 0x08, reg_8, 0xc0); + i2c_w_mask(ov, 0x0e, reg_e, 0x70); break; } default: @@ -3199,8 +3134,8 @@ #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16))) static inline void -ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, - int rowPixels, unsigned char * rgb, int bits) +move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, + int rowPixels, unsigned char * rgb, int bits) { const int rvScale = 91881; const int guScale = -22553; @@ -3270,10 +3205,10 @@ **********************************************************************/ /* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the - * array at pOut is specified by w. + * image at pOut is specified by w. */ static inline void -ov511_make_8x8(unsigned char *pIn, unsigned char *pOut, int w) +make_8x8(unsigned char *pIn, unsigned char *pOut, int w) { unsigned char *pOut1 = pOut; int x, y; @@ -3311,7 +3246,7 @@ for (y = 0; y < frame->rawheight - 1; y += 8) { pOut = pOutLine; for (x = 0; x < frame->rawwidth - 1; x += 8) { - ov511_make_8x8(pIn, pOut, frame->rawwidth); + make_8x8(pIn, pOut, frame->rawwidth); pIn += 64; pOut += 8; } @@ -3370,8 +3305,8 @@ for (y = 0; y < frame->rawheight - 1; y += 16) { pOut = pOutLine; for (x = 0; x < frame->rawwidth - 1; x += 16) { - ov511_make_8x8(pIn, pOut, w); - ov511_make_8x8(pIn + 64, pOut + a/4, w); + make_8x8(pIn, pOut, w); + make_8x8(pIn + 64, pOut + a/4, w); pIn += 384; pOut += 8; } @@ -3385,7 +3320,7 @@ for (y = 0; y < frame->rawheight - 1; y += 8) { pOut = pOutLine; for (x = 0; x < frame->rawwidth - 1; x += 8) { - ov511_make_8x8(pIn, pOut, frame->rawwidth); + make_8x8(pIn, pOut, frame->rawwidth); pIn += 64; pOut += 8; if ((++k) > 3) { @@ -3442,17 +3377,17 @@ * **********************************************************************/ -/* Chooses a decompression module, locks it, and sets ov511->decomp_ops +/* Chooses a decompression module, locks it, and sets ov->decomp_ops * accordingly. Returns -ENXIO if decompressor is not available, otherwise * returns 0 if no other error. */ static int -ov51x_request_decompressor(struct usb_ov511 *ov511) +request_decompressor(struct usb_ov511 *ov) { - if (!ov511) + if (!ov) return -ENODEV; - if (ov511->decomp_ops) { + if (ov->decomp_ops) { err("ERROR: Decompressor already requested!"); return -EINVAL; } @@ -3460,24 +3395,23 @@ lock_kernel(); /* Try to get MMX, and fall back on no-MMX if necessary */ - if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { + if (ov->bclass == BCL_OV511) { if (ov511_mmx_decomp_ops) { PDEBUG(3, "Using OV511 MMX decompressor"); - ov511->decomp_ops = ov511_mmx_decomp_ops; + ov->decomp_ops = ov511_mmx_decomp_ops; } else if (ov511_decomp_ops) { PDEBUG(3, "Using OV511 decompressor"); - ov511->decomp_ops = ov511_decomp_ops; + ov->decomp_ops = ov511_decomp_ops; } else { err("No decompressor available"); } - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + } else if (ov->bclass == BCL_OV518) { if (ov518_mmx_decomp_ops) { PDEBUG(3, "Using OV518 MMX decompressor"); - ov511->decomp_ops = ov518_mmx_decomp_ops; + ov->decomp_ops = ov518_mmx_decomp_ops; } else if (ov518_decomp_ops) { PDEBUG(3, "Using OV518 decompressor"); - ov511->decomp_ops = ov518_decomp_ops; + ov->decomp_ops = ov518_decomp_ops; } else { err("No decompressor available"); } @@ -3485,13 +3419,13 @@ err("Unknown bridge"); } - if (ov511->decomp_ops) { - if (!ov511->decomp_ops->decomp_lock) { - ov511->decomp_ops = NULL; + if (ov->decomp_ops) { + if (!ov->decomp_ops->decomp_lock) { + ov->decomp_ops = NULL; unlock_kernel(); return -ENOSYS; } - ov511->decomp_ops->decomp_lock(); + ov->decomp_ops->decomp_lock(); unlock_kernel(); return 0; } else { @@ -3500,25 +3434,25 @@ } } -/* Unlocks decompression module and nulls ov511->decomp_ops. Safe to call even - * if ov511->decomp_ops is NULL. +/* Unlocks decompression module and nulls ov->decomp_ops. Safe to call even + * if ov->decomp_ops is NULL. */ static void -ov51x_release_decompressor(struct usb_ov511 *ov511) +release_decompressor(struct usb_ov511 *ov) { int released = 0; /* Did we actually do anything? */ - if (!ov511) + if (!ov) return; lock_kernel(); - if (ov511->decomp_ops && ov511->decomp_ops->decomp_unlock) { - ov511->decomp_ops->decomp_unlock(); + if (ov->decomp_ops && ov->decomp_ops->decomp_unlock) { + ov->decomp_ops->decomp_unlock(); released = 1; } - ov511->decomp_ops = NULL; + ov->decomp_ops = NULL; unlock_kernel(); @@ -3527,26 +3461,26 @@ } static void -ov51x_decompress(struct usb_ov511 *ov511, struct ov511_frame *frame, - unsigned char *pIn0, unsigned char *pOut0) +decompress(struct usb_ov511 *ov, struct ov511_frame *frame, + unsigned char *pIn0, unsigned char *pOut0) { - if (!ov511->decomp_ops) - if (ov51x_request_decompressor(ov511)) + if (!ov->decomp_ops) + if (request_decompressor(ov)) return; PDEBUG(4, "Decompressing %d bytes", frame->bytes_recvd); if (frame->format == VIDEO_PALETTE_GREY - && ov511->decomp_ops->decomp_400) { - int ret = ov511->decomp_ops->decomp_400( + && ov->decomp_ops->decomp_400) { + int ret = ov->decomp_ops->decomp_400( pIn0, pOut0, frame->rawwidth, frame->rawheight, frame->bytes_recvd); PDEBUG(4, "DEBUG: decomp_400 returned %d", ret); - } else if (ov511->decomp_ops->decomp_420) { - int ret = ov511->decomp_ops->decomp_420( + } else if (ov->decomp_ops->decomp_420) { + int ret = ov->decomp_ops->decomp_420( pIn0, pOut0, frame->rawwidth, @@ -3586,8 +3520,8 @@ u = (*pU++) - 128; v = (*pV++) - 128; - ov511_move_420_block(y00, y01, y10, y11, u, v, - frame->width, pOut, bits); + move_420_block(y00, y01, y10, y11, u, v, + frame->width, pOut, bits); pY += 2; pOut += 2 * bytes; @@ -3742,11 +3676,11 @@ * 4. Fix the RGB offset, if necessary */ static void -ov511_postprocess(struct usb_ov511 *ov511, struct ov511_frame *frame) +ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame) { if (dumppix) { memset(frame->data, 0, - MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight)); + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd); memmove(frame->data, frame->rawdata, frame->bytes_recvd); return; @@ -3755,9 +3689,9 @@ /* YUV400 must be handled separately */ if (frame->format == VIDEO_PALETTE_GREY) { /* Deinterlace frame, if necessary */ - if (ov511->sensor == SEN_SAA7111A && frame->rawheight == 480) { + if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) { if (frame->compressed) - ov51x_decompress(ov511, frame, frame->rawdata, + decompress(ov, frame, frame->rawdata, frame->tempdata); else yuv400raw_to_yuv400p(frame, frame->rawdata, @@ -3767,7 +3701,7 @@ frame->data); } else { if (frame->compressed) - ov51x_decompress(ov511, frame, frame->rawdata, + decompress(ov, frame, frame->rawdata, frame->data); else yuv400raw_to_yuv400p(frame, frame->rawdata, @@ -3779,12 +3713,12 @@ /* Process frame->data to frame->rawdata */ if (frame->compressed) - ov51x_decompress(ov511, frame, frame->rawdata, frame->tempdata); + decompress(ov, frame, frame->rawdata, frame->tempdata); else yuv420raw_to_yuv420p(frame, frame->rawdata, frame->tempdata); /* Deinterlace frame, if necessary */ - if (ov511->sensor == SEN_SAA7111A && frame->rawheight == 480) { + if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) { memmove(frame->rawdata, frame->tempdata, MAX_RAW_DATA_SIZE(frame->width, frame->height)); deinterlace(frame, RAWFMT_YUV420, frame->rawdata, @@ -3838,7 +3772,7 @@ **********************************************************************/ static int -ov511_move_data(struct usb_ov511 *ov511, struct urb *urb) +ov511_move_data(struct usb_ov511 *ov, struct urb *urb) { unsigned char *cdata; int data_size, num, offset, i, totlen = 0; @@ -3848,7 +3782,7 @@ PDEBUG(5, "Moving %d packets", urb->number_of_packets); - data_size = ov511->packet_size - 1; + data_size = ov->packet_size - 1; for (i = 0; i < urb->number_of_packets; i++) { int n = urb->iso_frame_desc[i].actual_length; @@ -3859,15 +3793,15 @@ cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1; + aPackNum[i] = n ? cdata[ov->packet_size - 1] : -1; - if (!n || ov511->curframe == -1) + if (!n || ov->curframe == -1) continue; if (st) PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st); - frame = &ov511->frame[ov511->curframe]; + frame = &ov->frame[ov->curframe]; /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th * byte non-zero. The EOF packet has image width/height in the @@ -3885,7 +3819,7 @@ if (printph) { info("packet header (%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", - cdata[ov511->packet_size - 1], + cdata[ov->packet_size - 1], cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5], cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]); } @@ -3899,7 +3833,7 @@ /* Frame end */ if (cdata[8] & 0x80) { ts = (struct timeval *)(frame->data - + MAX_FRAME_SIZE(ov511->maxwidth, ov511->maxheight)); + + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); do_gettimeofday(ts); /* Get the actual frame size from the EOF header */ @@ -3907,21 +3841,21 @@ frame->rawheight = ((int)(cdata[10]) + 1) * 8; PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d, recvd=%d", - ov511->curframe, - (int)(cdata[ov511->packet_size - 1]), + ov->curframe, + (int)(cdata[ov->packet_size - 1]), frame->rawwidth, frame->rawheight, frame->bytes_recvd); /* Validate the header data */ - RESTRICT_TO_RANGE(frame->rawwidth, ov511->minwidth, ov511->maxwidth); - RESTRICT_TO_RANGE(frame->rawheight, ov511->minheight, ov511->maxheight); + RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); + RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); /* Don't allow byte count to exceed buffer size */ RESTRICT_TO_RANGE(frame->bytes_recvd, 8, - MAX_RAW_DATA_SIZE(ov511->maxwidth, - ov511->maxheight)); + MAX_RAW_DATA_SIZE(ov->maxwidth, + ov->maxheight)); if (frame->scanstate == STATE_LINES) { int iFrameNext; @@ -3935,20 +3869,20 @@ /* If next frame is ready or grabbing, * point to it */ - iFrameNext = (ov511->curframe + 1) % OV511_NUMFRAMES; - if (ov511->frame[iFrameNext].grabstate == FRAME_READY - || ov511->frame[iFrameNext].grabstate == FRAME_GRABBING) { - ov511->curframe = iFrameNext; - ov511->frame[iFrameNext].scanstate = STATE_SCANNING; + iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES; + if (ov->frame[iFrameNext].grabstate == FRAME_READY + || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) { + ov->curframe = iFrameNext; + ov->frame[iFrameNext].scanstate = STATE_SCANNING; } else { if (frame->grabstate == FRAME_DONE) { PDEBUG(4, "Frame done! congratulations"); } else { PDEBUG(4, "Frame not ready? state = %d", - ov511->frame[iFrameNext].grabstate); + ov->frame[iFrameNext].grabstate); } - ov511->curframe = -1; + ov->curframe = -1; } } else { PDEBUG(5, "Frame done, but not scanning"); @@ -3958,7 +3892,7 @@ */ } else { /* Frame start */ - PDEBUG(4, "Frame start, framenum = %d", ov511->curframe); + PDEBUG(4, "Frame start, framenum = %d", ov->curframe); /* Check to see if it's a snapshot frame */ /* FIXME?? Should the snapshot reset go here? Performance? */ @@ -4007,24 +3941,24 @@ /* Dump all data exactly as received */ if (dumppix == 2) { frame->bytes_recvd += n - 1; - if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) + if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) memmove(frame->rawdata + frame->bytes_recvd - (n - 1), &cdata[0], n - 1); else PDEBUG(3, "Raw data buffer overrun!! (%d)", frame->bytes_recvd - - MAX_RAW_DATA_SIZE(ov511->maxwidth, - ov511->maxheight)); + - MAX_RAW_DATA_SIZE(ov->maxwidth, + ov->maxheight)); } else if (!frame->compressed && !remove_zeros) { frame->bytes_recvd += num; - if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) + if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) memmove(frame->rawdata + frame->bytes_recvd - num, &cdata[offset], num); else PDEBUG(3, "Raw data buffer overrun!! (%d)", frame->bytes_recvd - - MAX_RAW_DATA_SIZE(ov511->maxwidth, - ov511->maxheight)); + - MAX_RAW_DATA_SIZE(ov->maxwidth, + ov->maxheight)); } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */ int b, in = 0, allzero, copied=0; if (offset) { @@ -4047,7 +3981,7 @@ /* Don't copy it */ } else { if (frame->bytes_recvd + copied + 32 - <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) { + <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) { memmove(frame->rawdata + frame->bytes_recvd + copied, &cdata[in], 32); copied += 32; @@ -4071,7 +4005,7 @@ } static int -ov518_move_data(struct usb_ov511 *ov511, struct urb *urb) +ov518_move_data(struct usb_ov511 *ov, struct urb *urb) { unsigned char *cdata; int i, data_size, totlen = 0; @@ -4081,7 +4015,7 @@ PDEBUG(5, "Moving %d packets", urb->number_of_packets); /* OV518(+) has no packet numbering */ - data_size = ov511->packet_size; + data_size = ov->packet_size; for (i = 0; i < urb->number_of_packets; i++) { int n = urb->iso_frame_desc[i].actual_length; @@ -4097,7 +4031,7 @@ continue; } - if (ov511->curframe == -1) { + if (ov->curframe == -1) { PDEBUG(4, "No frame currently active"); continue; } @@ -4105,21 +4039,7 @@ if (st) PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st); - frame = &ov511->frame[ov511->curframe]; - -#if 0 - { - int d; - /* Print all data */ - for (d = 0; d <= data_size - 16; d += 16) { - info("%4x: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", d, - cdata[d], cdata[d+1], cdata[d+2], cdata[d+3], - cdata[d+4], cdata[d+5], cdata[d+6], cdata[d+7], - cdata[d+8], cdata[d+9], cdata[d+10], cdata[d+11], - cdata[d+12], cdata[d+13], cdata[d+14], cdata[d+15]); - } - } -#endif + frame = &ov->frame[ov->curframe]; if (printph) { info("packet header: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", @@ -4137,7 +4057,7 @@ goto eof; } else { //scanstate == STATE_SCANNING /* Frame start */ - PDEBUG(4, "Frame start, framenum = %d", ov511->curframe); + PDEBUG(4, "Frame start, framenum = %d", ov->curframe); goto sof; } } else { @@ -4146,11 +4066,11 @@ eof: ts = (struct timeval *)(frame->data - + MAX_FRAME_SIZE(ov511->maxwidth, ov511->maxheight)); + + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); do_gettimeofday(ts); PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d", - ov511->curframe, + ov->curframe, (int)(cdata[9]), (int)(cdata[10]), frame->bytes_recvd); // FIXME: Since we don't know the header formats yet, @@ -4159,13 +4079,13 @@ frame->rawheight = frame->height; /* Validate the header data */ - RESTRICT_TO_RANGE(frame->rawwidth, ov511->minwidth, ov511->maxwidth); - RESTRICT_TO_RANGE(frame->rawheight, ov511->minheight, ov511->maxheight); + RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); + RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); /* Don't allow byte count to exceed buffer size */ RESTRICT_TO_RANGE(frame->bytes_recvd, 8, - MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)); + MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)); if (frame->scanstate == STATE_LINES) { int iFrameNext; @@ -4179,21 +4099,21 @@ /* If next frame is ready or grabbing, * point to it */ - iFrameNext = (ov511->curframe + 1) % OV511_NUMFRAMES; - if (ov511->frame[iFrameNext].grabstate == FRAME_READY - || ov511->frame[iFrameNext].grabstate == FRAME_GRABBING) { - ov511->curframe = iFrameNext; - ov511->frame[iFrameNext].scanstate = STATE_SCANNING; - frame = &ov511->frame[iFrameNext]; + iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES; + if (ov->frame[iFrameNext].grabstate == FRAME_READY + || ov->frame[iFrameNext].grabstate == FRAME_GRABBING) { + ov->curframe = iFrameNext; + ov->frame[iFrameNext].scanstate = STATE_SCANNING; + frame = &ov->frame[iFrameNext]; } else { if (frame->grabstate == FRAME_DONE) { PDEBUG(4, "Frame done! congratulations"); } else { PDEBUG(4, "Frame not ready? state = %d", - ov511->frame[iFrameNext].grabstate); + ov->frame[iFrameNext].grabstate); } - ov511->curframe = -1; + ov->curframe = -1; PDEBUG(4, "SOF dropped (no active frame)"); continue; /* Nowhere to store this frame */ } @@ -4226,31 +4146,26 @@ /* Dump all data exactly as received */ if (dumppix == 2) { frame->bytes_recvd += n; - if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) + if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) memmove(frame->rawdata + frame->bytes_recvd - n, &cdata[0], n); else PDEBUG(3, "Raw data buffer overrun!! (%d)", frame->bytes_recvd - - MAX_RAW_DATA_SIZE(ov511->maxwidth, - ov511->maxheight)); + - MAX_RAW_DATA_SIZE(ov->maxwidth, + ov->maxheight)); } else { /* All incoming data are divided into 8-byte segments. If the * segment contains all zero bytes, it must be skipped. These * zero-segments allow the OV518 to mainain a constant data rate * regardless of the effectiveness of the compression. Segments * are aligned relative to the beginning of each isochronous - * packet. The first segment is a header. + * packet. The first segment is a header (the decompressor + * skips it later). */ int b, in = 0, allzero, copied=0; -// Decompressor expects the header -#if 0 - if (frame->bytes_recvd == 0) - in += 8; /* Skip header */ -#endif - while (in < n) { allzero = 1; for (b = 0; b < 8; b++) { @@ -4264,7 +4179,7 @@ /* Don't copy it */ } else { if (frame->bytes_recvd + copied + 8 - <= MAX_RAW_DATA_SIZE(ov511->maxwidth, ov511->maxheight)) { + <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) { memmove(frame->rawdata + frame->bytes_recvd + copied, &cdata[in], 8); copied += 8; @@ -4282,43 +4197,41 @@ } static void -ov511_isoc_irq(struct urb *urb) +ov51x_isoc_irq(struct urb *urb) { int len; - struct usb_ov511 *ov511; + struct usb_ov511 *ov; if (!urb->context) { PDEBUG(4, "no context"); return; } - ov511 = (struct usb_ov511 *) urb->context; + ov = (struct usb_ov511 *) urb->context; - if (!ov511->dev || !ov511->user) { + if (!ov || !ov->dev || !ov->user) { PDEBUG(4, "no device, or not open"); return; } - if (!ov511->streaming) { + if (!ov->streaming) { PDEBUG(4, "hmmm... not streaming, but got interrupt"); return; } /* Copy the data received into our frame buffer */ - if (ov511->curframe >= 0) { - if (ov511->bridge == BRG_OV511 || - ov511->bridge == BRG_OV511PLUS) - len = ov511_move_data(ov511, urb); - else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - len = ov518_move_data(ov511, urb); + if (ov->curframe >= 0) { + if (ov->bclass == BCL_OV511) + len = ov511_move_data(ov, urb); + else if (ov->bclass == BCL_OV518) + len = ov518_move_data(ov, urb); else - err("Unknown bridge device (%d)", ov511->bridge); - } else if (waitqueue_active(&ov511->wq)) { - wake_up_interruptible(&ov511->wq); + err("Unknown bridge device (%d)", ov->bridge); + } else if (waitqueue_active(&ov->wq)) { + wake_up_interruptible(&ov->wq); } - urb->dev = ov511->dev; + urb->dev = ov->dev; return; } @@ -4330,16 +4243,16 @@ ***************************************************************************/ static int -ov511_init_isoc(struct usb_ov511 *ov511) +ov51x_init_isoc(struct usb_ov511 *ov) { struct urb *urb; int fx, err, n, size; PDEBUG(3, "*** Initializing capture ***"); - ov511->curframe = -1; + ov->curframe = -1; - if (ov511->bridge == BRG_OV511) { + if (ov->bridge == BRG_OV511) { if (cams == 1) size = 993; else if (cams == 2) size = 513; else if (cams == 3 || cams == 4) size = 257; @@ -4347,7 +4260,7 @@ err("\"cams\" parameter too high!"); return -1; } - } else if (ov511->bridge == BRG_OV511PLUS) { + } else if (ov->bridge == BRG_OV511PLUS) { if (cams == 1) size = 961; else if (cams == 2) size = 513; else if (cams == 3 || cams == 4) size = 257; @@ -4357,8 +4270,7 @@ err("\"cams\" parameter too high!"); return -1; } - } else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { + } else if (ov->bclass == BCL_OV518) { if (cams == 1) size = 896; else if (cams == 2) size = 512; else if (cams == 3 || cams == 4) size = 256; @@ -4374,14 +4286,13 @@ if (packetsize == -1) { // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - ov511_set_packet_size(ov511, 640); + if (ov->bclass == BCL_OV518) + ov51x_set_packet_size(ov, 640); else - ov511_set_packet_size(ov511, size); + ov51x_set_packet_size(ov, size); } else { info("Forcing packet size to %d", packetsize); - ov511_set_packet_size(ov511, packetsize); + ov51x_set_packet_size(ov, packetsize); } for (n = 0; n < OV511_NUMSBUF; n++) { @@ -4391,32 +4302,30 @@ err("init isoc: usb_alloc_urb ret. NULL"); return -ENOMEM; } - ov511->sbuf[n].urb = urb; - urb->dev = ov511->dev; - urb->context = ov511; - urb->pipe = usb_rcvisocpipe(ov511->dev, OV511_ENDPOINT_ADDRESS); + ov->sbuf[n].urb = urb; + urb->dev = ov->dev; + urb->context = ov; + urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS); urb->transfer_flags = USB_ISO_ASAP; - urb->transfer_buffer = ov511->sbuf[n].data; - urb->complete = ov511_isoc_irq; + urb->transfer_buffer = ov->sbuf[n].data; + urb->complete = ov51x_isoc_irq; urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = - ov511->packet_size * FRAMES_PER_DESC; + urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC; for (fx = 0; fx < FRAMES_PER_DESC; fx++) { - urb->iso_frame_desc[fx].offset = - ov511->packet_size * fx; - urb->iso_frame_desc[fx].length = ov511->packet_size; + urb->iso_frame_desc[fx].offset = ov->packet_size * fx; + urb->iso_frame_desc[fx].length = ov->packet_size; } } - ov511->streaming = 1; + ov->streaming = 1; - ov511->sbuf[OV511_NUMSBUF - 1].urb->next = ov511->sbuf[0].urb; + ov->sbuf[OV511_NUMSBUF - 1].urb->next = ov->sbuf[0].urb; for (n = 0; n < OV511_NUMSBUF - 1; n++) - ov511->sbuf[n].urb->next = ov511->sbuf[n+1].urb; + ov->sbuf[n].urb->next = ov->sbuf[n+1].urb; for (n = 0; n < OV511_NUMSBUF; n++) { - ov511->sbuf[n].urb->dev = ov511->dev; - err = usb_submit_urb(ov511->sbuf[n].urb, GFP_KERNEL); + ov->sbuf[n].urb->dev = ov->dev; + err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL); if (err) err("init isoc: usb_submit_urb(%d) ret %d", n, err); } @@ -4425,51 +4334,51 @@ } static void -ov511_stop_isoc(struct usb_ov511 *ov511) +ov51x_stop_isoc(struct usb_ov511 *ov) { int n; - if (!ov511->streaming || !ov511->dev) + if (!ov->streaming || !ov->dev) return; PDEBUG(3, "*** Stopping capture ***"); - ov511_set_packet_size(ov511, 0); + ov51x_set_packet_size(ov, 0); - ov511->streaming = 0; + ov->streaming = 0; /* Unschedule all of the iso td's */ for (n = OV511_NUMSBUF - 1; n >= 0; n--) { - if (ov511->sbuf[n].urb) { - ov511->sbuf[n].urb->next = NULL; - usb_unlink_urb(ov511->sbuf[n].urb); - usb_free_urb(ov511->sbuf[n].urb); - ov511->sbuf[n].urb = NULL; + if (ov->sbuf[n].urb) { + ov->sbuf[n].urb->next = NULL; + usb_unlink_urb(ov->sbuf[n].urb); + usb_free_urb(ov->sbuf[n].urb); + ov->sbuf[n].urb = NULL; } } } static int -ov511_new_frame(struct usb_ov511 *ov511, int framenum) +ov51x_new_frame(struct usb_ov511 *ov, int framenum) { struct ov511_frame *frame; int newnum; - PDEBUG(4, "ov511->curframe = %d, framenum = %d", ov511->curframe, - framenum); - if (!ov511->dev) + PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum); + + if (!ov->dev) return -1; /* If we're not grabbing a frame right now and the other frame is */ /* ready to be grabbed into, then use it instead */ - if (ov511->curframe == -1) { + if (ov->curframe == -1) { newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; - if (ov511->frame[newnum].grabstate == FRAME_READY) + if (ov->frame[newnum].grabstate == FRAME_READY) framenum = newnum; } else return 0; - frame = &ov511->frame[framenum]; + frame = &ov->frame[framenum]; PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, frame->width, frame->height); @@ -4478,16 +4387,16 @@ frame->scanstate = STATE_SCANNING; frame->snapshot = 0; - ov511->curframe = framenum; + ov->curframe = framenum; /* Make sure it's not too big */ - if (frame->width > ov511->maxwidth) - frame->width = ov511->maxwidth; + if (frame->width > ov->maxwidth) + frame->width = ov->maxwidth; frame->width &= ~7L; /* Multiple of 8 */ - if (frame->height > ov511->maxheight) - frame->height = ov511->maxheight; + if (frame->height > ov->maxheight) + frame->height = ov->maxheight; frame->height &= ~3L; /* Multiple of 4 */ @@ -4499,84 +4408,86 @@ * Buffer management * ***************************************************************************/ + static int -ov511_alloc(struct usb_ov511 *ov511) +ov51x_alloc(struct usb_ov511 *ov) { int i; - int w = ov511->maxwidth; - int h = ov511->maxheight; + const int w = ov->maxwidth; + const int h = ov->maxheight; + const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h); + const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h); PDEBUG(4, "entered"); - down(&ov511->buf_lock); + down(&ov->buf_lock); - if (ov511->buf_state == BUF_PEND_DEALLOC) { - ov511->buf_state = BUF_ALLOCATED; - del_timer(&ov511->buf_timer); + if (ov->buf_state == BUF_PEND_DEALLOC) { + ov->buf_state = BUF_ALLOCATED; + del_timer(&ov->buf_timer); } - if (ov511->buf_state == BUF_ALLOCATED) + if (ov->buf_state == BUF_ALLOCATED) goto out; - ov511->fbuf = rvmalloc(OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); - if (!ov511->fbuf) + ov->fbuf = rvmalloc(data_bufsize); + if (!ov->fbuf) goto error; - ov511->rawfbuf = vmalloc(OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); - if (!ov511->rawfbuf) { - rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); - ov511->fbuf = NULL; + ov->rawfbuf = vmalloc(raw_bufsize); + if (!ov->rawfbuf) { + rvfree(ov->fbuf, data_bufsize); + ov->fbuf = NULL; goto error; } - memset(ov511->rawfbuf, 0, OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); + memset(ov->rawfbuf, 0, raw_bufsize); - ov511->tempfbuf = vmalloc(OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); - if (!ov511->tempfbuf) { - vfree(ov511->rawfbuf); - ov511->rawfbuf = NULL; - rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); - ov511->fbuf = NULL; + ov->tempfbuf = vmalloc(raw_bufsize); + if (!ov->tempfbuf) { + vfree(ov->rawfbuf); + ov->rawfbuf = NULL; + rvfree(ov->fbuf, data_bufsize); + ov->fbuf = NULL; goto error; } - memset(ov511->tempfbuf, 0, OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h)); + memset(ov->tempfbuf, 0, raw_bufsize); for (i = 0; i < OV511_NUMSBUF; i++) { - ov511->sbuf[i].data = kmalloc(FRAMES_PER_DESC * + ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC * MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL); - if (!ov511->sbuf[i].data) { + if (!ov->sbuf[i].data) { while (--i) { - kfree(ov511->sbuf[i].data); - ov511->sbuf[i].data = NULL; + kfree(ov->sbuf[i].data); + ov->sbuf[i].data = NULL; } - vfree(ov511->tempfbuf); - ov511->tempfbuf = NULL; - vfree(ov511->rawfbuf); - ov511->rawfbuf = NULL; - rvfree(ov511->fbuf, - OV511_NUMFRAMES * MAX_DATA_SIZE(w, h)); - ov511->fbuf = NULL; + vfree(ov->tempfbuf); + ov->tempfbuf = NULL; + vfree(ov->rawfbuf); + ov->rawfbuf = NULL; + rvfree(ov->fbuf, data_bufsize); + ov->fbuf = NULL; goto error; } - PDEBUG(4, "sbuf[%d] @ %p", i, ov511->sbuf[i].data); + PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data); } for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].data = ov511->fbuf + i * MAX_DATA_SIZE(w, h); - ov511->frame[i].rawdata = ov511->rawfbuf + ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h); + ov->frame[i].rawdata = ov->rawfbuf + i * MAX_RAW_DATA_SIZE(w, h); - ov511->frame[i].tempdata = ov511->tempfbuf + ov->frame[i].tempdata = ov->tempfbuf + i * MAX_RAW_DATA_SIZE(w, h); - PDEBUG(4, "frame[%d] @ %p", i, ov511->frame[i].data); + PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data); } - ov511->buf_state = BUF_ALLOCATED; + ov->buf_state = BUF_ALLOCATED; out: - up(&ov511->buf_lock); + up(&ov->buf_lock); PDEBUG(4, "leaving"); return 0; error: - ov511->buf_state = BUF_NOT_ALLOCATED; - up(&ov511->buf_lock); + ov->buf_state = BUF_NOT_ALLOCATED; + up(&ov->buf_lock); PDEBUG(4, "errored"); return -ENOMEM; } @@ -4587,206 +4498,211 @@ * them if you explicitly free them somewhere else! */ static void -ov511_do_dealloc(struct usb_ov511 *ov511) +ov51x_do_dealloc(struct usb_ov511 *ov) { int i; PDEBUG(4, "entered"); - if (ov511->fbuf) { - rvfree(ov511->fbuf, OV511_NUMFRAMES - * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight)); - ov511->fbuf = NULL; + if (ov->fbuf) { + rvfree(ov->fbuf, OV511_NUMFRAMES + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); + ov->fbuf = NULL; } - if (ov511->rawfbuf) { - vfree(ov511->rawfbuf); - ov511->rawfbuf = NULL; + if (ov->rawfbuf) { + vfree(ov->rawfbuf); + ov->rawfbuf = NULL; } - if (ov511->tempfbuf) { - vfree(ov511->tempfbuf); - ov511->tempfbuf = NULL; + if (ov->tempfbuf) { + vfree(ov->tempfbuf); + ov->tempfbuf = NULL; } for (i = 0; i < OV511_NUMSBUF; i++) { - if (ov511->sbuf[i].data) { - kfree(ov511->sbuf[i].data); - ov511->sbuf[i].data = NULL; + if (ov->sbuf[i].data) { + kfree(ov->sbuf[i].data); + ov->sbuf[i].data = NULL; } } for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].data = NULL; - ov511->frame[i].rawdata = NULL; - ov511->frame[i].tempdata = NULL; + ov->frame[i].data = NULL; + ov->frame[i].rawdata = NULL; + ov->frame[i].tempdata = NULL; } PDEBUG(4, "buffer memory deallocated"); - ov511->buf_state = BUF_NOT_ALLOCATED; + ov->buf_state = BUF_NOT_ALLOCATED; PDEBUG(4, "leaving"); } static void -ov511_buf_callback(unsigned long data) +ov51x_buf_callback(unsigned long data) { - struct usb_ov511 *ov511 = (struct usb_ov511 *)data; + struct usb_ov511 *ov = (struct usb_ov511 *)data; PDEBUG(4, "entered"); - down(&ov511->buf_lock); + down(&ov->buf_lock); - if (ov511->buf_state == BUF_PEND_DEALLOC) - ov511_do_dealloc(ov511); + if (ov->buf_state == BUF_PEND_DEALLOC) + ov51x_do_dealloc(ov); - up(&ov511->buf_lock); + up(&ov->buf_lock); PDEBUG(4, "leaving"); } static void -ov511_dealloc(struct usb_ov511 *ov511, int now) +ov51x_dealloc(struct usb_ov511 *ov, int now) { - struct timer_list *bt = &(ov511->buf_timer); + struct timer_list *bt = &(ov->buf_timer); PDEBUG(4, "entered"); - down(&ov511->buf_lock); + down(&ov->buf_lock); PDEBUG(4, "deallocating buffer memory %s", now ? "now" : "later"); - if (ov511->buf_state == BUF_PEND_DEALLOC) { - ov511->buf_state = BUF_ALLOCATED; + if (ov->buf_state == BUF_PEND_DEALLOC) { + ov->buf_state = BUF_ALLOCATED; del_timer(bt); } if (now) - ov511_do_dealloc(ov511); + ov51x_do_dealloc(ov); else { - ov511->buf_state = BUF_PEND_DEALLOC; + ov->buf_state = BUF_PEND_DEALLOC; init_timer(bt); - bt->function = ov511_buf_callback; - bt->data = (unsigned long)ov511; + bt->function = ov51x_buf_callback; + bt->data = (unsigned long)ov; bt->expires = jiffies + buf_timeout * HZ; add_timer(bt); } - up(&ov511->buf_lock); + up(&ov->buf_lock); PDEBUG(4, "leaving"); } /**************************************************************************** * - * V4L API + * V4L 1 API * ***************************************************************************/ static int -ov511_open(struct video_device *vdev, int flags) +ov51x_v4l1_open(struct video_device *vdev, int flags) { - struct usb_ov511 *ov511 = vdev->priv; + struct usb_ov511 *ov = vdev->priv; int err, i; PDEBUG(4, "opening"); - down(&ov511->lock); + down(&ov->lock); err = -EBUSY; - if (ov511->user) + if (ov->user) goto out; err = -ENOMEM; - if (ov511_alloc(ov511)) + if (ov51x_alloc(ov)) goto out; - ov511->sub_flag = 0; + ov->sub_flag = 0; /* In case app doesn't set them... */ - if (ov51x_set_default_params(ov511) < 0) + if (ov51x_set_default_params(ov) < 0) goto out; /* Make sure frames are reset */ for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].grabstate = FRAME_UNUSED; - ov511->frame[i].bytes_read = 0; + ov->frame[i].grabstate = FRAME_UNUSED; + ov->frame[i].bytes_read = 0; } /* If compression is on, make sure now that a * decompressor can be loaded */ - if (ov511->compress && !ov511->decomp_ops) { - err = ov51x_request_decompressor(ov511); - if (err) + if (ov->compress && !ov->decomp_ops) { + err = request_decompressor(ov); + if (err && !dumppix) goto out; } - err = ov511_init_isoc(ov511); + err = ov51x_init_isoc(ov); if (err) { - ov511_dealloc(ov511, 0); + ov51x_dealloc(ov, 0); goto out; } - ov511->user++; + ov->user++; - if (ov511->led_policy == LED_AUTO) - ov51x_led_control(ov511, 1); + if (ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 1); out: - up(&ov511->lock); - + up(&ov->lock); return err; } static void -ov511_close(struct video_device *dev) +ov51x_v4l1_close(struct video_device *vdev) { - struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + struct usb_ov511 *ov = vdev->priv; PDEBUG(4, "ov511_close"); - down(&ov511->lock); + down(&ov->lock); - ov511->user--; - ov511_stop_isoc(ov511); + ov->user--; + ov51x_stop_isoc(ov); - ov51x_release_decompressor(ov511); + release_decompressor(ov); - if (ov511->led_policy == LED_AUTO) - ov51x_led_control(ov511, 0); + if (ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); - if (ov511->dev) - ov511_dealloc(ov511, 0); + if (ov->dev) + ov51x_dealloc(ov, 0); - up(&ov511->lock); + up(&ov->lock); /* Device unplugged while open. Only a minimum of unregistration is done * here; the disconnect callback already did the rest. */ - if (!ov511->dev) { - ov511_dealloc(ov511, 1); - video_unregister_device(&ov511->vdev); - kfree(ov511); - ov511 = NULL; + if (!ov->dev) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + + ov51x_dealloc(ov, 1); + video_unregister_device(&ov->vdev); + kfree(ov); + ov = NULL; } } static int -ov511_init_done(struct video_device *vdev) +ov51x_v4l1_init_done(struct video_device *vdev) { #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - create_proc_ov511_cam((struct usb_ov511 *)vdev); + create_proc_ov511_cam(vdev->priv); #endif return 0; } static long -ov511_write(struct video_device *vdev, const char *buf, - unsigned long count, int noblock) +ov51x_v4l1_write(struct video_device *vdev, const char *buf, + unsigned long count, int noblock) { return -EINVAL; } /* Do not call this function directly! */ static int -ov511_ioctl_internal(struct video_device *vdev, unsigned int cmd, void *arg) +ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd, + void *arg) { - struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev; + struct usb_ov511 *ov = vdev->priv; PDEBUG(5, "IOCtl: 0x%X", cmd); - if (!ov511->dev) + if (!ov->dev) return -EIO; switch (cmd) { @@ -4798,20 +4714,20 @@ memset(&b, 0, sizeof(b)); sprintf(b.name, "%s USB Camera", - ov511->bridge == BRG_OV511 ? "OV511" : - ov511->bridge == BRG_OV511PLUS ? "OV511+" : - ov511->bridge == BRG_OV518 ? "OV518" : - ov511->bridge == BRG_OV518PLUS ? "OV518+" : + ov->bridge == BRG_OV511 ? "OV511" : + ov->bridge == BRG_OV511PLUS ? "OV511+" : + ov->bridge == BRG_OV518 ? "OV518" : + ov->bridge == BRG_OV518PLUS ? "OV518+" : "unknown"); b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; - if (ov511->has_tuner) + if (ov->has_tuner) b.type |= VID_TYPE_TUNER; - b.channels = ov511->num_inputs; - b.audios = ov511->has_audio_proc ? 1:0; - b.maxwidth = ov511->maxwidth; - b.maxheight = ov511->maxheight; - b.minwidth = ov511->minwidth; - b.minheight = ov511->minheight; + b.channels = ov->num_inputs; + b.audios = ov->has_audio_proc ? 1:0; + b.maxwidth = ov->maxwidth; + b.maxheight = ov->maxheight; + b.minwidth = ov->minwidth; + b.minheight = ov->minheight; if (copy_to_user(arg, &b, sizeof(b))) return -EFAULT; @@ -4827,18 +4743,18 @@ if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; - if ((unsigned)(v.channel) >= ov511->num_inputs) { + if ((unsigned)(v.channel) >= ov->num_inputs) { err("Invalid channel (%d)", v.channel); return -EINVAL; } - v.norm = ov511->norm; - v.type = (ov511->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA; - v.flags = (ov511->has_tuner) ? VIDEO_VC_TUNER : 0; - v.flags |= (ov511->has_audio_proc) ? VIDEO_VC_AUDIO : 0; -// v.flags |= (ov511->has_decoder) ? VIDEO_VC_NORM : 0; - v.tuners = (ov511->has_tuner) ? 1:0; - decoder_get_input_name(ov511, v.channel, v.name); + v.norm = ov->norm; + v.type = (ov->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA; + v.flags = (ov->has_tuner) ? VIDEO_VC_TUNER : 0; + v.flags |= (ov->has_audio_proc) ? VIDEO_VC_AUDIO : 0; +// v.flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0; + v.tuners = (ov->has_tuner) ? 1:0; + decoder_get_input_name(ov, v.channel, v.name); if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; @@ -4856,7 +4772,7 @@ return -EFAULT; /* Make sure it's not a camera */ - if (!ov511->has_decoder) { + if (!ov->has_decoder) { if (v.channel == 0) return 0; else @@ -4871,16 +4787,16 @@ return -EINVAL; } - if ((unsigned)(v.channel) >= ov511->num_inputs) { + if ((unsigned)(v.channel) >= ov->num_inputs) { err("Invalid channel (%d)", v.channel); return -EINVAL; } - err = decoder_set_input(ov511, v.channel); + err = decoder_set_input(ov, v.channel); if (err) return err; - err = decoder_set_norm(ov511, v.norm); + err = decoder_set_norm(ov, v.norm); if (err) return err; @@ -4894,7 +4810,7 @@ memset(&p, 0, sizeof(p)); - if (sensor_get_picture(ov511, &p)) + if (sensor_get_picture(ov, &p)) return -EIO; if (copy_to_user(arg, &p, sizeof(p))) @@ -4912,10 +4828,10 @@ if (copy_from_user(&p, arg, sizeof(p))) return -EFAULT; - if (!ov511_get_depth(p.palette)) + if (!get_depth(p.palette)) return -EINVAL; - if (sensor_set_picture(ov511, &p)) + if (sensor_set_picture(ov, &p)) return -EIO; if (force_palette && p.palette != force_palette) { @@ -4924,23 +4840,22 @@ } // FIXME: Format should be independent of frames - if (p.palette != ov511->frame[0].format) { + if (p.palette != ov->frame[0].format) { PDEBUG(4, "Detected format change"); /* If we're collecting previous frame wait before changing modes */ - interruptible_sleep_on(&ov511->wq); + interruptible_sleep_on(&ov->wq); if (signal_pending(current)) return -EINTR; - mode_init_regs(ov511, ov511->frame[0].width, - ov511->frame[0].height, p.palette, - ov511->sub_flag); + mode_init_regs(ov, ov->frame[0].width, + ov->frame[0].height, p.palette, ov->sub_flag); } PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette); for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].depth = p.depth; - ov511->frame[i].format = p.palette; + ov->frame[i].depth = p.depth; + ov->frame[i].format = p.palette; } return 0; @@ -4953,7 +4868,7 @@ if (copy_from_user(&vf, arg, sizeof(vf))) return -EFAULT; - ov511->sub_flag = vf; + ov->sub_flag = vf; return 0; } case VIDIOCSCAPTURE: @@ -4981,10 +4896,10 @@ if (vc.height == 0) vc.height = 16; - ov511->subx = vc.x; - ov511->suby = vc.y; - ov511->subw = vc.width; - ov511->subh = vc.height; + ov->subx = vc.x; + ov->suby = vc.y; + ov->subw = vc.width; + ov->subh = vc.height; return 0; } @@ -5004,25 +4919,25 @@ return -EINVAL; if (vw.clipcount) return -EINVAL; - if (vw.height != ov511->maxheight) + if (vw.height != ov->maxheight) return -EINVAL; - if (vw.width != ov511->maxwidth) + if (vw.width != ov->maxwidth) return -EINVAL; #endif /* If we're collecting previous frame wait before changing modes */ - interruptible_sleep_on(&ov511->wq); + interruptible_sleep_on(&ov->wq); if (signal_pending(current)) return -EINTR; - result = mode_init_regs(ov511, vw.width, vw.height, - ov511->frame[0].format, ov511->sub_flag); + result = mode_init_regs(ov, vw.width, vw.height, + ov->frame[0].format, ov->sub_flag); if (result < 0) return result; for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].width = vw.width; - ov511->frame[i].height = vw.height; + ov->frame[i].width = vw.width; + ov->frame[i].height = vw.height; } return 0; @@ -5034,8 +4949,8 @@ memset(&vw, 0, sizeof(vw)); vw.x = 0; /* FIXME */ vw.y = 0; - vw.width = ov511->frame[0].width; - vw.height = ov511->frame[0].height; + vw.width = ov->frame[0].width; + vw.height = ov->frame[0].height; vw.flags = 30; PDEBUG(4, "VIDIOCGWIN: %dx%d", vw.width, vw.height); @@ -5054,13 +4969,13 @@ memset(&vm, 0, sizeof(vm)); vm.size = OV511_NUMFRAMES - * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight); + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); vm.frames = OV511_NUMFRAMES; vm.offsets[0] = 0; for (i = 1; i < OV511_NUMFRAMES; i++) { vm.offsets[i] = vm.offsets[i-1] - + MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight); + + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); } if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) @@ -5080,7 +4995,7 @@ PDEBUG(4, "frame: %d, size: %dx%d, format: %d", vm.frame, vm.width, vm.height, vm.format); - depth = ov511_get_depth(vm.format); + depth = get_depth(vm.format); if (!depth) { err("VIDIOCMCAPTURE: invalid format (%d)", vm.format); return -EINVAL; @@ -5091,13 +5006,13 @@ return -EINVAL; } - if (vm.width > ov511->maxwidth - || vm.height > ov511->maxheight) { + if (vm.width > ov->maxwidth + || vm.height > ov->maxheight) { err("VIDIOCMCAPTURE: requested dimensions too big"); return -EINVAL; } - if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING) { + if (ov->frame[vm.frame].grabstate == FRAME_GRABBING) { PDEBUG(4, "VIDIOCMCAPTURE: already grabbing"); return -EBUSY; } @@ -5107,38 +5022,38 @@ return -EINVAL; } - if ((ov511->frame[vm.frame].width != vm.width) || - (ov511->frame[vm.frame].height != vm.height) || - (ov511->frame[vm.frame].format != vm.format) || - (ov511->frame[vm.frame].sub_flag != ov511->sub_flag) || - (ov511->frame[vm.frame].depth != depth)) { + if ((ov->frame[vm.frame].width != vm.width) || + (ov->frame[vm.frame].height != vm.height) || + (ov->frame[vm.frame].format != vm.format) || + (ov->frame[vm.frame].sub_flag != ov->sub_flag) || + (ov->frame[vm.frame].depth != depth)) { PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters"); /* If we're collecting previous frame wait before changing modes */ - interruptible_sleep_on(&ov511->wq); + interruptible_sleep_on(&ov->wq); if (signal_pending(current)) return -EINTR; - ret = mode_init_regs(ov511, vm.width, vm.height, - vm.format, ov511->sub_flag); + ret = mode_init_regs(ov, vm.width, vm.height, + vm.format, ov->sub_flag); #if 0 if (ret < 0) { PDEBUG(1, "Got error while initializing regs "); return ret; } #endif - ov511->frame[vm.frame].width = vm.width; - ov511->frame[vm.frame].height = vm.height; - ov511->frame[vm.frame].format = vm.format; - ov511->frame[vm.frame].sub_flag = ov511->sub_flag; - ov511->frame[vm.frame].depth = depth; + ov->frame[vm.frame].width = vm.width; + ov->frame[vm.frame].height = vm.height; + ov->frame[vm.frame].format = vm.format; + ov->frame[vm.frame].sub_flag = ov->sub_flag; + ov->frame[vm.frame].depth = depth; } /* Mark it as ready */ - ov511->frame[vm.frame].grabstate = FRAME_READY; + ov->frame[vm.frame].grabstate = FRAME_READY; PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", vm.frame); - return ov511_new_frame(ov511, vm.frame); + return ov51x_new_frame(ov, vm.frame); } case VIDIOCSYNC: { @@ -5153,7 +5068,7 @@ return -EINVAL; } - frame = &ov511->frame[fnum]; + frame = &ov->frame[fnum]; PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum, frame->grabstate); @@ -5165,7 +5080,7 @@ case FRAME_GRABBING: case FRAME_ERROR: redo: - if (!ov511->dev) + if (!ov->dev) return -EIO; rc = wait_event_interruptible(frame->wq, @@ -5178,15 +5093,15 @@ if (frame->grabstate == FRAME_ERROR) { int ret; - if ((ret = ov511_new_frame(ov511, fnum)) < 0) + if ((ret = ov51x_new_frame(ov, fnum)) < 0) return ret; goto redo; } /* Fall through */ case FRAME_DONE: - if (ov511->snap_enabled && !frame->snapshot) { + if (ov->snap_enabled && !frame->snapshot) { int ret; - if ((ret = ov511_new_frame(ov511, fnum)) < 0) + if ((ret = ov51x_new_frame(ov, fnum)) < 0) return ret; goto redo; } @@ -5195,13 +5110,13 @@ /* Reset the hardware snapshot button */ /* FIXME - Is this the best place for this? */ - if ((ov511->snap_enabled) && (frame->snapshot)) { + if ((ov->snap_enabled) && (frame->snapshot)) { frame->snapshot = 0; - ov51x_clear_snapshot(ov511); + ov51x_clear_snapshot(ov); } /* Decompression, format conversion, etc... */ - ov511_postprocess(ov511, frame); + ov51x_postprocess(ov, frame); break; } /* end switch */ @@ -5230,7 +5145,7 @@ memset(&vu, 0, sizeof(vu)); - vu.video = ov511->vdev.minor; /* Video minor */ + vu.video = ov->vdev.minor; /* Video minor */ vu.vbi = VIDEO_NO_UNIT; /* VBI minor */ vu.radio = VIDEO_NO_UNIT; /* Radio minor */ vu.audio = VIDEO_NO_UNIT; /* Audio minor */ @@ -5250,7 +5165,7 @@ if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; - if (!ov511->has_tuner || v.tuner) // Only tuner 0 + if (!ov->has_tuner || v.tuner) // Only tuner 0 return -EINVAL; strcpy(v.name, "Television"); @@ -5264,7 +5179,7 @@ v.mode = 0; /* FIXME: Not sure what this is yet */ v.signal = 0xFFFF; /* unknown */ - call_i2c_clients(ov511, cmd, &v); + call_i2c_clients(ov, cmd, &v); if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; @@ -5282,7 +5197,7 @@ return -EFAULT; /* Only no or one tuner for now */ - if (!ov511->has_tuner || v.tuner) + if (!ov->has_tuner || v.tuner) return -EINVAL; /* and it only has certain valid modes */ @@ -5291,21 +5206,21 @@ v.mode != VIDEO_MODE_SECAM) return -EOPNOTSUPP; /* Is this right/necessary? */ - err = decoder_set_norm(ov511, v.mode); + err = decoder_set_norm(ov, v.mode); if (err) return err; - call_i2c_clients(ov511, cmd, &v); + call_i2c_clients(ov, cmd, &v); return 0; } case VIDIOCGFREQ: { - unsigned long v = ov511->freq; + unsigned long v = ov->freq; PDEBUG(4, "VIDIOCGFREQ"); - if (!ov511->has_tuner) + if (!ov->has_tuner) return -EINVAL; #if 0 /* FIXME: this is necessary for testing */ @@ -5320,7 +5235,7 @@ { unsigned long v; - if (!ov511->has_tuner) + if (!ov->has_tuner) return -EINVAL; if (copy_from_user(&v, arg, sizeof(v))) @@ -5328,8 +5243,8 @@ PDEBUG(4, "VIDIOCSFREQ: %lx", v); - ov511->freq = v; - call_i2c_clients(ov511, cmd, &v); + ov->freq = v; + call_i2c_clients(ov, cmd, &v); return 0; } @@ -5348,29 +5263,29 @@ } static int -ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) +ov51x_v4l1_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) { int rc; - struct usb_ov511 *ov511 = vdev->priv; + struct usb_ov511 *ov = vdev->priv; - if (down_interruptible(&ov511->lock)) + if (down_interruptible(&ov->lock)) return -EINTR; - rc = ov511_ioctl_internal(vdev, cmd, arg); + rc = ov51x_v4l1_ioctl_internal(vdev, cmd, arg); - up(&ov511->lock); + up(&ov->lock); return rc; } static inline long -ov511_read(struct video_device *vdev, char *buf, unsigned long count, - int noblock) +ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count, + int noblock) { - struct usb_ov511 *ov511 = vdev->priv; + struct usb_ov511 *ov = vdev->priv; int i, rc = 0, frmx = -1; struct ov511_frame *frame; - if (down_interruptible(&ov511->lock)) + if (down_interruptible(&ov->lock)) return -EINTR; PDEBUG(4, "%ld bytes, noblock=%d", count, noblock); @@ -5380,16 +5295,16 @@ goto error; } - if (!ov511->dev) { + if (!ov->dev) { rc = -EIO; goto error; } // FIXME: Only supports two frames /* See if a frame is completed, then use it. */ - if (ov511->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ + if (ov->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ frmx = 0; - else if (ov511->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ + else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ frmx = 1; /* If nonblocking we return immediately */ @@ -5401,24 +5316,24 @@ /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ /* See if a frame is in process (grabbing), then use it. */ if (frmx == -1) { - if (ov511->frame[0].grabstate == FRAME_GRABBING) + if (ov->frame[0].grabstate == FRAME_GRABBING) frmx = 0; - else if (ov511->frame[1].grabstate == FRAME_GRABBING) + else if (ov->frame[1].grabstate == FRAME_GRABBING) frmx = 1; } /* If no frame is active, start one. */ if (frmx == -1) { - if ((rc = ov511_new_frame(ov511, frmx = 0))) { - err("read: ov511_new_frame error"); + if ((rc = ov51x_new_frame(ov, frmx = 0))) { + err("read: ov51x_new_frame error"); goto error; } } - frame = &ov511->frame[frmx]; + frame = &ov->frame[frmx]; restart: - if (!ov511->dev) { + if (!ov->dev) { rc = -EIO; goto error; } @@ -5437,9 +5352,9 @@ if (frame->grabstate == FRAME_ERROR) { frame->bytes_read = 0; - err("** ick! ** Errored frame %d", ov511->curframe); - if (ov511_new_frame(ov511, frmx)) { - err("read: ov511_new_frame error"); + err("** ick! ** Errored frame %d", ov->curframe); + if (ov51x_new_frame(ov, frmx)) { + err("read: ov51x_new_frame error"); goto error; } goto restart; @@ -5447,25 +5362,25 @@ /* Repeat until we get a snapshot frame */ - if (ov511->snap_enabled) + if (ov->snap_enabled) PDEBUG(4, "Waiting snapshot frame"); - if (ov511->snap_enabled && !frame->snapshot) { + if (ov->snap_enabled && !frame->snapshot) { frame->bytes_read = 0; - if ((rc = ov511_new_frame(ov511, frmx))) { - err("read: ov511_new_frame error"); + if ((rc = ov51x_new_frame(ov, frmx))) { + err("read: ov51x_new_frame error"); goto error; } goto restart; } /* Clear the snapshot */ - if (ov511->snap_enabled && frame->snapshot) { + if (ov->snap_enabled && frame->snapshot) { frame->snapshot = 0; - ov51x_clear_snapshot(ov511); + ov51x_clear_snapshot(ov); } /* Decompression, format conversion, etc... */ - ov511_postprocess(ov511, frame); + ov51x_postprocess(ov, frame); PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx, frame->bytes_read, @@ -5497,48 +5412,49 @@ // FIXME: Only supports two frames /* Mark it as available to be used again. */ - ov511->frame[frmx].grabstate = FRAME_UNUSED; - if ((rc = ov511_new_frame(ov511, !frmx))) { - err("ov511_new_frame returned error"); + ov->frame[frmx].grabstate = FRAME_UNUSED; + if ((rc = ov51x_new_frame(ov, !frmx))) { + err("ov51x_new_frame returned error"); goto error; } } PDEBUG(4, "read finished, returning %ld (sweet)", count); - up(&ov511->lock); + up(&ov->lock); return count; error: - up(&ov511->lock); + up(&ov->lock); return rc; } static int -ov511_mmap(struct vm_area_struct *vma, struct video_device *vdev, const char *adr, unsigned long size) +ov51x_v4l1_mmap(struct vm_area_struct *vma, struct video_device *vdev, + const char *adr, unsigned long size) { - struct usb_ov511 *ov511 = vdev->priv; + struct usb_ov511 *ov = vdev->priv; unsigned long start = (unsigned long)adr; unsigned long page, pos; - if (ov511->dev == NULL) + if (ov->dev == NULL) return -EIO; PDEBUG(4, "mmap: %ld (%lX) bytes", size, size); if (size > (((OV511_NUMFRAMES - * MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight) + * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))) return -EINVAL; - if (down_interruptible(&ov511->lock)) + if (down_interruptible(&ov->lock)) return -EINTR; - pos = (unsigned long)ov511->fbuf; + pos = (unsigned long)ov->fbuf; while (size > 0) { page = kvirt_to_pa(pos); if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - up(&ov511->lock); + up(&ov->lock); return -EAGAIN; } start += PAGE_SIZE; @@ -5549,31 +5465,31 @@ size = 0; } - up(&ov511->lock); + up(&ov->lock); return 0; } -static struct video_device ov511_template = { +static struct video_device vdev_template = { owner: THIS_MODULE, name: "OV511 USB Camera", type: VID_TYPE_CAPTURE, hardware: VID_HARDWARE_OV511, - open: ov511_open, - close: ov511_close, - read: ov511_read, - write: ov511_write, - ioctl: ov511_ioctl, - mmap: ov511_mmap, - initialize: ov511_init_done, + open: ov51x_v4l1_open, + close: ov51x_v4l1_close, + read: ov51x_v4l1_read, + write: ov51x_v4l1_write, + ioctl: ov51x_v4l1_ioctl, + mmap: ov51x_v4l1_mmap, + initialize: ov51x_v4l1_init_done, }; #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) static int -ov511_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd, +ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long ularg) { struct proc_dir_entry *pde; - struct usb_ov511 *ov511; + struct usb_ov511 *ov; void *arg = (void *) ularg; int rc; @@ -5581,11 +5497,11 @@ if (!pde) return -ENOENT; - ov511 = (struct usb_ov511 *) pde->data; - if (!ov511) + ov = (struct usb_ov511 *) pde->data; + if (!ov) return -ENODEV; - if (!ov511->dev) + if (!ov->dev) return -EIO; /* Should we pass through standard V4L IOCTLs? */ @@ -5610,19 +5526,19 @@ switch (opt.optnum) { case OV511_USOPT_BRIGHT: - rc = sensor_get_brightness(ov511, &(opt.val)); + rc = sensor_get_brightness(ov, &(opt.val)); if (rc) return rc; break; case OV511_USOPT_SAT: - rc = sensor_get_saturation(ov511, &(opt.val)); + rc = sensor_get_saturation(ov, &(opt.val)); if (rc) return rc; break; case OV511_USOPT_HUE: - rc = sensor_get_hue(ov511, &(opt.val)); + rc = sensor_get_hue(ov, &(opt.val)); if (rc) return rc; break; case OV511_USOPT_CONTRAST: - rc = sensor_get_contrast(ov511, &(opt.val)); + rc = sensor_get_contrast(ov, &(opt.val)); if (rc) return rc; break; default: @@ -5644,19 +5560,19 @@ switch (opt.optnum) { case OV511_USOPT_BRIGHT: - rc = sensor_set_brightness(ov511, opt.val); + rc = sensor_set_brightness(ov, opt.val); if (rc) return rc; break; case OV511_USOPT_SAT: - rc = sensor_set_saturation(ov511, opt.val); + rc = sensor_set_saturation(ov, opt.val); if (rc) return rc; break; case OV511_USOPT_HUE: - rc = sensor_set_hue(ov511, opt.val); + rc = sensor_set_hue(ov, opt.val); if (rc) return rc; break; case OV511_USOPT_CONTRAST: - rc = sensor_set_contrast(ov511, opt.val); + rc = sensor_set_contrast(ov, opt.val); if (rc) return rc; break; default: @@ -5675,19 +5591,19 @@ switch (opt.optnum) { case OV511_UIOPT_POWER_FREQ: - opt.val = ov511->lightfreq; + opt.val = ov->lightfreq; break; case OV511_UIOPT_BFILTER: - opt.val = ov511->bandfilt; + opt.val = ov->bandfilt; break; case OV511_UIOPT_LED: - opt.val = ov511->led_policy; + opt.val = ov->led_policy; break; case OV511_UIOPT_DEBUG: opt.val = debug; break; case OV511_UIOPT_COMPRESS: - opt.val = ov511->compress; + opt.val = ov->compress; break; default: err("Invalid get int option number"); @@ -5708,20 +5624,20 @@ switch (opt.optnum) { case OV511_UIOPT_POWER_FREQ: - rc = sensor_set_light_freq(ov511, opt.val); + rc = sensor_set_light_freq(ov, opt.val); if (rc) return rc; break; case OV511_UIOPT_BFILTER: - rc = sensor_set_banding_filter(ov511, opt.val); + rc = sensor_set_banding_filter(ov, opt.val); if (rc) return rc; break; case OV511_UIOPT_LED: if (opt.val <= 2) { - ov511->led_policy = opt.val; - if (ov511->led_policy == LED_OFF) - ov51x_led_control(ov511, 0); - else if (ov511->led_policy == LED_ON) - ov51x_led_control(ov511, 1); + ov->led_policy = opt.val; + if (ov->led_policy == LED_OFF) + ov51x_led_control(ov, 0); + else if (ov->led_policy == LED_ON) + ov51x_led_control(ov, 1); } else { return -EINVAL; } @@ -5733,14 +5649,12 @@ return -EINVAL; break; case OV511_UIOPT_COMPRESS: - ov511->compress = opt.val; - if (ov511->compress) { - if (ov511->bridge == BRG_OV511 || - ov511->bridge == BRG_OV511PLUS) - ov511_init_compression(ov511); - else if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) - ov518_init_compression(ov511); + ov->compress = opt.val; + if (ov->compress) { + if (ov->bclass == BCL_OV511) + ov511_init_compression(ov); + else if (ov->bclass == BCL_OV518) + ov518_init_compression(ov); } break; default: @@ -5757,7 +5671,7 @@ if (copy_from_user(&w, arg, sizeof(w))) return -EFAULT; - return ov51x_i2c_write_slave(ov511, w.slave, w.reg, w.value, + return i2c_w_slave(ov, w.slave, w.reg, w.value, w.mask); } case OV511IOC_RI2C: @@ -5767,7 +5681,7 @@ if (copy_from_user(&r, arg, sizeof(r))) return -EFAULT; - rc = ov51x_i2c_read_slave(ov511, r.slave, r.reg); + rc = i2c_r_slave(ov, r.slave, r.reg); if (rc < 0) return rc; @@ -5796,7 +5710,7 @@ * the same register settings as the OV7610, since they are very similar. */ static int -ov7xx0_configure(struct usb_ov511 *ov511) +ov7xx0_configure(struct usb_ov511 *ov) { int i, success; int rc; @@ -5913,16 +5827,15 @@ PDEBUG(4, "starting configuration"); /* This looks redundant, but is necessary for WebCam 3 */ - ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID, - OV7xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) return -1; - if (ov51x_init_ov_sensor(ov511) >= 0) { + if (init_ov_sensor(ov) >= 0) { PDEBUG(1, "OV7xx0 sensor initalized (method 1)"); } else { /* Reset the 76xx */ - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) return -1; + if (i2c_w(ov, 0x12, 0x80) < 0) return -1; /* Wait for it to initialize */ schedule_timeout(1 + 150 * HZ / 1000); @@ -5930,10 +5843,8 @@ i = 0; success = 0; while (i <= i2c_detect_tries) { - if ((ov51x_i2c_read(ov511, - OV7610_REG_ID_HIGH) == 0x7F) && - (ov51x_i2c_read(ov511, - OV7610_REG_ID_LOW) == 0xA2)) { + if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && + (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { success = 1; break; } else { @@ -5957,17 +5868,17 @@ } /* Detect sensor (sub)type */ - rc = ov51x_i2c_read(ov511, OV7610_REG_COM_I); + rc = i2c_r(ov, OV7610_REG_COM_I); if (rc < 0) { err("Error detecting sensor type"); return -1; } else if ((rc & 3) == 3) { info("Sensor is an OV7610"); - ov511->sensor = SEN_OV7610; + ov->sensor = SEN_OV7610; } else if ((rc & 3) == 1) { /* I don't know what's different about the 76BE yet */ - if (ov51x_i2c_read(ov511, 0x15) & 1) + if (i2c_r(ov, 0x15) & 1) info("Sensor is an OV7620AE"); else info("Sensor is an OV76BE"); @@ -5975,48 +5886,48 @@ /* OV511+ will return all zero isoc data unless we * configure the sensor as a 7620. Someone needs to * find the exact reg. setting that causes this. */ - if (ov511->bridge == BRG_OV511PLUS) { + if (ov->bridge == BRG_OV511PLUS) { info("Enabling 511+/7620AE workaround"); - ov511->sensor = SEN_OV7620; + ov->sensor = SEN_OV7620; } else { - ov511->sensor = SEN_OV7620AE; + ov->sensor = SEN_OV7620AE; } } else if ((rc & 3) == 0) { info("Sensor is an OV7620"); - ov511->sensor = SEN_OV7620; + ov->sensor = SEN_OV7620; } else { err("Unknown image sensor version: %d", rc & 3); return -1; } - if (ov511->sensor == SEN_OV7620) { + if (ov->sensor == SEN_OV7620) { PDEBUG(4, "Writing 7620 registers"); - if (ov511_write_regvals(ov511, aRegvalsNorm7620)) + if (write_regvals(ov, aRegvalsNorm7620)) return -1; } else { PDEBUG(4, "Writing 7610 registers"); - if (ov511_write_regvals(ov511, aRegvalsNorm7610)) + if (write_regvals(ov, aRegvalsNorm7610)) return -1; } /* Set sensor-specific vars */ - ov511->maxwidth = 640; - ov511->maxheight = 480; - ov511->minwidth = 64; - ov511->minheight = 48; + ov->maxwidth = 640; + ov->maxheight = 480; + ov->minwidth = 64; + ov->minheight = 48; // FIXME: These do not match the actual settings yet - ov511->brightness = 0x80 << 8; - ov511->contrast = 0x80 << 8; - ov511->colour = 0x80 << 8; - ov511->hue = 0x80 << 8; + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; return 0; } /* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ static int -ov6xx0_configure(struct usb_ov511 *ov511) +ov6xx0_configure(struct usb_ov511 *ov) { int rc; @@ -6142,7 +6053,7 @@ PDEBUG(4, "starting sensor configuration"); - if (ov51x_init_ov_sensor(ov511) < 0) { + if (init_ov_sensor(ov) < 0) { err("Failed to read sensor ID. You might not have an OV6xx0,"); err("or it may be not responding. Report this to " EMAIL); return -1; @@ -6151,50 +6062,44 @@ } /* Detect sensor (sub)type */ - rc = ov51x_i2c_read(ov511, OV7610_REG_COM_I); + rc = i2c_r(ov, OV7610_REG_COM_I); if (rc < 0) { err("Error detecting sensor type"); return -1; } else if ((rc & 3) == 0) { info("Sensor is an OV6630"); - ov511->sensor = SEN_OV6630; + ov->sensor = SEN_OV6630; } else if ((rc & 3) == 1) { info("Sensor is an OV6620"); - ov511->sensor = SEN_OV6620; + ov->sensor = SEN_OV6620; } else if ((rc & 3) == 2) { info("Sensor is an OV6630AE"); - ov511->sensor = SEN_OV6630; + ov->sensor = SEN_OV6630; } else if ((rc & 3) == 3) { info("Sensor is an OV6630AF"); - ov511->sensor = SEN_OV6630; + ov->sensor = SEN_OV6630; } /* Set sensor-specific vars */ - if (ov511->sensor == SEN_OV6620) { - ov511->maxwidth = 352; - ov511->maxheight = 288; - } else { - /* 352x288 not working with OV518 yet */ - ov511->maxwidth = 320; - ov511->maxheight = 240; - } - ov511->minwidth = 64; - ov511->minheight = 48; + ov->maxwidth = 352; + ov->maxheight = 288; + ov->minwidth = 64; + ov->minheight = 48; // FIXME: These do not match the actual settings yet - ov511->brightness = 0x80 << 8; - ov511->contrast = 0x80 << 8; - ov511->colour = 0x80 << 8; - ov511->hue = 0x80 << 8; + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; - if (ov511->sensor == SEN_OV6620) { + if (ov->sensor == SEN_OV6620) { PDEBUG(4, "Writing 6x20 registers"); - if (ov511_write_regvals(ov511, aRegvalsNorm6x20)) + if (write_regvals(ov, aRegvalsNorm6x20)) return -1; } else { PDEBUG(4, "Writing 6x30 registers"); - if (ov511_write_regvals(ov511, aRegvalsNorm6x30)) + if (write_regvals(ov, aRegvalsNorm6x30)) return -1; } @@ -6203,13 +6108,13 @@ /* This initializes the KS0127 and KS0127B video decoders. */ static int -ks0127_configure(struct usb_ov511 *ov511) +ks0127_configure(struct usb_ov511 *ov) { int rc; // FIXME: I don't know how to sync or reset it yet #if 0 - if (ov51x_init_ks_sensor(ov511) < 0) { + if (ov51x_init_ks_sensor(ov) < 0) { err("Failed to initialize the KS0127"); return -1; } else { @@ -6218,21 +6123,21 @@ #endif /* Detect decoder subtype */ - rc = ov51x_i2c_read(ov511, 0x00); + rc = i2c_r(ov, 0x00); if (rc < 0) { err("Error detecting sensor type"); return -1; } else if (rc & 0x08) { - rc = ov51x_i2c_read(ov511, 0x3d); + rc = i2c_r(ov, 0x3d); if (rc < 0) { err("Error detecting sensor type"); return -1; } else if ((rc & 0x0f) == 0) { info("Sensor is a KS0127"); - ov511->sensor = SEN_KS0127; + ov->sensor = SEN_KS0127; } else if ((rc & 0x0f) == 9) { info("Sensor is a KS0127B Rev. A"); - ov511->sensor = SEN_KS0127B; + ov->sensor = SEN_KS0127B; } } else { err("Error: Sensor is an unsupported KS0122"); @@ -6240,16 +6145,16 @@ } /* Set sensor-specific vars */ - ov511->maxwidth = 640; - ov511->maxheight = 480; - ov511->minwidth = 64; - ov511->minheight = 48; + ov->maxwidth = 640; + ov->maxheight = 480; + ov->minwidth = 64; + ov->minheight = 48; // FIXME: These do not match the actual settings yet - ov511->brightness = 0x80 << 8; - ov511->contrast = 0x80 << 8; - ov511->colour = 0x80 << 8; - ov511->hue = 0x80 << 8; + ov->brightness = 0x80 << 8; + ov->contrast = 0x80 << 8; + ov->colour = 0x80 << 8; + ov->hue = 0x80 << 8; /* This device is not supported yet. Bail out now... */ err("This sensor is not supported yet."); @@ -6262,7 +6167,6 @@ static int saa7111a_configure(struct usb_ov511 *ov511) { - struct usb_device *dev = ov511->dev; int rc; /* Since there is no register reset command, all registers must be @@ -6297,7 +6201,7 @@ // FIXME: I don't know how to sync or reset it yet #if 0 - if (ov51x_init_saa_sensor(ov511) < 0) { + if (ov51x_init_saa_sensor(ov) < 0) { err("Failed to initialize the SAA7111A"); return -1; } else { @@ -6324,12 +6228,12 @@ ov511->hue = 32768; PDEBUG(4, "Writing SAA7111A registers"); - if (ov511_write_regvals(ov511, aRegvalsNormSAA7111A)) + if (write_regvals(ov511, aRegvalsNormSAA7111A)) return -1; /* Detect version of decoder. This must be done after writing the * initial regs or the decoder will lock up. */ - rc = ov51x_i2c_read(ov511, 0x00); + rc = i2c_r(ov511, 0x00); if (rc < 0) { err("Error detecting sensor version"); @@ -6342,8 +6246,8 @@ // FIXME: Fix this for OV518(+) /* Latch to negative edge of clock. Otherwise, we get incorrect * colors and jitter in the digital signal. */ - if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) - ov511_reg_write(dev, 0x11, 0x00); + if (ov511->bclass == BCL_OV511) + reg_w(ov511, 0x11, 0x00); else warn("SAA7111A not yet supported with OV518/OV518+"); @@ -6352,144 +6256,138 @@ /* This initializes the OV511/OV511+ and the sensor */ static int -ov511_configure(struct usb_ov511 *ov511) +ov511_configure(struct usb_ov511 *ov) { - struct usb_device *dev = ov511->dev; int i; static struct ov511_regvals aRegvalsInit511[] = { - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3f }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3d }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3f }, + { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3d }, { OV511_DONE_BUS, 0x0, 0x00}, }; static struct ov511_regvals aRegvalsNorm511[] = { - { OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x03 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, - { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x1f }, - { OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x00 }, - { OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 }, + { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0x01 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x03 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R511_FIFO_OPTS, 0x1f }, + { OV511_REG_BUS, R511_COMP_EN, 0x00 }, + { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, { OV511_DONE_BUS, 0x0, 0x00 }, }; static struct ov511_regvals aRegvalsNorm511Plus[] = { - { OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0xff }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x03 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x01 }, - { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0xff }, - { OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x00 }, - { OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 }, + { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0xff }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x03 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R511_FIFO_OPTS, 0xff }, + { OV511_REG_BUS, R511_COMP_EN, 0x00 }, + { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, { OV511_DONE_BUS, 0x0, 0x00 }, }; PDEBUG(4, ""); - ov511->customid = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID); - if (ov511->customid < 0) { + ov->customid = reg_r(ov, R511_SYS_CUST_ID); + if (ov->customid < 0) { err("Unable to read camera bridge registers"); goto error; } - ov511->desc = -1; - PDEBUG (1, "CustomID = %d", ov511->customid); + ov->desc = -1; + PDEBUG (1, "CustomID = %d", ov->customid); for (i = 0; clist[i].id >= 0; i++) { - if (ov511->customid == clist[i].id) { + if (ov->customid == clist[i].id) { info("model: %s", clist[i].description); - ov511->desc = i; + ov->desc = i; break; } } if (clist[i].id == -1) { - err("Camera type (%d) not recognized", ov511->customid); + err("Camera type (%d) not recognized", ov->customid); err("Please notify " EMAIL " of the name,"); err("manufacturer, model, and this number of your camera."); err("Also include the output of the detection process."); } if (clist[i].id == 6) { /* USB Life TV (NTSC) */ - ov511->tuner_type = 8; /* Temic 4036FY5 3X 1981 */ + ov->tuner_type = 8; /* Temic 4036FY5 3X 1981 */ } - if (ov511_write_regvals(ov511, aRegvalsInit511)) goto error; + if (write_regvals(ov, aRegvalsInit511)) goto error; - if (ov511->led_policy == LED_OFF || ov511->led_policy == LED_AUTO) - ov51x_led_control(ov511, 0); + if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); /* The OV511+ has undocumented bits in the flow control register. * Setting it to 0xff fixes the corruption with moving objects. */ - if (ov511->bridge == BRG_OV511) { - if (ov511_write_regvals(ov511, aRegvalsNorm511)) goto error; - } else if (ov511->bridge == BRG_OV511PLUS) { - if (ov511_write_regvals(ov511, aRegvalsNorm511Plus)) goto error; + if (ov->bridge == BRG_OV511) { + if (write_regvals(ov, aRegvalsNorm511)) goto error; + } else if (ov->bridge == BRG_OV511PLUS) { + if (write_regvals(ov, aRegvalsNorm511Plus)) goto error; } else { err("Invalid bridge"); } - if (ov511_init_compression(ov511)) goto error; + if (ov511_init_compression(ov)) goto error; - ov511_set_packet_size(ov511, 0); + ov51x_set_packet_size(ov, 0); - ov511->snap_enabled = snapshot; + ov->snap_enabled = snapshot; /* Test for 7xx0 */ PDEBUG(3, "Testing for 0V7xx0"); - ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID, - OV7xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) goto error; - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) { + if (i2c_w(ov, 0x12, 0x80) < 0) { /* Test for 6xx0 */ PDEBUG(3, "Testing for 0V6xx0"); - ov511->primary_i2c_slave = OV6xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV6xx0_I2C_WRITE_ID, - OV6xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV6xx0_SID; + if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) goto error; - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) { + if (i2c_w(ov, 0x12, 0x80) < 0) { /* Test for 8xx0 */ PDEBUG(3, "Testing for 0V8xx0"); - ov511->primary_i2c_slave = OV8xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV8xx0_I2C_WRITE_ID, - OV8xx0_I2C_READ_ID)) + ov->primary_i2c_slave = OV8xx0_SID; + if (ov51x_set_slave_ids(ov, OV8xx0_SID)) goto error; - if (ov51x_i2c_write(ov511, 0x12, 0x80) < 0) { + if (i2c_w(ov, 0x12, 0x80) < 0) { /* Test for SAA7111A */ PDEBUG(3, "Testing for SAA7111A"); - ov511->primary_i2c_slave = SAA7111A_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, SAA7111A_I2C_WRITE_ID, - SAA7111A_I2C_READ_ID)) + ov->primary_i2c_slave = SAA7111A_SID; + if (ov51x_set_slave_ids(ov, SAA7111A_SID)) goto error; - if (ov51x_i2c_write(ov511, 0x0d, 0x00) < 0) { + if (i2c_w(ov, 0x0d, 0x00) < 0) { /* Test for KS0127 */ PDEBUG(3, "Testing for KS0127"); - ov511->primary_i2c_slave = KS0127_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, KS0127_I2C_WRITE_ID, - KS0127_I2C_READ_ID)) + ov->primary_i2c_slave = KS0127_SID; + if (ov51x_set_slave_ids(ov, KS0127_SID)) goto error; - if (ov51x_i2c_write(ov511, 0x10, 0x00) < 0) { + if (i2c_w(ov, 0x10, 0x00) < 0) { err("Can't determine sensor slave IDs"); goto error; } else { - if(ks0127_configure(ov511) < 0) { + if (ks0127_configure(ov) < 0) { err("Failed to configure KS0127"); goto error; } } } else { - if(saa7111a_configure(ov511) < 0) { + if (saa7111a_configure(ov) < 0) { err("Failed to configure SAA7111A"); goto error; } @@ -6499,13 +6397,13 @@ goto error; } } else { - if(ov6xx0_configure(ov511) < 0) { + if (ov6xx0_configure(ov) < 0) { err("Failed to configure OV6xx0"); goto error; } } } else { - if(ov7xx0_configure(ov511) < 0) { + if (ov7xx0_configure(ov) < 0) { err("Failed to configure OV7xx0"); goto error; } @@ -6521,96 +6419,90 @@ /* This initializes the OV518/OV518+ and the sensor */ static int -ov518_configure(struct usb_ov511 *ov511) +ov518_configure(struct usb_ov511 *ov) { - struct usb_device *dev = ov511->dev; - static struct ov511_regvals aRegvalsInit518[] = { - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x40 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3e }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x00 }, - { OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0xe1 }, - { OV511_REG_BUS, 0x46, 0x00 }, - { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x40 }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x3e }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, R51x_SYS_RESET, 0x00 }, + { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, + { OV511_REG_BUS, 0x46, 0x00 }, + { OV511_REG_BUS, 0x5d, 0x03 }, { OV511_DONE_BUS, 0x0, 0x00}, }; /* New values, based on Windows driver. Since what they do is not * known yet, this may be incorrect. */ static struct ov511_regvals aRegvalsNorm518[] = { - { OV511_REG_BUS, 0x52, 0x02 }, /* Reset snapshot */ - { OV511_REG_BUS, 0x52, 0x01 }, /* Enable snapshot */ - { OV511_REG_BUS, 0x31, 0x0f }, - { OV511_REG_BUS, 0x5d, 0x03 }, - { OV511_REG_BUS, 0x24, 0x9f }, - { OV511_REG_BUS, 0x25, 0x90 }, - { OV511_REG_BUS, 0x20, 0x00 }, /* Was 0x08 */ - { OV511_REG_BUS, 0x51, 0x04 }, - { OV511_REG_BUS, 0x71, 0x19 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ + { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ + { OV511_REG_BUS, 0x31, 0x0f }, + { OV511_REG_BUS, 0x5d, 0x03 }, + { OV511_REG_BUS, 0x24, 0x9f }, + { OV511_REG_BUS, 0x25, 0x90 }, + { OV511_REG_BUS, 0x20, 0x00 }, /* Was 0x08 */ + { OV511_REG_BUS, 0x51, 0x04 }, + { OV511_REG_BUS, 0x71, 0x19 }, { OV511_DONE_BUS, 0x0, 0x00 }, }; PDEBUG(4, ""); /* First 5 bits of custom ID reg are a revision ID on OV518 */ - info("Device revision %d", - 0x1F & ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID)); + info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID)); - if (ov511_write_regvals(ov511, aRegvalsInit518)) goto error; + if (write_regvals(ov, aRegvalsInit518)) goto error; /* Set LED GPIO pin to output mode */ - if (ov511_reg_write_mask(dev, 0x57,0x00, 0x02) < 0) goto error; + if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0) goto error; /* LED is off by default with OV518; have to explicitly turn it on */ - if (ov511->led_policy == LED_OFF || ov511->led_policy == LED_AUTO) - ov51x_led_control(ov511, 0); + if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) + ov51x_led_control(ov, 0); else - ov51x_led_control(ov511, 1); + ov51x_led_control(ov, 1); /* Don't require compression if dumppix is enabled; otherwise it's * required. OV518 has no uncompressed mode, to save RAM. */ - if (!dumppix && !ov511->compress) { - ov511->compress = 1; + if (!dumppix && !ov->compress) { + ov->compress = 1; warn("Compression required with OV518...enabling"); } - if (ov511_write_regvals(ov511, aRegvalsNorm518)) goto error; + if (write_regvals(ov, aRegvalsNorm518)) goto error; - if (ov511_reg_write(dev, 0x2f,0x80) < 0) goto error; + if (reg_w(ov, 0x2f, 0x80) < 0) goto error; - if (ov518_init_compression(ov511)) goto error; + if (ov518_init_compression(ov)) goto error; - ov511_set_packet_size(ov511, 0); + ov51x_set_packet_size(ov, 0); - ov511->snap_enabled = snapshot; + ov->snap_enabled = snapshot; /* Test for 76xx */ - ov511->primary_i2c_slave = OV7xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV7xx0_I2C_WRITE_ID, - OV7xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV7xx0_SID; + if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) goto error; /* The OV518 must be more aggressive about sensor detection since * I2C write will never fail if the sensor is not present. We have * to try to initialize the sensor to detect its presence */ - if (ov51x_init_ov_sensor(ov511) < 0) { + if (init_ov_sensor(ov) < 0) { /* Test for 6xx0 */ - ov511->primary_i2c_slave = OV6xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV6xx0_I2C_WRITE_ID, - OV6xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV6xx0_SID; + if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) goto error; - if (ov51x_init_ov_sensor(ov511) < 0) { + if (init_ov_sensor(ov) < 0) { /* Test for 8xx0 */ - ov511->primary_i2c_slave = OV8xx0_I2C_WRITE_ID; - if (ov51x_set_slave_ids(ov511, OV8xx0_I2C_WRITE_ID, - OV8xx0_I2C_READ_ID) < 0) + ov->primary_i2c_slave = OV8xx0_SID; + if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) goto error; - if (ov51x_init_ov_sensor(ov511) < 0) { + if (init_ov_sensor(ov) < 0) { err("Can't determine sensor slave IDs"); goto error; } else { @@ -6618,21 +6510,25 @@ goto error; } } else { - if (ov6xx0_configure(ov511) < 0) { + if (ov6xx0_configure(ov) < 0) { err("Failed to configure OV6xx0"); goto error; } } } else { - if (ov7xx0_configure(ov511) < 0) { + if (ov7xx0_configure(ov) < 0) { err("Failed to configure OV7xx0"); goto error; } } + // FIXME: Sizes > 320x240 are not working yet + ov->maxwidth = 320; + ov->maxheight = 240; + // The OV518 cannot go as low as the sensor can - ov511->minwidth = 160; - ov511->minheight = 120; + ov->minwidth = 160; + ov->minheight = 120; return 0; @@ -6649,12 +6545,13 @@ * ***************************************************************************/ +/* 2.2.x compatibility */ static void * ov51x_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) { struct usb_interface_descriptor *interface; - struct usb_ov511 *ov511; + struct usb_ov511 *ov; int i; int registered = 0; @@ -6672,57 +6569,54 @@ if (interface->bInterfaceSubClass != 0x00) return NULL; - /* Since code below may sleep, we use this as a lock */ - MOD_INC_USE_COUNT; - - if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) { - err("couldn't kmalloc ov511 struct"); - goto error_unlock; - } - - memset(ov511, 0, sizeof(*ov511)); - - ov511->dev = dev; - ov511->iface = interface->bInterfaceNumber; - ov511->led_policy = led; - ov511->compress = compress; - ov511->lightfreq = lightfreq; - ov511->num_inputs = 1; /* Video decoder init functs. change this */ - ov511->stop_during_set = !fastset; - ov511->tuner_type = tuner; - ov511->backlight = backlight; - - ov511->auto_brt = autobright; - ov511->auto_gain = autogain; - ov511->auto_exp = autoexp; + if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) { + err("couldn't kmalloc ov struct"); + goto error_out; + } + + memset(ov, 0, sizeof(*ov)); + + ov->dev = dev; + ov->iface = interface->bInterfaceNumber; + ov->led_policy = led; + ov->compress = compress; + ov->lightfreq = lightfreq; + ov->num_inputs = 1; /* Video decoder init functs. change this */ + ov->stop_during_set = !fastset; + ov->tuner_type = tuner; + ov->backlight = backlight; + + ov->auto_brt = autobright; + ov->auto_gain = autogain; + ov->auto_exp = autoexp; switch (dev->descriptor.idProduct) { case PROD_OV511: info("USB OV511 camera found"); - ov511->bridge = BRG_OV511; - ov511->bclass = BCL_OV511; + ov->bridge = BRG_OV511; + ov->bclass = BCL_OV511; break; case PROD_OV511PLUS: info("USB OV511+ camera found"); - ov511->bridge = BRG_OV511PLUS; - ov511->bclass = BCL_OV511; + ov->bridge = BRG_OV511PLUS; + ov->bclass = BCL_OV511; break; case PROD_OV518: info("USB OV518 camera found"); - ov511->bridge = BRG_OV518; - ov511->bclass = BCL_OV518; + ov->bridge = BRG_OV518; + ov->bclass = BCL_OV518; break; case PROD_OV518PLUS: info("USB OV518+ camera found"); - ov511->bridge = BRG_OV518PLUS; - ov511->bclass = BCL_OV518; + ov->bridge = BRG_OV518PLUS; + ov->bclass = BCL_OV518; break; case PROD_ME2CAM: if (dev->descriptor.idVendor != VEND_MATTEL) goto error; info("Intel Play Me2Cam (OV511+) found"); - ov511->bridge = BRG_OV511PLUS; - ov511->bclass = BCL_OV511; + ov->bridge = BRG_OV511PLUS; + ov->bclass = BCL_OV511; break; default: err("Unknown product ID 0x%x", dev->descriptor.idProduct); @@ -6734,47 +6628,53 @@ if (force_rgb) info("data format set to RGB"); - init_waitqueue_head(&ov511->wq); + init_waitqueue_head(&ov->wq); + + init_MUTEX(&ov->lock); /* to 1 == available */ + init_MUTEX(&ov->buf_lock); + init_MUTEX(&ov->param_lock); + init_MUTEX(&ov->i2c_lock); + init_MUTEX(&ov->cbuf_lock); + + ov->buf_state = BUF_NOT_ALLOCATED; + + /* Must be kmalloc()'ed, for DMA accessibility */ + ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL); + if (!ov->cbuf) + goto error; - init_MUTEX(&ov511->lock); /* to 1 == available */ - init_MUTEX(&ov511->buf_lock); - init_MUTEX(&ov511->param_lock); - init_MUTEX(&ov511->i2c_lock); - ov511->buf_state = BUF_NOT_ALLOCATED; - - if (ov511->bridge == BRG_OV518 || - ov511->bridge == BRG_OV518PLUS) { - if (ov518_configure(ov511) < 0) + if (ov->bclass == BCL_OV518) { + if (ov518_configure(ov) < 0) goto error; } else { - if (ov511_configure(ov511) < 0) + if (ov511_configure(ov) < 0) goto error; } for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].framenum = i; - init_waitqueue_head(&ov511->frame[i].wq); + ov->frame[i].framenum = i; + init_waitqueue_head(&ov->frame[i].wq); } /* Unnecessary? (This is done on open(). Need to make sure variables * are properly initialized without this before removing it, though). */ - if (ov51x_set_default_params(ov511) < 0) + if (ov51x_set_default_params(ov) < 0) goto error; #ifdef OV511_DEBUG if (dump_bridge) - ov511_dump_regs(dev); + ov511_dump_regs(ov); #endif - memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template)); - ov511->vdev.priv = ov511; + memcpy(&ov->vdev, &vdev_template, sizeof(vdev_template)); + ov->vdev.priv = ov; for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) { /* Minor 0 cannot be specified; assume user wants autodetect */ if (unit_video[i] == 0) break; - if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER, + if (video_register_device(&ov->vdev, VFL_TYPE_GRABBER, unit_video[i]) >= 0) { registered = 1; break; @@ -6783,35 +6683,40 @@ /* Use the next available one */ if (!registered && - video_register_device(&ov511->vdev, VFL_TYPE_GRABBER, -1) < 0) { + video_register_device(&ov->vdev, VFL_TYPE_GRABBER, -1) < 0) { err("video_register_device failed"); goto error; } - info("Device registered on minor %d", ov511->vdev.minor); + info("Device registered on minor %d", ov->vdev.minor); - MOD_DEC_USE_COUNT; - return ov511; + return ov; error: err("Camera initialization failed"); #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) /* Safe to call even if entry doesn't exist */ - destroy_proc_ov511_cam(ov511); + destroy_proc_ov511_cam(ov); #endif + if (ov->cbuf) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + } + usb_driver_release_interface(&ov511_driver, - &dev->actconfig->interface[ov511->iface]); + &dev->actconfig->interface[ov->iface]); error_dealloc: - if (ov511) { - kfree(ov511); - ov511 = NULL; + if (ov) { + kfree(ov); + ov = NULL; } -error_unlock: - MOD_DEC_USE_COUNT; +error_out: return NULL; } @@ -6819,62 +6724,64 @@ static void ov51x_disconnect(struct usb_device *dev, void *ptr) { - struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr; + struct usb_ov511 *ov = (struct usb_ov511 *) ptr; int n; - MOD_INC_USE_COUNT; - PDEBUG(3, ""); /* We don't want people trying to open up the device */ - if (!ov511->user) - video_unregister_device(&ov511->vdev); + if (!ov->user) + video_unregister_device(&ov->vdev); else PDEBUG(3, "Device open...deferring video_unregister_device"); for (n = 0; n < OV511_NUMFRAMES; n++) - ov511->frame[n].grabstate = FRAME_ERROR; + ov->frame[n].grabstate = FRAME_ERROR; - ov511->curframe = -1; + ov->curframe = -1; /* This will cause the process to request another frame */ for (n = 0; n < OV511_NUMFRAMES; n++) - if (waitqueue_active(&ov511->frame[n].wq)) - wake_up_interruptible(&ov511->frame[n].wq); - if (waitqueue_active(&ov511->wq)) - wake_up_interruptible(&ov511->wq); + if (waitqueue_active(&ov->frame[n].wq)) + wake_up_interruptible(&ov->frame[n].wq); + if (waitqueue_active(&ov->wq)) + wake_up_interruptible(&ov->wq); - ov511->streaming = 0; + ov->streaming = 0; /* Unschedule all of the iso td's */ for (n = OV511_NUMSBUF - 1; n >= 0; n--) { - if (ov511->sbuf[n].urb) { - ov511->sbuf[n].urb->next = NULL; - usb_unlink_urb(ov511->sbuf[n].urb); - usb_free_urb(ov511->sbuf[n].urb); - ov511->sbuf[n].urb = NULL; + if (ov->sbuf[n].urb) { + ov->sbuf[n].urb->next = NULL; + usb_unlink_urb(ov->sbuf[n].urb); + usb_free_urb(ov->sbuf[n].urb); + ov->sbuf[n].urb = NULL; } } #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - destroy_proc_ov511_cam(ov511); + destroy_proc_ov511_cam(ov); #endif usb_driver_release_interface(&ov511_driver, - &ov511->dev->actconfig->interface[ov511->iface]); - ov511->dev = NULL; + &ov->dev->actconfig->interface[ov->iface]); + ov->dev = NULL; /* Free the memory */ - if (ov511 && !ov511->user) { - ov511_dealloc(ov511, 1); - kfree(ov511); - ov511 = NULL; + if (ov && !ov->user) { + down(&ov->cbuf_lock); + kfree(ov->cbuf); + ov->cbuf = NULL; + up(&ov->cbuf_lock); + + ov51x_dealloc(ov, 1); + kfree(ov); + ov = NULL; } - - MOD_DEC_USE_COUNT; } static struct usb_driver ov511_driver = { + owner: THIS_MODULE, name: "ov511", id_table: device_table, probe: ov51x_probe, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/ov511.h linux-2.5/drivers/usb/ov511.h --- linux-2.5.5/drivers/usb/ov511.h Thu Feb 21 17:47:41 2002 +++ linux-2.5/drivers/usb/ov511.h Tue Mar 5 14:07:52 2002 @@ -9,11 +9,11 @@ #define OV511_DEBUG /* Turn on debug messages */ #ifdef OV511_DEBUG -# define PDEBUG(level, fmt, args...) \ -if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , \ - ## args) + #define PDEBUG(level, fmt, args...) \ + if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt,\ + __LINE__ , ## args) #else -# define PDEBUG(level, fmt, args...) do {} while(0) + #define PDEBUG(level, fmt, args...) do {} while(0) #endif /* This macro restricts an int variable to an inclusive range */ @@ -36,98 +36,105 @@ #define VEND_MATTEL 0x0813 #define PROD_ME2CAM 0x0002 +/* --------------------------------- */ +/* OV51x REGISTER MNEMONICS */ +/* --------------------------------- */ + /* Camera interface register numbers */ -#define OV511_REG_CAMERA_DELAY_MODE 0x10 -#define OV511_REG_CAMERA_EDGE_MODE 0x11 -#define OV511_REG_CAMERA_CLAMPED_PIXEL_NUM 0x12 -#define OV511_REG_CAMERA_CLAMPED_LINE_NUM 0x13 -#define OV511_REG_CAMERA_PIXEL_DIVISOR 0x14 -#define OV511_REG_CAMERA_LINE_DIVISOR 0x15 -#define OV511_REG_CAMERA_DATA_INPUT_SELECT 0x16 -#define OV511_REG_CAMERA_RESERVED_LINE_MODE 0x17 -#define OV511_REG_CAMERA_BITMASK 0x18 +#define R511_CAM_DELAY 0x10 +#define R511_CAM_EDGE 0x11 +#define R511_CAM_PXCNT 0x12 +#define R511_CAM_LNCNT 0x13 +#define R511_CAM_PXDIV 0x14 +#define R511_CAM_LNDIV 0x15 +#define R511_CAM_UV_EN 0x16 +#define R511_CAM_LINE_MODE 0x17 +#define R511_CAM_OPTS 0x18 /* Snapshot mode camera interface register numbers */ -#define OV511_REG_SNAP_CAPTURED_FRAME 0x19 -#define OV511_REG_SNAP_CLAMPED_PIXEL_NUM 0x1A -#define OV511_REG_SNAP_CLAMPED_LINE_NUM 0x1B -#define OV511_REG_SNAP_PIXEL_DIVISOR 0x1C -#define OV511_REG_SNAP_LINE_DIVISOR 0x1D -#define OV511_REG_SNAP_DATA_INPUT_SELECT 0x1E -#define OV511_REG_SNAP_BITMASK 0x1F +#define R511_SNAP_FRAME 0x19 +#define R511_SNAP_PXCNT 0x1A +#define R511_SNAP_LNCNT 0x1B +#define R511_SNAP_PXDIV 0x1C +#define R511_SNAP_LNDIV 0x1D +#define R511_SNAP_UV_EN 0x1E +#define R511_SNAP_OPTS 0x1F /* DRAM register numbers */ -#define OV511_REG_DRAM_ENABLE_FLOW_CONTROL 0x20 -#define OV511_REG_DRAM_READ_CYCLE_PREDICT 0x21 -#define OV511_REG_DRAM_MANUAL_READ_CYCLE 0x22 -#define OV511_REG_DRAM_REFRESH_COUNTER 0x23 +#define R511_DRAM_FLOW_CTL 0x20 +#define R511_DRAM_ARCP 0x21 +#define R511_DRAM_MRC 0x22 +#define R511_DRAM_RFC 0x23 /* ISO FIFO register numbers */ -#define OV511_REG_FIFO_PACKET_SIZE 0x30 -#define OV511_REG_FIFO_BITMASK 0x31 +#define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */ +#define R511_FIFO_OPTS 0x31 -/* PIO register numbers */ -#define OV511_REG_PIO_BITMASK 0x38 -#define OV511_REG_PIO_DATA_PORT 0x39 -#define OV511_REG_PIO_BIST 0x3E - -/* I2C register numbers */ -#define OV511_REG_I2C_CONTROL 0x40 -#define OV518_REG_I2C_CONTROL 0x47 /* OV518(+) only */ -#define OV511_REG_I2C_SLAVE_ID_WRITE 0x41 -#define OV511_REG_I2C_SUB_ADDRESS_3_BYTE 0x42 -#define OV511_REG_I2C_SUB_ADDRESS_2_BYTE 0x43 -#define OV511_REG_I2C_SLAVE_ID_READ 0x44 -#define OV511_REG_I2C_DATA_PORT 0x45 -#define OV511_REG_I2C_CLOCK_PRESCALER 0x46 -#define OV511_REG_I2C_TIME_OUT_COUNTER 0x47 - -/* I2C snapshot register numbers */ -#define OV511_REG_I2C_SNAP_SUB_ADDRESS 0x48 -#define OV511_REG_I2C_SNAP_DATA_PORT 0x49 - -/* System control register numbers */ -#define OV511_REG_SYSTEM_RESET 0x50 -#define OV511_RESET_UDC 0x01 -#define OV511_RESET_I2C 0x02 -#define OV511_RESET_FIFO 0x04 -#define OV511_RESET_OMNICE 0x08 -#define OV511_RESET_DRAM_INTF 0x10 -#define OV511_RESET_CAMERA_INTF 0x20 -#define OV511_RESET_OV511 0x40 -#define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */ -#define OV511_RESET_ALL 0x7F -#define OV511_REG_SYSTEM_CLOCK_DIVISOR 0x51 -#define OV511_REG_SYSTEM_SNAPSHOT 0x52 -#define OV511_REG_SYSTEM_INIT 0x53 -#define OV511_REG_SYSTEM_PWR_CLK 0x54 /* OV511+/OV518(+) only */ -#define OV511_REG_SYSTEM_LED_CTL 0x55 /* OV511+ only */ -#define OV518_REG_GPIO_IN 0x55 /* OV518(+) only */ -#define OV518_REG_GPIO_OUT 0x56 /* OV518(+) only */ -#define OV518_REG_GPIO_CTL 0x57 /* OV518(+) only */ -#define OV518_REG_GPIO_PULSE_IN 0x58 /* OV518(+) only */ -#define OV518_REG_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */ -#define OV518_REG_GPIO_PULSE_POLARITY 0x5a /* OV518(+) only */ -#define OV518_REG_GPIO_PULSE_EN 0x5b /* OV518(+) only */ -#define OV518_REG_GPIO_RESET 0x5c /* OV518(+) only */ -#define OV511_REG_SYSTEM_USER_DEFINED 0x5E -#define OV511_REG_SYSTEM_CUSTOM_ID 0x5F - -/* OmniCE register numbers */ -#define OV511_OMNICE_PREDICTION_HORIZ_Y 0x70 -#define OV511_OMNICE_PREDICTION_HORIZ_UV 0x71 -#define OV511_OMNICE_PREDICTION_VERT_Y 0x72 -#define OV511_OMNICE_PREDICTION_VERT_UV 0x73 -#define OV511_OMNICE_QUANTIZATION_HORIZ_Y 0x74 -#define OV511_OMNICE_QUANTIZATION_HORIZ_UV 0x75 -#define OV511_OMNICE_QUANTIZATION_VERT_Y 0x76 -#define OV511_OMNICE_QUANTIZATION_VERT_UV 0x77 -#define OV511_OMNICE_ENABLE 0x78 -#define OV511_OMNICE_LUT_ENABLE 0x79 -#define OV511_OMNICE_Y_LUT_BEGIN 0x80 -#define OV511_OMNICE_Y_LUT_END 0x9F -#define OV511_OMNICE_UV_LUT_BEGIN 0xA0 -#define OV511_OMNICE_UV_LUT_END 0xBF +/* Parallel IO register numbers */ +#define R511_PIO_OPTS 0x38 +#define R511_PIO_DATA 0x39 +#define R511_PIO_BIST 0x3E +#define R518_GPIO_IN 0x55 /* OV518(+) only */ +#define R518_GPIO_OUT 0x56 /* OV518(+) only */ +#define R518_GPIO_CTL 0x57 /* OV518(+) only */ +#define R518_GPIO_PULSE_IN 0x58 /* OV518(+) only */ +#define R518_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */ +#define R518_GPIO_PULSE_POL 0x5a /* OV518(+) only */ +#define R518_GPIO_PULSE_EN 0x5b /* OV518(+) only */ +#define R518_GPIO_RESET 0x5c /* OV518(+) only */ + +/* I2C registers */ +#define R511_I2C_CTL 0x40 +#define R518_I2C_CTL 0x47 /* OV518(+) only */ +#define R51x_I2C_W_SID 0x41 +#define R51x_I2C_SADDR_3 0x42 +#define R51x_I2C_SADDR_2 0x43 +#define R51x_I2C_R_SID 0x44 +#define R51x_I2C_DATA 0x45 +#define R51x_I2C_CLOCK 0x46 +#define R51x_I2C_TIMEOUT 0x47 + +/* I2C snapshot registers */ +#define R511_SI2C_SADDR_3 0x48 +#define R511_SI2C_DATA 0x49 + +/* System control registers */ +#define R51x_SYS_RESET 0x50 + /* Reset type definitions */ +#define OV511_RESET_UDC 0x01 +#define OV511_RESET_I2C 0x02 +#define OV511_RESET_FIFO 0x04 +#define OV511_RESET_OMNICE 0x08 +#define OV511_RESET_DRAM 0x10 +#define OV511_RESET_CAM_INT 0x20 +#define OV511_RESET_OV511 0x40 +#define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */ +#define OV511_RESET_ALL 0x7F + +#define R511_SYS_CLOCK_DIV 0x51 +#define R51x_SYS_SNAP 0x52 +#define R51x_SYS_INIT 0x53 +#define R511_SYS_PWR_CLK 0x54 /* OV511+/OV518(+) only */ +#define R511_SYS_LED_CTL 0x55 /* OV511+ only */ +#define R511_SYS_USER 0x5E +#define R511_SYS_CUST_ID 0x5F + +/* OmniCE (compression) registers */ +#define R511_COMP_PHY 0x70 +#define R511_COMP_PHUV 0x71 +#define R511_COMP_PVY 0x72 +#define R511_COMP_PVUV 0x73 +#define R511_COMP_QHY 0x74 +#define R511_COMP_QHUV 0x75 +#define R511_COMP_QVY 0x76 +#define R511_COMP_QVUV 0x77 +#define R511_COMP_EN 0x78 +#define R511_COMP_LUT_EN 0x79 +#define R511_COMP_LUT_BEGIN 0x80 + +/* --------------------------------- */ +/* ALTERNATE NUMBERS */ +/* --------------------------------- */ /* Alternate numbers for various max packet sizes (OV511 only) */ #define OV511_ALT_SIZE_992 0 @@ -159,6 +166,10 @@ #define OV518_ALT_SIZE_768 6 #define OV518_ALT_SIZE_896 7 +/* --------------------------------- */ +/* OV7610 REGISTER MNEMONICS */ +/* --------------------------------- */ + /* OV7610 registers */ #define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ #define OV7610_REG_BLUE 0x01 /* blue channel balance */ @@ -210,26 +221,27 @@ /* 36-37 reserved */ #define OV7610_REG_COM_K 0x38 /* misc registers */ +/* --------------------------------- */ +/* I2C ADDRESSES */ +/* --------------------------------- */ + +#define OV7xx0_SID 0x42 +#define OV6xx0_SID 0xC0 +#define OV8xx0_SID 0xA0 +#define KS0127_SID 0xD8 +#define SAA7111A_SID 0x48 + +/* --------------------------------- */ +/* MISCELLANEOUS DEFINES */ +/* --------------------------------- */ + +#define I2C_CLOCK_PRESCALER 0x03 + #define FRAMES_PER_DESC 10 /* FIXME - What should this be? */ -#define FRAME_SIZE_PER_DESC 993 /* FIXME - Deprecated */ #define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */ #define PIXELS_PER_SEG 256 /* Pixels per segment */ -#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ - -/* I2C addresses */ -#define OV7xx0_I2C_WRITE_ID 0x42 -#define OV7xx0_I2C_READ_ID 0x43 -#define OV6xx0_I2C_WRITE_ID 0xC0 -#define OV6xx0_I2C_READ_ID 0xC1 -#define OV8xx0_I2C_WRITE_ID 0xA0 -#define OV8xx0_I2C_READ_ID 0xA1 -#define KS0127_I2C_WRITE_ID 0xD8 -#define KS0127_I2C_READ_ID 0xD9 -#define SAA7111A_I2C_WRITE_ID 0x48 -#define SAA7111A_I2C_READ_ID 0x49 - -#define OV511_I2C_CLOCK_PRESCALER 0x03 +#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ /* Bridge types */ enum { @@ -429,11 +441,14 @@ #define OV511_NUMFRAMES 2 #if OV511_NUMFRAMES > VIDEO_MAX_FRAME -#error "OV511_NUMFRAMES is too high" + #error "OV511_NUMFRAMES is too high" #endif #define OV511_NUMSBUF 2 +/* Control transfers use up to 4 bytes */ +#define OV511_CBUF_SIZE 4 + struct usb_ov511 { struct video_device vdev; @@ -535,6 +550,10 @@ /* I2C interface to kernel */ struct semaphore i2c_lock; /* Protect I2C controller regs */ unsigned char primary_i2c_slave; /* I2C write id of sensor */ + + /* Control transaction stuff */ + unsigned char *cbuf; /* Buffer for payload */ + struct semaphore cbuf_lock; }; struct cam_list { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/powermate.c linux-2.5/drivers/usb/powermate.c --- linux-2.5.5/drivers/usb/powermate.c Thu Jan 1 00:00:00 1970 +++ linux-2.5/drivers/usb/powermate.c Fri Feb 8 09:44:26 2002 @@ -0,0 +1,356 @@ +/* + * A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial. + * + * v1.0, (c)2002 William R Sowerbutts + * + * This device is a stainless steel knob which connects over USB. It can measure + * clockwise and anticlockwise rotation. The dial also acts as a pushbutton with + * a spring for automatic release. The base contains a pair of LEDs which illuminate + * the translucent base. It rotates without limit and reports its relative rotation + * back to the host when polled by the USB controller. + * + * Testing with the knob I have has shown that it measures approximately 94 "clicks" + * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was + * a variable speed cordless electric drill) has shown that the device can measure + * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from + * the host. If it counts more than 7 clicks before it is polled, it will wrap back + * to zero and start counting again. This was at quite high speed, however, almost + * certainly faster than the human hand could turn it. + * + * The device's microcontroller can be programmed to set the LED to either a constant + * intensity, or to a rhythmic pulsing. Several patterns and speeds are available. + * + * Griffin were very happy to provide documentation and free hardware for development. + * + */ + +#include +#include +#include +#include +#include +#include + +#define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */ +#define POWERMATE_PRODUCT_NEW 0x0410 /* Griffin PowerMate */ +#define POWERMATE_PRODUCT_OLD 0x04AA /* Griffin soundKnob */ + +/* these are the command codes we send to the device */ +#define SET_STATIC_BRIGHTNESS 0x01 +#define SET_PULSE_ASLEEP 0x02 +#define SET_PULSE_AWAKE 0x03 +#define SET_PULSE_MODE 0x04 + +/* these refer to bits in the powermate_device's requires_update field. */ +#define UPDATE_STATIC_BRIGHTNESS (1<<0) +#define UPDATE_PULSE_ASLEEP (1<<1) +#define UPDATE_PULSE_AWAKE (1<<2) +#define UPDATE_PULSE_MODE (1<<3) + +#define POWERMATE_PAYLOAD_SIZE 3 +struct powermate_device { + signed char data[POWERMATE_PAYLOAD_SIZE]; + struct urb irq, config; + struct usb_ctrlrequest configcr; + struct usb_device *udev; + struct input_dev input; + struct semaphore lock; + int static_brightness; + int pulse_speed; + int pulse_table; + int pulse_asleep; + int pulse_awake; + int requires_update; // physical settings which are out of sync + char phys[64]; +}; + +static char pm_name_powermate[] = "Griffin PowerMate"; +static char pm_name_soundknob[] = "Griffin SoundKnob"; + +static void powermate_config_complete(struct urb *urb); /* forward declararation of callback */ + +/* Callback for data arriving from the PowerMate over the USB interrupt pipe */ +static void powermate_irq(struct urb *urb) +{ + struct powermate_device *pm = urb->context; + + if(urb->status) + return; + + /* handle updates to device state */ + input_report_key(&pm->input, BTN_0, pm->data[0] & 0x01); + input_report_rel(&pm->input, REL_DIAL, pm->data[1]); +} + +/* Decide if we need to issue a control message and do so. Must be called with pm->lock down */ +static void powermate_sync_state(struct powermate_device *pm) +{ + if(pm->requires_update == 0) + return; /* no updates are required */ + if(pm->config.status == -EINPROGRESS) + return; /* an update is already in progress; it'll issue this update when it completes */ + + if(pm->requires_update & UPDATE_STATIC_BRIGHTNESS){ + pm->configcr.wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS ); + pm->configcr.wIndex = cpu_to_le16( pm->static_brightness ); + pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS; + }else if(pm->requires_update & UPDATE_PULSE_ASLEEP){ + pm->configcr.wValue = cpu_to_le16( SET_PULSE_ASLEEP ); + pm->configcr.wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 ); + pm->requires_update &= ~UPDATE_PULSE_ASLEEP; + }else if(pm->requires_update & UPDATE_PULSE_AWAKE){ + pm->configcr.wValue = cpu_to_le16( SET_PULSE_AWAKE ); + pm->configcr.wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 ); + pm->requires_update &= ~UPDATE_PULSE_AWAKE; + }else if(pm->requires_update & UPDATE_PULSE_MODE){ + int op, arg; + /* the powermate takes an operation and an argument for its pulse algorithm. + the operation can be: + 0: divide the speed + 1: pulse at normal speed + 2: multiply the speed + the argument only has an effect for operations 0 and 2, and ranges between + 1 (least effect) to 255 (maximum effect). + + thus, several states are equivalent and are coalesced into one state. + + we map this onto a range from 0 to 510, with: + 0 -- 254 -- use divide (0 = slowest) + 255 -- use normal speed + 256 -- 510 -- use multiple (510 = fastest). + + Only values of 'arg' quite close to 255 are particularly useful/spectacular. + */ + if(pm->pulse_speed < 255){ + op = 0; // divide + arg = 255 - pm->pulse_speed; + }else if(pm->pulse_speed > 255){ + op = 2; // multiply + arg = pm->pulse_speed - 255; + }else{ + op = 1; // normal speed + arg = 0; // can be any value + } + pm->configcr.wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE ); + pm->configcr.wIndex = cpu_to_le16( (arg << 8) | op ); + pm->requires_update &= ~UPDATE_PULSE_MODE; + }else{ + printk(KERN_ERR "powermate: unknown update required"); + pm->requires_update = 0; /* fudge the bug */ + return; + } + +/* printk("powermate: %04x %04x\n", pm->configcr.wValue, pm->configcr.wIndex); */ + + pm->config.dev = pm->udev; /* is this necessary? */ + pm->configcr.bRequestType = 0x41; /* vendor request */ + pm->configcr.bRequest = 0x01; + pm->configcr.wLength = 0; + + FILL_CONTROL_URB(&pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0), + (void*)&pm->configcr, 0, 0, powermate_config_complete, pm); + + if(usb_submit_urb(&pm->config, GFP_KERNEL)) + printk(KERN_ERR "powermate: usb_submit_urb(config) failed"); +} + +/* Called when our asynchronous control message completes. We may need to issue another immediately */ +static void powermate_config_complete(struct urb *urb) +{ + struct powermate_device *pm = urb->context; + + if(urb->status) + printk(KERN_ERR "powermate: config urb returned %d\n", urb->status); + + down(&pm->lock); + powermate_sync_state(pm); + up(&pm->lock); +} + +/* Set the LED up as described and begin the sync with the hardware if required */ +static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, + int pulse_table, int pulse_asleep, int pulse_awake) +{ + if(pulse_speed < 0) + pulse_speed = 0; + if(pulse_table < 0) + pulse_table = 0; + if(pulse_speed > 510) + pulse_speed = 510; + if(pulse_table > 2) + pulse_table = 2; + + pulse_asleep = !!pulse_asleep; + pulse_awake = !!pulse_awake; + + down(&pm->lock); + + /* mark state updates which are required */ + if(static_brightness != pm->static_brightness){ + pm->static_brightness = static_brightness; + pm->requires_update |= UPDATE_STATIC_BRIGHTNESS; + } + if(pulse_asleep != pm->pulse_asleep){ + pm->pulse_asleep = pulse_asleep; + pm->requires_update |= UPDATE_PULSE_ASLEEP; + } + if(pulse_awake != pm->pulse_awake){ + pm->pulse_awake = pulse_awake; + pm->requires_update |= UPDATE_PULSE_AWAKE; + } + if(pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table){ + pm->pulse_speed = pulse_speed; + pm->pulse_table = pulse_table; + pm->requires_update |= UPDATE_PULSE_MODE; + } + + powermate_sync_state(pm); + + up(&pm->lock); +} + +/* Callback from the Input layer when an event arrives from userspace to configure the LED */ +static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value) +{ + unsigned int command = (unsigned int)_value; + struct powermate_device *pm = dev->private; + + if(type == EV_MSC && code == MSC_PULSELED){ + /* + bits 0- 7: 8 bits: LED brightness + bits 8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster. + bits 17-18: 2 bits: pulse table (0, 1, 2 valid) + bit 19: 1 bit : pulse whilst asleep? + bit 20: 1 bit : pulse constantly? + */ + int static_brightness = command & 0xFF; // bits 0-7 + int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16 + int pulse_table = (command >> 17) & 0x3; // bits 17-18 + int pulse_asleep = (command >> 19) & 0x1; // bit 19 + int pulse_awake = (command >> 20) & 0x1; // bit 20 + + powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake); + } + + return 0; +} + +/* Called whenever a USB device matching one in our supported devices table is connected */ +static void *powermate_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct powermate_device *pm; + int pipe, maxp; + char path[64]; + + interface = udev->config[0].interface[ifnum].altsetting + 0; + endpoint = interface->endpoint + 0; + if (!(endpoint->bEndpointAddress & 0x80)) return NULL; + if ((endpoint->bmAttributes & 3) != 3) return NULL; + + usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, interface->bInterfaceNumber, NULL, 0, + HZ * USB_CTRL_SET_TIMEOUT); + + if (!(pm = kmalloc(sizeof(struct powermate_device), GFP_KERNEL))) + return NULL; + + memset(pm, 0, sizeof(struct powermate_device)); + pm->udev = udev; + + init_MUTEX(&pm->lock); + + /* get a handle to the interrupt data pipe */ + pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + + if(maxp != POWERMATE_PAYLOAD_SIZE) + printk("powermate: Expected payload of %d bytes, found %d bytes!\n", POWERMATE_PAYLOAD_SIZE, maxp); + + FILL_INT_URB(&pm->irq, udev, pipe, pm->data, POWERMATE_PAYLOAD_SIZE, powermate_irq, pm, endpoint->bInterval); + + /* register our interrupt URB with the USB system */ + if(usb_submit_urb(&pm->irq, GFP_KERNEL)) { + kfree(pm); + return NULL; /* failure */ + } + + switch (udev->descriptor.idProduct) { + case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break; + case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break; + default: + pm->input.name = pm_name_soundknob; + printk(KERN_WARNING "powermate: unknown product id %04x\n", udev->descriptor.idProduct); + } + + pm->input.private = pm; + pm->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC); + pm->input.keybit[LONG(BTN_0)] = BIT(BTN_0); + pm->input.relbit[LONG(REL_DIAL)] = BIT(REL_DIAL); + pm->input.mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED); + pm->input.idbus = BUS_USB; + pm->input.idvendor = udev->descriptor.idVendor; + pm->input.idproduct = udev->descriptor.idProduct; + pm->input.idversion = udev->descriptor.bcdDevice; + pm->input.event = powermate_input_event; + + input_register_device(&pm->input); + + usb_make_path(udev, path, 64); + snprintf(pm->phys, 64, "%s/input0", path); + printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.phys); + + /* force an update of everything */ + pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS; + powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters + + return pm; +} + +/* Called when a USB device we've accepted ownership of is removed */ +static void powermate_disconnect(struct usb_device *dev, void *ptr) +{ + struct powermate_device *pm = ptr; + down(&pm->lock); + pm->requires_update = 0; + usb_unlink_urb(&pm->irq); + input_unregister_device(&pm->input); + + kfree(pm); +} + +static struct usb_device_id powermate_devices [] = { + { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_NEW) }, + { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_OLD) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, powermate_devices); + +static struct usb_driver powermate_driver = { + name: "powermate", + probe: powermate_probe, + disconnect: powermate_disconnect, + id_table: powermate_devices, +}; + +int powermate_init(void) +{ + if (usb_register(&powermate_driver) < 0) + return -1; + return 0; +} + +void powermate_cleanup(void) +{ + usb_deregister(&powermate_driver); +} + +module_init(powermate_init); +module_exit(powermate_cleanup); + +MODULE_AUTHOR( "William R Sowerbutts" ); +MODULE_DESCRIPTION( "Griffin Technology, Inc PowerMate driver" ); +MODULE_LICENSE("GPL"); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/pwc-if.c linux-2.5/drivers/usb/pwc-if.c --- linux-2.5.5/drivers/usb/pwc-if.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/usb/pwc-if.c Tue Feb 26 21:24:49 2002 @@ -179,28 +179,24 @@ /* Private functions */ /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); return ret; } -static void * rvmalloc(signed long size) +static void * rvmalloc(unsigned long size) { void * mem; - unsigned long adr, page; + unsigned long adr; - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - + size=PAGE_ALIGN(size); mem=vmalloc_32(size); if (mem) { @@ -208,8 +204,7 @@ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -217,20 +212,16 @@ return mem; } -static void rvfree(void * mem, signed long size) +static void rvfree(void * mem, unsigned long size) { - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + if (mem) { adr=(unsigned long) mem; - while (size > 0) + while ((long) size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/se401.c linux-2.5/drivers/usb/se401.c --- linux-2.5.5/drivers/usb/se401.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/usb/se401.c Tue Feb 26 21:24:49 2002 @@ -84,15 +84,14 @@ **********************************************************************/ /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); return ret; } @@ -100,12 +99,9 @@ static void *rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (!mem) return NULL; @@ -113,13 +109,9 @@ memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; @@ -127,23 +119,16 @@ static void rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - adr=(unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + adr = (unsigned long) mem; + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree(mem); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/Config.help linux-2.5/drivers/usb/serial/Config.help --- linux-2.5.5/drivers/usb/serial/Config.help Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/usb/serial/Config.help Fri Mar 1 15:07:38 2002 @@ -40,9 +40,10 @@ module, say M here and read . CONFIG_USB_SERIAL_IPAQ - Say Y here if you want to connect to your Compaq iPAQ running - Windows CE 3.0 using a USB autosync cable. For information on using - the driver, read . + Say Y here if you want to connect to your Compaq iPAQ or HP Jornada + 548/568 running Windows CE 3.0 or PocketPC 2002 using a USB + cradle/cable. For information on using the driver, + read . This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/Config.in linux-2.5/drivers/usb/serial/Config.in --- linux-2.5.5/drivers/usb/serial/Config.in Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/usb/serial/Config.in Fri Mar 1 15:07:38 2002 @@ -15,7 +15,7 @@ dep_tristate ' USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL -dep_tristate ' USB Compaq iPAQ Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL +dep_tristate ' USB Compaq iPAQ / HP Jornada Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL dep_tristate ' USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/belkin_sa.c linux-2.5/drivers/usb/serial/belkin_sa.c --- linux-2.5.5/drivers/usb/serial/belkin_sa.c Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/usb/serial/belkin_sa.c Fri Mar 1 15:07:38 2002 @@ -207,8 +207,6 @@ dbg(__FUNCTION__" port %d", port->number); - down (&port->sem); - ++port->open_count; if (port->open_count == 1) { @@ -230,8 +228,6 @@ } exit: - up (&port->sem); - return retval; } /* belkin_sa_open */ @@ -249,8 +245,6 @@ dbg(__FUNCTION__" port %d", port->number); - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -262,8 +256,6 @@ } port->open_count = 0; } - - up (&port->sem); } /* belkin_sa_close */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/cyberjack.c linux-2.5/drivers/usb/serial/cyberjack.c --- linux-2.5.5/drivers/usb/serial/cyberjack.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/usb/serial/cyberjack.c Fri Mar 1 15:07:38 2002 @@ -151,8 +151,6 @@ dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); - ++port->open_count; if (port->open_count == 1) { @@ -179,8 +177,6 @@ dbg(__FUNCTION__ " - usb_submit_urb(int urb)"); } - up (&port->sem); - return result; } @@ -188,8 +184,6 @@ { dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -201,8 +195,6 @@ } port->open_count = 0; } - - up (&port->sem); } static int cyberjack_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) @@ -225,8 +217,6 @@ return (0); } - down (&port->sem); - if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) { /* To much data for buffer. Reset buffer. */ priv->wrfilled=0; @@ -235,8 +225,9 @@ /* Copy data */ if (from_user) { - if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count)) + if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count)) { return -EFAULT; + } } else { memcpy (priv->wrbuf+priv->wrfilled, buf, count); } @@ -277,7 +268,6 @@ /* Throw away data. No better idea what to do with it. */ priv->wrfilled=0; priv->wrsent=0; - up (&port->sem); return 0; } @@ -292,7 +282,6 @@ } } - up (&port->sem); return (count); } @@ -432,8 +421,6 @@ return; } - down (&port->sem); - dbg(__FUNCTION__ " - transmitting data (frame n)"); length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ? @@ -459,7 +446,6 @@ /* Throw away data. No better idea what to do with it. */ priv->wrfilled=0; priv->wrsent=0; - up (&port->sem); queue_task(&port->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); return; @@ -477,7 +463,6 @@ priv->wrsent=0; } - up (&port->sem); queue_task(&port->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); return; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/empeg.c linux-2.5/drivers/usb/serial/empeg.c --- linux-2.5.5/drivers/usb/serial/empeg.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/usb/serial/empeg.c Fri Mar 1 15:07:38 2002 @@ -157,8 +157,6 @@ dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); - ++port->open_count; if (port->open_count == 1) { @@ -189,8 +187,6 @@ } - up (&port->sem); - return result; } @@ -208,8 +204,6 @@ if (!serial) return; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -220,8 +214,6 @@ port->open_count = 0; } - up (&port->sem); - /* Uncomment the following line if you want to see some statistics in your syslog */ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ } @@ -462,15 +454,7 @@ static void empeg_throttle (struct usb_serial_port *port) { dbg(__FUNCTION__ " - port %d", port->number); - - down (&port->sem); - usb_unlink_urb (port->read_urb); - - up (&port->sem); - - return; - } @@ -480,8 +464,6 @@ dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); - port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_KERNEL); @@ -489,10 +471,7 @@ if (result) err(__FUNCTION__ " - failed submitting read urb, error %d", result); - up (&port->sem); - return; - } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/ftdi_sio.c linux-2.5/drivers/usb/serial/ftdi_sio.c --- linux-2.5.5/drivers/usb/serial/ftdi_sio.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/usb/serial/ftdi_sio.c Fri Mar 1 15:07:38 2002 @@ -319,8 +319,6 @@ dbg(__FUNCTION__); - down (&port->sem); - ++port->open_count; if (port->open_count == 1){ @@ -361,7 +359,6 @@ err(__FUNCTION__ " - failed submitting read urb, error %d", result); } - up (&port->sem); return result; } /* ftdi_sio_open */ @@ -374,7 +371,6 @@ dbg( __FUNCTION__); - down (&port->sem); --port->open_count; if (port->open_count <= 0) { @@ -411,9 +407,6 @@ tty_hangup(port->tty); } } - - up (&port->sem); - } /* ftdi_sio_close */ @@ -447,8 +440,6 @@ return (0); } - down(&port->sem); - count += data_offset; count = (count > port->bulk_out_size) ? port->bulk_out_size : count; @@ -456,7 +447,6 @@ if (from_user) { if (copy_from_user(port->write_urb->transfer_buffer + data_offset, buf, count - data_offset )){ - up (&port->sem); return -EFAULT; } } else { @@ -482,14 +472,11 @@ result = usb_submit_urb(port->write_urb, GFP_KERNEL); if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); - up (&port->sem); return 0; } - up (&port->sem); dbg(__FUNCTION__ " write returning: %d", count - data_offset); return (count - data_offset); - } /* ftdi_sio_write */ static void ftdi_sio_write_bulk_callback (struct urb *urb) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/ipaq.c linux-2.5/drivers/usb/serial/ipaq.c --- linux-2.5.5/drivers/usb/serial/ipaq.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/usb/serial/ipaq.c Fri Mar 1 15:07:38 2002 @@ -1,7 +1,7 @@ /* * USB Compaq iPAQ driver * - * Copyright (C) 2001 + * Copyright (C) 2001 - 2002 * Ganesh Varadarajan * * This program is free software; you can redistribute it and/or modify @@ -9,6 +9,9 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * + * (25/2/2002) ganesh + * Added support for the HP Jornada 548 and 568. Completely untested. + * Thanks to info from Heath Robinson and Arieh Davidoff. */ #include @@ -39,9 +42,9 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.1" +#define DRIVER_VERSION "v0.2" #define DRIVER_AUTHOR "Ganesh Varadarajan " -#define DRIVER_DESC "USB Compaq iPAQ driver" +#define DRIVER_DESC "USB Compaq iPAQ, HP Jornada driver" /* Function prototypes for an ipaq */ static int ipaq_open (struct usb_serial_port *port, struct file *filp); @@ -61,7 +64,9 @@ static __devinitdata struct usb_device_id ipaq_id_table [] = { - { USB_DEVICE(IPAQ_VENDOR_ID, IPAQ_PRODUCT_ID) }, + { USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) }, { } /* Terminating entry */ }; @@ -72,7 +77,7 @@ owner: THIS_MODULE, name: "Compaq iPAQ", id_table: ipaq_id_table, - num_interrupt_in: 0, + num_interrupt_in: NUM_DONT_CARE, num_bulk_in: 1, num_bulk_out: 1, num_ports: 1, @@ -104,8 +109,6 @@ dbg(__FUNCTION__ " - port %d", port->number); - down(&port->sem); - ++port->open_count; if (port->open_count == 1) { @@ -193,8 +196,6 @@ } } - up(&port->sem); - return result; enomem: @@ -219,8 +220,6 @@ serial = get_usb_serial(port, __FUNCTION__); if (!serial) return; - - down (&port->sem); --port->open_count; @@ -238,8 +237,6 @@ port->open_count = 0; } - up (&port->sem); - /* Uncomment the following line if you want to see some statistics in your syslog */ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/ipaq.h linux-2.5/drivers/usb/serial/ipaq.h --- linux-2.5.5/drivers/usb/serial/ipaq.h Wed Feb 20 02:10:54 2002 +++ linux-2.5/drivers/usb/serial/ipaq.h Fri Mar 1 15:07:38 2002 @@ -1,7 +1,7 @@ /* * USB Compaq iPAQ driver * - * Copyright (C) 2001 + * Copyright (C) 2001 - 2002 * Ganesh Varadarajan * * This program is free software; you can redistribute it and/or modify @@ -16,8 +16,12 @@ #define __LINUX_USB_SERIAL_IPAQ_H -#define IPAQ_VENDOR_ID 0x049f -#define IPAQ_PRODUCT_ID 0x0003 +#define COMPAQ_VENDOR_ID 0x049f +#define COMPAQ_IPAQ_ID 0x0003 + +#define HP_VENDOR_ID 0x003f +#define HP_JORNADA_548_ID 0x1016 +#define HP_JORNADA_568_ID 0x1116 /* * Since we can't queue our bulk write urbs (don't know why - it just diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/ir-usb.c linux-2.5/drivers/usb/serial/ir-usb.c --- linux-2.5.5/drivers/usb/serial/ir-usb.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/usb/serial/ir-usb.c Fri Mar 1 15:07:38 2002 @@ -252,8 +252,6 @@ dbg("%s - port %d", __FUNCTION__, port->number); - down (&port->sem); - ++port->open_count; if (port->open_count == 1) { @@ -293,9 +291,6 @@ if (result) err("%s - failed submitting read urb, error %d", __FUNCTION__, result); } - - up (&port->sem); - return result; } @@ -312,8 +307,6 @@ if (!serial) return; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -324,7 +317,6 @@ port->open_count = 0; } - up (&port->sem); } static int ir_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/keyspan.c linux-2.5/drivers/usb/serial/keyspan.c --- linux-2.5.5/drivers/usb/serial/keyspan.c Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/usb/serial/keyspan.c Fri Mar 1 15:07:38 2002 @@ -861,10 +861,8 @@ dbg("keyspan_open called for port%d.\n", port->number); - down (&port->sem); already_active = port->open_count; ++port->open_count; - up (&port->sem); if (already_active) return 0; @@ -926,8 +924,6 @@ p_priv->out_flip = 0; p_priv->in_flip = 0; - down (&port->sem); - if (--port->open_count <= 0) { if (serial->dev) { /* Stop reading/writing urbs */ @@ -941,7 +937,6 @@ port->open_count = 0; port->tty = 0; } - up (&port->sem); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/keyspan_pda.c linux-2.5/drivers/usb/serial/keyspan_pda.c --- linux-2.5.5/drivers/usb/serial/keyspan_pda.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/usb/serial/keyspan_pda.c Fri Mar 1 15:07:38 2002 @@ -662,8 +662,6 @@ int rc = 0; struct keyspan_pda_private *priv; - down (&port->sem); - ++port->open_count; if (port->open_count == 1) { @@ -707,12 +705,9 @@ } - - up (&port->sem); return rc; error: --port->open_count; - up (&port->sem); return rc; } @@ -721,8 +716,6 @@ { struct usb_serial *serial = port->serial; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -737,8 +730,6 @@ } port->open_count = 0; } - - up (&port->sem); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/kl5kusb105.c linux-2.5/drivers/usb/serial/kl5kusb105.c --- linux-2.5.5/drivers/usb/serial/kl5kusb105.c Wed Feb 20 02:10:53 2002 +++ linux-2.5/drivers/usb/serial/kl5kusb105.c Fri Mar 1 15:07:38 2002 @@ -358,8 +358,6 @@ dbg(__FUNCTION__" port %d", port->number); - down (&port->sem); - ++port->open_count; if (port->open_count == 1) { @@ -437,8 +435,6 @@ } exit: - up (&port->sem); - return retval; } /* klsi_105_open */ @@ -455,8 +451,6 @@ if(!serial) return; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -482,8 +476,6 @@ port->open_count = 0; info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out); } - - up (&port->sem); } /* klsi_105_close */ @@ -505,9 +497,6 @@ dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); /* to lock against someone else trying to - take an URB we just selected from the pool */ - while (count > 0) { /* try to find a free urb (write 0 bytes if none) */ struct urb *urb = NULL; @@ -543,7 +532,6 @@ if (from_user) { if (copy_from_user(urb->transfer_buffer + KLSI_105_DATA_OFFSET, buf, size)) { - up (&port->sem); return -EFAULT; } } else { @@ -578,7 +566,6 @@ count -= size; } exit: - up (&port->sem); priv->bytes_out+=bytes_sent; return bytes_sent; /* that's how much we wrote */ @@ -1021,34 +1008,21 @@ static void klsi_105_throttle (struct usb_serial_port *port) { - dbg(__FUNCTION__ " - port %d", port->number); - - down (&port->sem); - usb_unlink_urb (port->read_urb); - - up (&port->sem); - - return; } + static void klsi_105_unthrottle (struct usb_serial_port *port) { int result; dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); - port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) err(__FUNCTION__ " - failed submitting read urb, error %d", result); - - up (&port->sem); - - return; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/mct_u232.c linux-2.5/drivers/usb/serial/mct_u232.c --- linux-2.5.5/drivers/usb/serial/mct_u232.c Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/usb/serial/mct_u232.c Fri Mar 1 15:07:38 2002 @@ -341,8 +341,6 @@ dbg(__FUNCTION__" port %d", port->number); - down (&port->sem); - ++port->open_count; if (port->open_count == 1) { @@ -398,8 +396,6 @@ } exit: - up (&port->sem); - return 0; } /* mct_u232_open */ @@ -408,8 +404,6 @@ { dbg(__FUNCTION__" port %d", port->number); - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -421,8 +415,6 @@ } port->open_count = 0; } - - up (&port->sem); } /* mct_u232_close */ @@ -454,16 +446,12 @@ bytes_sent = 0; while (count > 0) { - - down (&port->sem); - size = (count > port->bulk_out_size) ? port->bulk_out_size : count; usb_serial_debug_data (__FILE__, __FUNCTION__, size, buf); if (from_user) { if (copy_from_user(port->write_urb->transfer_buffer, buf, size)) { - up (&port->sem); return -EFAULT; } } @@ -486,11 +474,8 @@ if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); - up (&port->sem); return result; } - - up (&port->sem); bytes_sent += size; if (write_blocking) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/omninet.c linux-2.5/drivers/usb/serial/omninet.c --- linux-2.5.5/drivers/usb/serial/omninet.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/usb/serial/omninet.c Fri Mar 1 15:07:38 2002 @@ -157,8 +157,6 @@ if (!serial) return -ENODEV; - down (&port->sem); - ++port->open_count; if (port->open_count == 1) { @@ -166,7 +164,6 @@ if( !od ) { err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct omninet_data)); port->open_count = 0; - up (&port->sem); return -ENOMEM; } @@ -184,8 +181,6 @@ err(__FUNCTION__ " - failed submitting read urb, error %d", result); } - up (&port->sem); - return result; } @@ -204,8 +199,6 @@ if (!serial) return; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -220,8 +213,6 @@ if (od) kfree(od); } - - up (&port->sem); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/pl2303.c linux-2.5/drivers/usb/serial/pl2303.c --- linux-2.5.5/drivers/usb/serial/pl2303.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/usb/serial/pl2303.c Fri Mar 1 15:07:38 2002 @@ -367,8 +367,6 @@ dbg (__FUNCTION__ " - port %d", port->number); - down (&port->sem); - ++port->open_count; if (port->open_count == 1) { @@ -407,7 +405,6 @@ result = usb_submit_urb (port->read_urb, GFP_KERNEL); if (result) { err(__FUNCTION__ " - failed submitting read urb, error %d", result); - up (&port->sem); pl2303_close (port, NULL); return -EPROTO; } @@ -417,12 +414,10 @@ result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL); if (result) { err(__FUNCTION__ " - failed submitting interrupt urb, error %d", result); - up (&port->sem); pl2303_close (port, NULL); return -EPROTO; } } - up (&port->sem); return 0; } @@ -442,8 +437,6 @@ dbg (__FUNCTION__ " - port %d", port->number); - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { if (serial->dev) { @@ -478,8 +471,6 @@ } port->open_count = 0; } - - up (&port->sem); } static int set_modem_info (struct usb_serial_port *port, unsigned int cmd, unsigned int *value) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/usbserial.c linux-2.5/drivers/usb/serial/usbserial.c --- linux-2.5.5/drivers/usb/serial/usbserial.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/usb/serial/usbserial.c Fri Mar 1 15:07:38 2002 @@ -1,7 +1,7 @@ /* * USB Serial Converter driver * - * Copyright (C) 1999 - 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2000 Peter Berger (pberger@brimson.com) * Copyright (c) 2000 Al Borchers (borchers@steinerpoint.com) * @@ -15,6 +15,13 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (02/26/2002) gkh + * Moved all locking into the main serial_* functions, instead of having + * the individual drivers have to grab the port semaphore. This should + * reduce races. + * Reworked the MOD_INC logic a bit to always increment and decrement, even + * if the generic driver is being used. + * * (10/10/2001) gkh * usb_serial_disconnect() now sets the serial->dev pointer is to NULL to * help prevent child drivers from accessing the device since it is now @@ -337,6 +344,7 @@ /* All of the device info needed for the Generic Serial Converter */ static struct usb_serial_device_type generic_device = { + owner: THIS_MODULE, name: "Generic", id_table: generic_device_ids, num_interrupt_in: NUM_DONT_CARE, @@ -345,13 +353,6 @@ num_ports: 1, shutdown: generic_shutdown, }; - -#define if_generic_do(x) \ - if ((serial->vendor == vendor) && \ - (serial->product == product)) \ - x -#else -#define if_generic_do(x) #endif @@ -384,7 +385,7 @@ via modprobe, and modprobe will load usbserial because the serial drivers depend on it. */ - + static int serial_refcount; static struct tty_driver serial_tty_driver; @@ -392,8 +393,6 @@ static struct termios * serial_termios[SERIAL_TTY_MINORS]; static struct termios * serial_termios_locked[SERIAL_TTY_MINORS]; static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ - - static LIST_HEAD(usb_serial_driver_list); @@ -402,7 +401,6 @@ return serial_table[minor]; } - static struct usb_serial *get_free_serial (int num_ports, unsigned int *minor) { struct usb_serial *serial = NULL; @@ -439,7 +437,6 @@ return NULL; } - static void return_serial (struct usb_serial *serial) { int i; @@ -456,7 +453,6 @@ return; } - #ifdef USES_EZUSB_FUNCTIONS /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ #define CPUCS_REG 0x7F92 @@ -483,7 +479,6 @@ return result; } - int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit) { int response; @@ -497,7 +492,6 @@ #endif /* USES_EZUSB_FUNCTIONS */ - /***************************************************************************** * Driver tty interface functions *****************************************************************************/ @@ -516,266 +510,293 @@ /* get the serial object associated with this tty pointer */ serial = get_serial_by_minor (minor(tty->device)); - if (serial_paranoia_check (serial, __FUNCTION__)) { + if (serial_paranoia_check (serial, __FUNCTION__)) return -ENODEV; - } /* set up our port structure making the tty driver remember our port object, and us it */ portNumber = minor(tty->device) - serial->minor; port = &serial->port[portNumber]; tty->driver_data = port; + + down (&port->sem); port->tty = tty; + /* lock this module before we call it */ + if (serial->type->owner) + __MOD_INC_USE_COUNT(serial->type->owner); + /* pass on to the driver specific version of this function if it is available */ - if (serial->type->open) { - if (serial->type->owner) - __MOD_INC_USE_COUNT(serial->type->owner); + if (serial->type->open) retval = serial->type->open(port, filp); - if (retval) - __MOD_DEC_USE_COUNT(serial->type->owner); - } else { + else retval = generic_open(port, filp); - } + if (retval) + __MOD_DEC_USE_COUNT(serial->type->owner); + + up (&port->sem); return retval; } - static void serial_close(struct tty_struct *tty, struct file * filp) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - if (!serial) { + if (!serial) return; - } + + down (&port->sem); dbg(__FUNCTION__ " - port %d", port->number); - + + if (tty->driver_data == NULL) { + /* disconnect beat us to the punch here, so handle it gracefully */ + goto exit; + } if (!port->open_count) { dbg (__FUNCTION__ " - port not opened"); - return; + goto exit_no_mod_dec; } /* pass on to the driver specific version of this function if it is available */ - if (serial->type->close) { + if (serial->type->close) serial->type->close(port, filp); - if (serial->type->owner) - __MOD_DEC_USE_COUNT(serial->type->owner); - } else { + else generic_close(port, filp); - } -} +exit: + if (serial->type->owner) + __MOD_DEC_USE_COUNT(serial->type->owner); + +exit_no_mod_dec: + up (&port->sem); +} static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - - if (!serial) { + int retval = -EINVAL; + + if (!serial) return -ENODEV; - } - + + down (&port->sem); + dbg(__FUNCTION__ " - port %d, %d byte(s)", port->number, count); if (!port->open_count) { dbg (__FUNCTION__ " - port not opened"); - return -EINVAL; + goto exit; } - + /* pass on to the driver specific version of this function if it is available */ - if (serial->type->write) { - return (serial->type->write(port, from_user, buf, count)); - } else { - return (generic_write(port, from_user, buf, count)); - } -} + if (serial->type->write) + retval = serial->type->write(port, from_user, buf, count); + else + retval = generic_write(port, from_user, buf, count); +exit: + up (&port->sem); + return retval; +} static int serial_write_room (struct tty_struct *tty) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); + int retval = -EINVAL; - if (!serial) { + if (!serial) return -ENODEV; - } + + down (&port->sem); dbg(__FUNCTION__ " - port %d", port->number); - + if (!port->open_count) { dbg (__FUNCTION__ " - port not open"); - return -EINVAL; + goto exit; } /* pass on to the driver specific version of this function if it is available */ - if (serial->type->write_room) { - return (serial->type->write_room(port)); - } else { - return (generic_write_room(port)); - } -} + if (serial->type->write_room) + retval = serial->type->write_room(port); + else + retval = generic_write_room(port); +exit: + up (&port->sem); + return retval; +} static int serial_chars_in_buffer (struct tty_struct *tty) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); + int retval = -EINVAL; - if (!serial) { + if (!serial) return -ENODEV; - } + + down (&port->sem); + + dbg(__FUNCTION__ " - port %d", port->number); if (!port->open_count) { dbg (__FUNCTION__ " - port not open"); - return -EINVAL; + goto exit; } /* pass on to the driver specific version of this function if it is available */ - if (serial->type->chars_in_buffer) { - return (serial->type->chars_in_buffer(port)); - } else { - return (generic_chars_in_buffer(port)); - } -} + if (serial->type->chars_in_buffer) + retval = serial->type->chars_in_buffer(port); + else + retval = generic_chars_in_buffer(port); +exit: + up (&port->sem); + return retval; +} static void serial_throttle (struct tty_struct * tty) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - if (!serial) { + if (!serial) return; - } + + down (&port->sem); dbg(__FUNCTION__ " - port %d", port->number); if (!port->open_count) { dbg (__FUNCTION__ " - port not open"); - return; + goto exit; } /* pass on to the driver specific version of this function */ - if (serial->type->throttle) { + if (serial->type->throttle) serial->type->throttle(port); - } - return; +exit: + up (&port->sem); } - static void serial_unthrottle (struct tty_struct * tty) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - if (!serial) { + if (!serial) return; - } + + down (&port->sem); dbg(__FUNCTION__ " - port %d", port->number); if (!port->open_count) { dbg (__FUNCTION__ " - port not open"); - return; + goto exit; } /* pass on to the driver specific version of this function */ - if (serial->type->unthrottle) { + if (serial->type->unthrottle) serial->type->unthrottle(port); - } - return; +exit: + up (&port->sem); } - static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); + int retval = -ENODEV; - if (!serial) { + if (!serial) return -ENODEV; - } + + down (&port->sem); dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd); if (!port->open_count) { dbg (__FUNCTION__ " - port not open"); - return -ENODEV; + goto exit; } /* pass on to the driver specific version of this function if it is available */ - if (serial->type->ioctl) { - return (serial->type->ioctl(port, file, cmd, arg)); - } else { - return -ENOIOCTLCMD; - } -} + if (serial->type->ioctl) + retval = serial->type->ioctl(port, file, cmd, arg); + else + retval = -ENOIOCTLCMD; +exit: + up (&port->sem); + return retval; +} static void serial_set_termios (struct tty_struct *tty, struct termios * old) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - if (!serial) { + if (!serial) return; - } + + down (&port->sem); dbg(__FUNCTION__ " - port %d", port->number); if (!port->open_count) { dbg (__FUNCTION__ " - port not open"); - return; + goto exit; } /* pass on to the driver specific version of this function if it is available */ - if (serial->type->set_termios) { + if (serial->type->set_termios) serial->type->set_termios(port, old); - } - - return; -} +exit: + up (&port->sem); +} static void serial_break (struct tty_struct *tty, int break_state) { struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - if (!serial) { + if (!serial) return; - } + + down (&port->sem); dbg(__FUNCTION__ " - port %d", port->number); if (!port->open_count) { dbg (__FUNCTION__ " - port not open"); - return; + goto exit; } - /* pass on to the driver specific version of this function if it is - available */ - if (serial->type->break_ctl) { + /* pass on to the driver specific version of this function if it is available */ + if (serial->type->break_ctl) serial->type->break_ctl(port, break_state); - } -} +exit: + up (&port->sem); +} static void serial_shutdown (struct usb_serial *serial) { - if (serial->type->shutdown) { + if (serial->type->shutdown) serial->type->shutdown(serial); - } else { + else generic_shutdown(serial); - } } - - /***************************************************************************** * generic devices specific driver functions *****************************************************************************/ @@ -787,21 +808,16 @@ if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; - /* only increment our usage count, if this device is _really_ a generic device */ - if_generic_do(MOD_INC_USE_COUNT); - dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); - ++port->open_count; - + if (port->open_count == 1) { /* force low_latency on so that our tty_push actually forces the data through, otherwise it is scheduled, and with high data rates (like with OHCI) data can get lost. */ port->tty->low_latency = 1; - + /* if we have a bulk interrupt, start reading from it */ if (serial->num_bulk_in) { /* Start reading from the device */ @@ -818,21 +834,16 @@ err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); } } - - up (&port->sem); - + return result; } - static void generic_close (struct usb_serial_port *port, struct file * filp) { struct usb_serial *serial = port->serial; dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -845,14 +856,8 @@ } port->open_count = 0; } - - up (&port->sem); - - /* only decrement our usage count, if this device is _really_ a generic device */ - if_generic_do(MOD_DEC_USE_COUNT); } - static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) { struct usb_serial *serial = port->serial; @@ -880,14 +885,14 @@ } else { memcpy (port->write_urb->transfer_buffer, buf, count); - } + } usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer); /* set up our urb */ usb_fill_bulk_urb (port->write_urb, serial->dev, usb_sndbulkpipe (serial->dev, - port->bulk_out_endpointAddress), + port->bulk_out_endpointAddress), port->write_urb->transfer_buffer, count, ((serial->type->write_bulk_callback) ? serial->type->write_bulk_callback : @@ -902,11 +907,10 @@ return result; } - + /* no bulk out, so return 0 bytes written */ return (0); -} - +} static int generic_write_room (struct usb_serial_port *port) { @@ -919,19 +923,18 @@ if (port->write_urb->status != -EINPROGRESS) room = port->bulk_out_size; } - + dbg(__FUNCTION__ " - returns %d", room); return (room); } - static int generic_chars_in_buffer (struct usb_serial_port *port) { struct usb_serial *serial = port->serial; int chars = 0; dbg(__FUNCTION__ " - port %d", port->number); - + if (serial->num_bulk_out) { if (port->write_urb->status == -EINPROGRESS) chars = port->write_urb->transfer_buffer_length; @@ -941,7 +944,6 @@ return (chars); } - static void generic_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; @@ -952,7 +954,7 @@ int result; dbg(__FUNCTION__ " - port %d", port->number); - + if (!serial) { dbg(__FUNCTION__ " - bad serial pointer, exiting"); return; @@ -992,14 +994,13 @@ err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); } - static void generic_write_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); dbg(__FUNCTION__ " - port %d", port->number); - + if (!serial) { dbg(__FUNCTION__ " - bad serial pointer, exiting"); return; @@ -1012,11 +1013,10 @@ queue_task(&port->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); - + return; } - static void generic_shutdown (struct usb_serial *serial) { int i; @@ -1025,13 +1025,13 @@ /* stop reads and writes on all ports */ for (i=0; i < serial->num_ports; ++i) { - while (serial->port[i].open_count > 0) { + down (&serial->port[i].sem); + while (serial->port[i].open_count > 0) generic_close (&serial->port[i], NULL); - } + up (&serial->port[i].sem); } } - static void port_softint(void *private) { struct usb_serial_port *port = (struct usb_serial_port *)private; @@ -1043,7 +1043,7 @@ if (!serial) { return; } - + tty = port->tty; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { dbg(__FUNCTION__ " - write wakeup call."); @@ -1053,8 +1053,6 @@ wake_up_interruptible(&tty->write_wait); } - - static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) { @@ -1080,7 +1078,6 @@ int max_endpoints; const struct usb_device_id *id_pattern = NULL; - /* loop through our list of known serial converters, and see if this device matches. */ found = 0; @@ -1130,7 +1127,7 @@ ++num_interrupt_in; } } - + #if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE) /* BEGIN HORRIBLE HACK FOR PL2303 */ /* this is needed due to the looney way its endpoints are set up */ @@ -1156,7 +1153,7 @@ } /* END HORRIBLE HACK FOR PL2303 */ #endif - + /* found all that we need */ info("%s converter detected", type->name); @@ -1176,7 +1173,7 @@ err("No more free serial devices"); return NULL; } - + serial->dev = dev; serial->type = type; serial->interface = interface; @@ -1289,14 +1286,14 @@ port->tqueue.data = port; init_MUTEX (&port->sem); } - + /* initialize the devfs nodes for this device and let the user know what ports we are bound to */ for (i = 0; i < serial->num_ports; ++i) { tty_register_devfs (&serial_tty_driver, 0, serial->port[i].number); info("%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)", type->name, serial->port[i].number, serial->port[i].number); } - + return serial; /* success */ @@ -1322,7 +1319,7 @@ if (port->interrupt_in_buffer) kfree (port->interrupt_in_buffer); } - + /* return the minor range that this device had */ return_serial (serial); @@ -1331,7 +1328,6 @@ return NULL; } - static void usb_serial_disconnect(struct usb_device *dev, void *ptr) { struct usb_serial *serial = (struct usb_serial *) ptr; @@ -1341,8 +1337,10 @@ if (serial) { /* fail all future close/read/write/ioctl/etc calls */ for (i = 0; i < serial->num_ports; ++i) { + down (&serial->port[i].sem); if (serial->port[i].tty != NULL) serial->port[i].tty->driver_data = NULL; + up (&serial->port[i].sem); } serial->dev = NULL; @@ -1393,7 +1391,7 @@ } else { info("device disconnected"); } - + } @@ -1407,12 +1405,12 @@ type: TTY_DRIVER_TYPE_SERIAL, subtype: SERIAL_TYPE_NORMAL, flags: TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS, - + refcount: &serial_refcount, table: serial_tty, termios: serial_termios, termios_locked: serial_termios_locked, - + open: serial_open, close: serial_close, write: serial_write, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/visor.c linux-2.5/drivers/usb/serial/visor.c --- linux-2.5.5/drivers/usb/serial/visor.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/usb/serial/visor.c Fri Mar 1 15:07:38 2002 @@ -12,6 +12,15 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (02/27/2002) gkh + * Reworked the urb handling logic. We have no more pool, but dynamically + * allocate the urb and the transfer buffer on the fly. In testing this + * does not incure any measurable overhead. This also relies on the fact + * that we have proper reference counting logic for urbs. + * + * (02/21/2002) SilaS + * Added initial support for the Palm m515 devices. + * * (02/14/2002) gkh * Added support for the Clie S-360 device. * @@ -134,7 +143,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.9" +#define DRIVER_VERSION "v2.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman " #define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony Clié driver" @@ -158,6 +167,7 @@ static __devinitdata struct usb_device_id combined_id_table [] = { { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) }, { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, @@ -174,6 +184,7 @@ { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, @@ -233,12 +244,8 @@ }; -#define NUM_URBS 24 -#define URB_TRANSFER_BUFFER_SIZE 768 -static struct urb *write_urb_pool[NUM_URBS]; -static spinlock_t write_urb_pool_lock; -static int bytes_in; -static int bytes_out; +static int bytes_in; +static int bytes_out; /****************************************************************************** @@ -259,8 +266,6 @@ return -ENODEV; } - down (&port->sem); - ++port->open_count; if (port->open_count == 1) { @@ -284,8 +289,6 @@ err(__FUNCTION__ " - failed submitting read urb, error %d", result); } - up (&port->sem); - return result; } @@ -304,8 +307,6 @@ if (!serial) return; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -329,8 +330,6 @@ } port->open_count = 0; } - up (&port->sem); - /* Uncomment the following line if you want to see some statistics in your syslog */ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ } @@ -340,120 +339,84 @@ { struct usb_serial *serial = port->serial; struct urb *urb; - const unsigned char *current_position = buf; - unsigned long flags; + unsigned char *buffer; int status; - int i; - int bytes_sent = 0; - int transfer_size; dbg(__FUNCTION__ " - port %d", port->number); - while (count > 0) { - /* try to find a free urb in our list of them */ - urb = NULL; - spin_lock_irqsave (&write_urb_pool_lock, flags); - for (i = 0; i < NUM_URBS; ++i) { - if (write_urb_pool[i]->status != -EINPROGRESS) { - urb = write_urb_pool[i]; - break; - } - } - spin_unlock_irqrestore (&write_urb_pool_lock, flags); - if (urb == NULL) { - dbg (__FUNCTION__ " - no more free urbs"); - goto exit; - } - if (urb->transfer_buffer == NULL) { - urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); - if (urb->transfer_buffer == NULL) { - err(__FUNCTION__" no more kernel memory..."); - goto exit; - } - } - - transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE); - if (from_user) { - if (copy_from_user (urb->transfer_buffer, current_position, transfer_size)) { - bytes_sent = -EFAULT; - break; - } - } else { - memcpy (urb->transfer_buffer, current_position, transfer_size); - } + buffer = kmalloc (count, GFP_KERNEL); + if (!buffer) { + err ("out of memory"); + return -ENOMEM; + } - usb_serial_debug_data (__FILE__, __FUNCTION__, transfer_size, urb->transfer_buffer); + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + err ("no more free urbs"); + kfree (buffer); + return -ENOMEM; + } - /* build up our urb */ - usb_fill_bulk_urb (urb, serial->dev, - usb_sndbulkpipe (serial->dev, - port->bulk_out_endpointAddress), - urb->transfer_buffer, transfer_size, - visor_write_bulk_callback, port); - urb->transfer_flags |= USB_QUEUE_BULK; - - /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_KERNEL); - if (status) { - err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); - bytes_sent = status; - break; + if (from_user) { + if (copy_from_user (buffer, buf, count)) { + kfree (buffer); + usb_free_urb (urb); + return -EFAULT; } + } else { + memcpy (buffer, buf, count); + } + + usb_serial_debug_data (__FILE__, __FUNCTION__, count, buffer); - current_position += transfer_size; - bytes_sent += transfer_size; - count -= transfer_size; - bytes_out += transfer_size; + usb_fill_bulk_urb (urb, serial->dev, + usb_sndbulkpipe (serial->dev, + port->bulk_out_endpointAddress), + buffer, count, + visor_write_bulk_callback, port); + urb->transfer_flags |= USB_QUEUE_BULK; + + /* send it down the pipe */ + status = usb_submit_urb(urb, GFP_KERNEL); + if (status) { + err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); + count = status; + } else { + bytes_out += count; } -exit: - return bytes_sent; + /* we are done with this urb, so let the host driver + * really free it when it is finished with it */ + usb_free_urb (urb); + + return count; } static int visor_write_room (struct usb_serial_port *port) { - unsigned long flags; - int i; - int room = 0; - dbg(__FUNCTION__ " - port %d", port->number); - - spin_lock_irqsave (&write_urb_pool_lock, flags); - for (i = 0; i < NUM_URBS; ++i) { - if (write_urb_pool[i]->status != -EINPROGRESS) { - room += URB_TRANSFER_BUFFER_SIZE; - } - } - - spin_unlock_irqrestore (&write_urb_pool_lock, flags); - - dbg(__FUNCTION__ " - returns %d", room); - return (room); + /* + * We really can take anything the user throws at us + * but let's pick a nice big number to tell the tty + * layer that we have lots of free space + */ + return 2048; } static int visor_chars_in_buffer (struct usb_serial_port *port) { - unsigned long flags; - int i; - int chars = 0; - dbg(__FUNCTION__ " - port %d", port->number); - - spin_lock_irqsave (&write_urb_pool_lock, flags); - - for (i = 0; i < NUM_URBS; ++i) { - if (write_urb_pool[i]->status == -EINPROGRESS) { - chars += URB_TRANSFER_BUFFER_SIZE; - } - } - - spin_unlock_irqrestore (&write_urb_pool_lock, flags); - dbg (__FUNCTION__ " - returns %d", chars); - return (chars); + /* + * We can't really account for how much data we + * have sent out, but hasn't made it through to the + * device, so just tell the tty layer that everything + * is flushed. + */ + return 0; } @@ -471,9 +434,12 @@ return; } + /* free up the transfer buffer, as usb_free_urb() does not do this */ + kfree (urb->transfer_buffer); + queue_task(&port->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); - + return; } @@ -534,16 +500,8 @@ static void visor_throttle (struct usb_serial_port *port) { - dbg(__FUNCTION__ " - port %d", port->number); - - down (&port->sem); - usb_unlink_urb (port->read_urb); - - up (&port->sem); - - return; } @@ -553,16 +511,10 @@ dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); - port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) err(__FUNCTION__ " - failed submitting read urb, error %d", result); - - up (&port->sem); - - return; } @@ -783,30 +735,8 @@ static int __init visor_init (void) { - struct urb *urb; - int i; - usb_serial_register (&handspring_device); usb_serial_register (&clie_3_5_device); - - /* create our write urb pool and transfer buffers */ - spin_lock_init (&write_urb_pool_lock); - for (i = 0; i < NUM_URBS; ++i) { - urb = usb_alloc_urb(0, GFP_KERNEL); - write_urb_pool[i] = urb; - if (urb == NULL) { - err("No more urbs???"); - continue; - } - - urb->transfer_buffer = NULL; - urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); - if (!urb->transfer_buffer) { - err (__FUNCTION__ " - out of memory for urb buffers."); - continue; - } - } - info(DRIVER_DESC " " DRIVER_VERSION); return 0; @@ -815,27 +745,8 @@ static void __exit visor_exit (void) { - int i; - unsigned long flags; - usb_serial_deregister (&handspring_device); usb_serial_deregister (&clie_3_5_device); - - spin_lock_irqsave (&write_urb_pool_lock, flags); - - for (i = 0; i < NUM_URBS; ++i) { - if (write_urb_pool[i]) { - /* FIXME - uncomment the following usb_unlink_urb call when - * the host controllers get fixed to set urb->dev = NULL after - * the urb is finished. Otherwise this call oopses. */ - /* usb_unlink_urb(write_urb_pool[i]); */ - if (write_urb_pool[i]->transfer_buffer) - kfree(write_urb_pool[i]->transfer_buffer); - usb_free_urb (write_urb_pool[i]); - } - } - - spin_unlock_irqrestore (&write_urb_pool_lock, flags); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/visor.h linux-2.5/drivers/usb/serial/visor.h --- linux-2.5.5/drivers/usb/serial/visor.h Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/usb/serial/visor.h Fri Mar 1 15:07:38 2002 @@ -23,6 +23,7 @@ #define PALM_VENDOR_ID 0x0830 #define PALM_M500_ID 0x0001 #define PALM_M505_ID 0x0002 +#define PALM_M515_ID 0x0003 #define PALM_M125_ID 0x0040 #define SONY_VENDOR_ID 0x054C diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/serial/whiteheat.c linux-2.5/drivers/usb/serial/whiteheat.c --- linux-2.5.5/drivers/usb/serial/whiteheat.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/usb/serial/whiteheat.c Fri Mar 1 15:07:38 2002 @@ -306,8 +306,6 @@ dbg(__FUNCTION__" - port %d", port->number); - down (&port->sem); - ++port->open_count; if (port->open_count == 1) { @@ -354,16 +352,12 @@ } dbg(__FUNCTION__ " - exit"); - up (&port->sem); - return retval; error_exit: --port->open_count; dbg(__FUNCTION__ " - error_exit"); - up (&port->sem); - return retval; } @@ -374,7 +368,6 @@ dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); --port->open_count; if (port->open_count <= 0) { @@ -391,7 +384,6 @@ usb_unlink_urb (port->read_urb); port->open_count = 0; } - up (&port->sem); } @@ -410,8 +402,6 @@ dbg(__FUNCTION__ " -port %d", port->number); - down (&port->sem); - if ((!port->tty) || (!port->tty->termios)) { dbg(__FUNCTION__" - no tty structures"); goto exit; @@ -492,7 +482,6 @@ whiteheat_send_cmd (port->serial, WHITEHEAT_SETUP_PORT, (__u8 *)&port_settings, sizeof(port_settings)); exit: - up (&port->sem); return; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/storage/Makefile linux-2.5/drivers/usb/storage/Makefile --- linux-2.5.5/drivers/usb/storage/Makefile Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/usb/storage/Makefile Mon Feb 4 22:15:17 2002 @@ -1,7 +1,7 @@ # # Makefile for the USB Mass Storage device drivers. # -# 15 Aug 2000, Christoph Hellwig +# 15 Aug 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/storage/isd200.c linux-2.5/drivers/usb/storage/isd200.c --- linux-2.5.5/drivers/usb/storage/isd200.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/usb/storage/isd200.c Sun Mar 3 17:54:36 2002 @@ -821,7 +821,7 @@ * Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to - * the device and recieve the response. + * the device and receive the response. */ void isd200_invoke_transport( struct us_data *us, Scsi_Cmnd *srb, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/storage/transport.c linux-2.5/drivers/usb/storage/transport.c --- linux-2.5.5/drivers/usb/storage/transport.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/usb/storage/transport.c Sun Mar 3 17:54:36 2002 @@ -612,7 +612,7 @@ /* Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to - * the device and recieve the response. + * the device and receive the response. */ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) { @@ -798,7 +798,7 @@ { struct us_data *us = (struct us_data *)urb->context; - US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no); + US_DEBUGP("USB IRQ received for device on host %d\n", us->host_no); US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length); US_DEBUGP("-- IRQ state is %d\n", urb->status); US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n", @@ -1157,7 +1157,7 @@ le32_to_cpu(bcs.Signature), bcs.Tag, bcs.Residue, bcs.Status); if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || - bcs.Tag != bcb.Tag || + ((bcs.Tag != bcb.Tag ) && (!(us->flags & US_FL_SL_IDE_BUG))) || bcs.Status > US_BULK_STAT_PHASE || partial != 13) { US_DEBUGP("Bulk logical error\n"); return USB_STOR_TRANSPORT_ERROR; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/storage/unusual_devs.h linux-2.5/drivers/usb/storage/unusual_devs.h --- linux-2.5.5/drivers/usb/storage/unusual_devs.h Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/usb/storage/unusual_devs.h Tue Feb 26 16:32:30 2002 @@ -110,6 +110,28 @@ "LS-120 Camera", US_SC_UFI, US_PR_CBI, NULL, 0), +/* Reported by Peter Wächtler */ +UNUSUAL_DEV( 0x04ce, 0x0002, 0x0074, 0x0074, + "ScanLogic", + "SL11R-IDE 0049SQFP-1.2 A002", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY ), + +/* Reported by Leif Sawyer */ +UNUSUAL_DEV( 0x04ce, 0x0002, 0x0240, 0x0240, + "H45 ScanLogic", + "SL11R-IDE 9951SQFP-1.2 K004", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY | US_FL_SL_IDE_BUG ), + +/* Reported by Rene Engelhard and + Dylan Egan */ +UNUSUAL_DEV( 0x04ce, 0x0002, 0x0260, 0x0260, + "ScanLogic", + "SL11R-IDE unknown HW rev", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_SL_IDE_BUG ), + /* Most of the following entries were developed with the help of * Shuttle/SCM directly. */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/storage/usb.h linux-2.5/drivers/usb/storage/usb.h --- linux-2.5.5/drivers/usb/storage/usb.h Wed Feb 20 02:11:04 2002 +++ linux-2.5/drivers/usb/storage/usb.h Tue Feb 26 16:32:26 2002 @@ -101,6 +101,7 @@ #define US_FL_IGNORE_SER 0x00000010 /* Ignore the serial number given */ #define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ #define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ +#define US_FL_SL_IDE_BUG 0x00000100 /* ScanLogic usb-ide workaround */ #define USB_STOR_STRING_LEN 32 diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/stv680.c linux-2.5/drivers/usb/stv680.c --- linux-2.5.5/drivers/usb/stv680.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/usb/stv680.c Tue Feb 26 21:24:49 2002 @@ -127,54 +127,25 @@ * And the STV0680 driver - Kevin ********************************************************************/ -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva (pgd_t * pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none (*pgd)) { - pmd = pmd_offset (pgd, adr); - if (!pmd_none (*pmd)) { - preempt_disable(); - ptep = pte_offset_map (pmd, adr); - pte = *ptep; - pte_unmap(pte); - preempt_enable(); - if (pte_present (pte)) { - ret = (unsigned long) page_address (pte_page (pte)); - ret |= (adr & (PAGE_SIZE - 1)); - } - } - } - return ret; -} - -/* Here we want the physical address of the memory. This is used when - * initializing the contents of the area and marking the pages as reserved. +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa (unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR (adr); - kva = uvirt_to_kva (pgd_offset_k (va), va); - ret = __pa (kva); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ + ret = __pa(kva); return ret; } static void *rvmalloc (unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32 (size); if (!mem) return NULL; @@ -182,36 +153,25 @@ memset (mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = kvirt_to_pa (adr); - mem_map_reserve (virt_to_page (__va (page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; } static void rvfree (void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - adr = (unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa (adr); - mem_map_unreserve (virt_to_page (__va (page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree (mem); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/uhci.c linux-2.5/drivers/usb/uhci.c --- linux-2.5.5/drivers/usb/uhci.c Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/usb/uhci.c Fri Mar 1 15:07:38 2002 @@ -4,7 +4,7 @@ * Maintainer: Johannes Erdfelt * * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999-2001 Johannes Erdfelt, johannes@erdfelt.com + * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com * (C) Copyright 1999 Randy Dunlap * (C) Copyright 1999 Georg Acher, acher@in.tum.de * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de @@ -53,11 +53,11 @@ #include #include +#include "hcd.h" #include "uhci.h" #include - /* * Version Information */ @@ -65,7 +65,6 @@ #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber" #define DRIVER_DESC "USB Universal Host Controller Interface driver" - /* * debug = 0, no debugging messages * debug = 1, dump failed URB's except for stalls @@ -100,6 +99,7 @@ /* If a transfer is still active after this much time, turn off FSBR */ #define IDLE_TIMEOUT (HZ / 20) /* 50 ms */ +#define FSBR_DELAY (HZ / 20) /* 50 ms */ #define MAX_URB_LOOP 2048 /* Maximum number of linked URB's */ @@ -240,10 +240,10 @@ unsigned long flags; /* If it's not inserted, don't remove it */ + spin_lock_irqsave(&uhci->frame_list_lock, flags); if (td->frame == -1 && list_empty(&td->fl_list)) - return; + goto out; - spin_lock_irqsave(&uhci->frame_list_lock, flags); if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) { if (list_empty(&td->fl_list)) { uhci->fl->frame[td->frame] = td->link; @@ -268,6 +268,7 @@ list_del_init(&td->fl_list); td->frame = -1; +out: spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } @@ -358,6 +359,9 @@ pci_pool_free(uhci->qh_pool, qh, qh->dma_handle); } +/* + * MUST be called with uhci->frame_list_lock acquired + */ static void _uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; @@ -417,11 +421,10 @@ return; /* Only go through the hoops if it's actually linked in */ + spin_lock_irqsave(&uhci->frame_list_lock, flags); if (!list_empty(&qh->list)) { qh->urbp = NULL; - spin_lock_irqsave(&uhci->frame_list_lock, flags); - pqh = list_entry(qh->list.prev, struct uhci_qh, list); if (pqh->urbp) { @@ -444,9 +447,8 @@ qh->element = qh->link = UHCI_PTR_TERM; list_del_init(&qh->list); - - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); spin_lock_irqsave(&uhci->qh_remove_list_lock, flags); @@ -658,6 +660,9 @@ return urbp; } +/* + * MUST be called with urb->lock acquired + */ static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; @@ -667,6 +672,9 @@ list_add_tail(&td->list, &urbp->td_list); } +/* + * MUST be called with urb->lock acquired + */ static void uhci_remove_td_from_urb(struct uhci_td *td) { if (list_empty(&td->list)) @@ -677,22 +685,22 @@ td->urb = NULL; } +/* + * MUST be called with urb->lock acquired + */ static void uhci_destroy_urb_priv(struct urb *urb) { struct list_head *head, *tmp; struct urb_priv *urbp; struct uhci *uhci; - unsigned long flags; - - spin_lock_irqsave(&urb->lock, flags); urbp = (struct urb_priv *)urb->hcpriv; if (!urbp) - goto out; + return; if (!urbp->dev || !urbp->dev->bus || !urbp->dev->bus->hcpriv) { warn("uhci_destroy_urb_priv: urb %p belongs to disconnected device or bus?", urb); - goto out; + return; } if (!list_empty(&urb->urb_list)) @@ -715,20 +723,21 @@ uhci_free_td(uhci, td); } - if (urbp->setup_packet_dma_handle) + if (urbp->setup_packet_dma_handle) { pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle, sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE); + urbp->setup_packet_dma_handle = 0; + } - if (urbp->transfer_buffer_dma_handle) + if (urbp->transfer_buffer_dma_handle) { pci_unmap_single(uhci->dev, urbp->transfer_buffer_dma_handle, urb->transfer_buffer_length, usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + urbp->transfer_buffer_dma_handle = 0; + } urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); - -out: - spin_unlock_irqrestore(&urb->lock, flags); } static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb) @@ -757,7 +766,7 @@ if ((!(urb->transfer_flags & USB_NO_FSBR)) && urbp->fsbr) { urbp->fsbr = 0; if (!--uhci->fsbr) - uhci->skel_term_qh->link = UHCI_PTR_TERM; + uhci->fsbrtimeout = jiffies + FSBR_DELAY; } spin_unlock_irqrestore(&uhci->frame_list_lock, flags); @@ -872,7 +881,7 @@ * It's IN if the pipe is an output pipe or we're not expecting * data back. */ - destination &= ~TD_PID; + destination &= ~TD_TOKEN_PID_MASK; if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) destination |= USB_PID_IN; else @@ -1312,9 +1321,7 @@ struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; struct list_head *tmp, *head; int ret = 0; - unsigned long flags; - spin_lock_irqsave(&uhci->urb_list_lock, flags); head = &uhci->urb_list; tmp = head->next; while (tmp != head) { @@ -1337,8 +1344,6 @@ } else ret = -1; /* no previous urb found */ - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); - return ret; } @@ -1446,34 +1451,30 @@ return ret; } +/* + * MUST be called with uhci->urb_list_lock acquired + */ static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb) { struct list_head *tmp, *head; - unsigned long flags; - struct urb *u = NULL; /* We don't match Isoc transfers since they are special */ if (usb_pipeisoc(urb->pipe)) return NULL; - spin_lock_irqsave(&uhci->urb_list_lock, flags); head = &uhci->urb_list; tmp = head->next; while (tmp != head) { - u = list_entry(tmp, struct urb, urb_list); + struct urb *u = list_entry(tmp, struct urb, urb_list); tmp = tmp->next; if (u->dev == urb->dev && u->pipe == urb->pipe && u->status == -EINPROGRESS) - goto out; + return u; } - u = NULL; -out: - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); - - return u; + return NULL; } static int uhci_submit_urb(struct urb *urb, int mem_flags) @@ -1492,19 +1493,25 @@ return -ENODEV; } + /* increment the reference count of the urb, as we now also control it */ + urb = usb_get_urb(urb); + uhci = (struct uhci *)urb->dev->bus->hcpriv; INIT_LIST_HEAD(&urb->urb_list); usb_inc_dev_use(urb->dev); - spin_lock_irqsave(&urb->lock, flags); + spin_lock_irqsave(&uhci->urb_list_lock, flags); + spin_lock(&urb->lock); if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET || urb->status == -ECONNABORTED) { dbg("uhci_submit_urb: urb not available to submit (status = %d)", urb->status); /* Since we can have problems on the out path */ - spin_unlock_irqrestore(&urb->lock, flags); + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); usb_dec_dev_use(urb->dev); + usb_put_urb(urb); return ret; } @@ -1572,18 +1579,21 @@ out: urb->status = ret; - spin_unlock_irqrestore(&urb->lock, flags); - if (ret == -EINPROGRESS) { - spin_lock_irqsave(&uhci->urb_list_lock, flags); /* We use _tail to make find_urb_ep more efficient */ list_add_tail(&urb->urb_list, &uhci->urb_list); + + spin_unlock(&urb->lock); spin_unlock_irqrestore(&uhci->urb_list_lock, flags); return 0; } uhci_unlink_generic(uhci, urb); + + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + uhci_call_completion(urb); return ret; @@ -1592,7 +1602,7 @@ /* * Return the result of a transfer * - * Must be called with urb_list_lock acquired + * MUST be called with urb_list_lock acquired */ static void uhci_transfer_result(struct uhci *uhci, struct urb *urb) { @@ -1631,10 +1641,10 @@ urbp->status = ret; - spin_unlock_irqrestore(&urb->lock, flags); - - if (ret == -EINPROGRESS) + if (ret == -EINPROGRESS) { + spin_unlock_irqrestore(&urb->lock, flags); return; + } switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL: @@ -1664,15 +1674,22 @@ usb_pipetype(urb->pipe), urb); } + /* Remove it from uhci->urb_list */ list_del_init(&urb->urb_list); uhci_add_complete(urb); + + spin_unlock_irqrestore(&urb->lock, flags); } +/* + * MUST be called with urb->lock acquired + */ static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb) { struct list_head *head, *tmp; struct urb_priv *urbp = urb->hcpriv; + int prevactive = 1; /* We can get called when urbp allocation fails, so check */ if (!urbp) @@ -1680,6 +1697,19 @@ uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ + /* + * Now we need to find out what the last successful toggle was + * so we can update the local data toggle for the next transfer + * + * There's 3 way's the last successful completed TD is found: + * + * 1) The TD is NOT active and the actual length < expected length + * 2) The TD is NOT active and it's the last TD in the chain + * 3) The TD is active and the previous TD is NOT active + * + * Control and Isochronous ignore the toggle, so this is safe + * for all types + */ head = &urbp->td_list; tmp = head->next; while (tmp != head) { @@ -1687,15 +1717,18 @@ tmp = tmp->next; - /* Control and Isochronous ignore the toggle, so this */ - /* is safe for all types */ - if ((!(td->status & TD_CTRL_ACTIVE) && - (uhci_actual_length(td->status) < uhci_expected_length(td->info)) || - tmp == head)) { + if (!(td->status & TD_CTRL_ACTIVE) && + (uhci_actual_length(td->status) < uhci_expected_length(td->info) || + tmp == head)) usb_settoggle(urb->dev, uhci_endpoint(td->info), uhci_packetout(td->info), uhci_toggle(td->info) ^ 1); - } + else if ((td->status & TD_CTRL_ACTIVE) && !prevactive) + usb_settoggle(urb->dev, uhci_endpoint(td->info), + uhci_packetout(td->info), + uhci_toggle(td->info)); + + prevactive = td->status & TD_CTRL_ACTIVE; } uhci_delete_queued_urb(uhci, urb); @@ -1718,6 +1751,9 @@ uhci = (struct uhci *)urb->dev->bus->hcpriv; + spin_lock_irqsave(&uhci->urb_list_lock, flags); + spin_lock(&urb->lock); + /* Release bandwidth for Interrupt or Isoc. transfers */ /* Spinlock needed ? */ if (urb->bandwidth) { @@ -1733,35 +1769,41 @@ } } - if (urb->status != -EINPROGRESS) + if (urb->status != -EINPROGRESS) { + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); return 0; + } - spin_lock_irqsave(&uhci->urb_list_lock, flags); list_del_init(&urb->urb_list); - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); uhci_unlink_generic(uhci, urb); /* Short circuit the virtual root hub */ if (urb->dev == uhci->rh.dev) { rh_unlink_urb(urb); + + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + uhci_call_completion(urb); } else { if (urb->transfer_flags & USB_ASYNC_UNLINK) { - /* urb_list is available now since we called */ - /* uhci_unlink_generic already */ - urbp->status = urb->status = -ECONNABORTED; - spin_lock_irqsave(&uhci->urb_remove_list_lock, flags); + spin_lock(&uhci->urb_remove_list_lock); - /* Check to see if the remove list is empty */ + /* If we're the first, set the next interrupt bit */ if (list_empty(&uhci->urb_remove_list)) uhci_set_next_interrupt(uhci); list_add(&urb->urb_list, &uhci->urb_remove_list); - spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); + spin_unlock(&uhci->urb_remove_list_lock); + + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + } else { urb->status = -ENOENT; @@ -1774,6 +1816,9 @@ } else schedule_timeout(1+1*HZ/1000); + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + uhci_call_completion(urb); } } @@ -1907,12 +1952,14 @@ /* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */ static int rh_send_irq(struct urb *urb) { - int i, len = 1; struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; unsigned int io_addr = uhci->io_addr; + unsigned long flags; + int i, len = 1; __u16 data = 0; - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + spin_lock_irqsave(&urb->lock, flags); for (i = 0; i < uhci->rh.numports; i++) { data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0); len = (i + 1) / 8 + 1; @@ -1922,6 +1969,8 @@ urb->actual_length = len; urbp->status = 0; + spin_unlock_irqrestore(&urb->lock, flags); + if ((data > 0) && (uhci->rh.send != 0)) { dbg("root-hub INT complete: port1: %x port2: %x data: %x", inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data); @@ -1948,7 +1997,6 @@ spin_lock_irqsave(&uhci->urb_list_lock, flags); head = &uhci->urb_list; - tmp = head->next; while (tmp != head) { struct urb *u = list_entry(tmp, struct urb, urb_list); @@ -1956,6 +2004,8 @@ tmp = tmp->next; + spin_lock(&urb->lock); + /* Check if the FSBR timed out */ if (urbp->fsbr && !urbp->fsbr_timeout && time_after_eq(jiffies, urbp->fsbrtime + IDLE_TIMEOUT)) uhci_fsbr_timeout(uhci, u); @@ -1965,6 +2015,8 @@ list_del(&u->urb_list); list_add_tail(&u->urb_list, &list); } + + spin_unlock(&urb->lock); } spin_unlock_irqrestore(&uhci->urb_list_lock, flags); @@ -1979,6 +2031,12 @@ uhci_unlink_urb(u); } + /* Really disable FSBR */ + if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { + uhci->fsbrtimeout = 0; + uhci->skel_term_qh->link = UHCI_PTR_TERM; + } + /* enter global suspend if nothing connected */ if (!uhci->is_suspended && !ports_active(uhci)) suspend_hc(uhci); @@ -2198,6 +2256,9 @@ return stat; } +/* + * MUST be called with urb->lock acquired + */ static int rh_unlink_urb(struct urb *urb) { struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; @@ -2233,16 +2294,25 @@ static void uhci_call_completion(struct urb *urb) { - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct urb_priv *urbp; struct usb_device *dev = urb->dev; struct uhci *uhci = (struct uhci *)dev->bus->hcpriv; int is_ring = 0, killed, resubmit_interrupt, status; struct urb *nurb; + unsigned long flags; + + spin_lock_irqsave(&urb->lock, flags); + + urbp = (struct urb_priv *)urb->hcpriv; + if (!urbp || !urb->dev) { + spin_unlock_irqrestore(&urb->lock, flags); + return; + } killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED || urb->status == -ECONNRESET); resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT && - urb->interval && !killed); + urb->interval); nurb = urb->next; if (nurb && !killed) { @@ -2267,14 +2337,6 @@ is_ring = (nurb == urb); } - status = urbp->status; - if (!resubmit_interrupt) - /* We don't need urb_priv anymore */ - uhci_destroy_urb_priv(urb); - - if (!killed) - urb->status = status; - if (urbp->transfer_buffer_dma_handle) pci_dma_sync_single(uhci->dev, urbp->transfer_buffer_dma_handle, urb->transfer_buffer_length, usb_pipein(urb->pipe) ? @@ -2284,11 +2346,28 @@ pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle, sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE); + status = urbp->status; + if (!resubmit_interrupt || killed) + /* We don't need urb_priv anymore */ + uhci_destroy_urb_priv(urb); + + if (!killed) + urb->status = status; + urb->dev = NULL; - if (urb->complete) + spin_unlock_irqrestore(&urb->lock, flags); + + if (urb->complete) { urb->complete(urb); - if (resubmit_interrupt) { + /* Recheck the status. The completion handler may have */ + /* unlinked the resubmitting interrupt URB */ + killed = (urb->status == -ENOENT || + urb->status == -ECONNABORTED || + urb->status == -ECONNRESET); + } + + if (resubmit_interrupt && !killed) { urb->dev = dev; uhci_reset_interrupt(urb); } else { @@ -2299,6 +2378,7 @@ /* We decrement the usage count after we're done */ /* with everything */ usb_dec_dev_use(dev); + usb_put_urb(urb); } } } @@ -2315,11 +2395,14 @@ struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list); struct urb *urb = urbp->urb; - tmp = tmp->next; - list_del_init(&urbp->complete_list); + spin_unlock_irqrestore(&uhci->complete_list_lock, flags); uhci_call_completion(urb); + + spin_lock_irqsave(&uhci->complete_list_lock, flags); + head = &uhci->complete_list; + tmp = head->next; } spin_unlock_irqrestore(&uhci->complete_list_lock, flags); } @@ -2341,7 +2424,8 @@ list_del_init(&urb->urb_list); urbp->status = urb->status = -ECONNRESET; - uhci_call_completion(urb); + + uhci_add_complete(urb); } spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); } @@ -2996,7 +3080,7 @@ id_table: uhci_pci_ids, probe: uhci_pci_probe, - remove: uhci_pci_remove, + remove: __devexit_p(uhci_pci_remove), #ifdef CONFIG_PM suspend: uhci_pci_suspend, @@ -3074,3 +3158,4 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); + diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/uhci.h linux-2.5/drivers/usb/uhci.h --- linux-2.5.5/drivers/usb/uhci.h Thu Feb 21 17:47:37 2002 +++ linux-2.5/drivers/usb/uhci.h Tue Mar 5 14:07:48 2002 @@ -121,15 +121,16 @@ * for TD : (a.k.a. Token) */ #define TD_TOKEN_TOGGLE 19 -#define TD_PID 0xFF +#define TD_TOKEN_PID_MASK 0xFF +#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n - 1 */ #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_TOKEN_EXPLEN_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) #define uhci_devep(token) (((token) >> 8) & 0x7ff) -#define uhci_packetid(token) ((token) & 0xff) +#define uhci_packetid(token) ((token) & TD_TOKEN_PID_MASK) #define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN) #define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN) @@ -163,7 +164,7 @@ struct list_head list; /* P: urb->lock */ int frame; - struct list_head fl_list; /* P: frame_list_lock */ + struct list_head fl_list; /* P: uhci->frame_list_lock */ } __attribute__((aligned(16))); /* @@ -306,21 +307,26 @@ struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ spinlock_t frame_list_lock; - struct uhci_frame_list *fl; /* Frame list */ + struct uhci_frame_list *fl; /* P: uhci->frame_list_lock */ int fsbr; /* Full speed bandwidth reclamation */ + unsigned long fsbrtimeout; /* FSBR delay */ int is_suspended; + /* Main list of URB's currently controlled by this HC */ + spinlock_t urb_list_lock; + struct list_head urb_list; /* P: uhci->urb_list_lock */ + + /* List of QH's that are done, but waiting to be unlinked (race) */ spinlock_t qh_remove_list_lock; - struct list_head qh_remove_list; + struct list_head qh_remove_list; /* P: uhci->qh_remove_list_lock */ + /* List of asynchronously unlinked URB's */ spinlock_t urb_remove_list_lock; - struct list_head urb_remove_list; - - spinlock_t urb_list_lock; - struct list_head urb_list; + struct list_head urb_remove_list; /* P: uhci->urb_remove_list_lock */ + /* List of URB's awaiting completion callback */ spinlock_t complete_list_lock; - struct list_head complete_list; + struct list_head complete_list; /* P: uhci->complete_list_lock */ struct virt_root_hub rh; /* private data of the virtual root hub */ }; @@ -333,7 +339,7 @@ dma_addr_t transfer_buffer_dma_handle; struct uhci_qh *qh; /* QH for this URB */ - struct list_head td_list; + struct list_head td_list; /* P: urb->lock */ int fsbr : 1; /* URB turned on FSBR */ int fsbr_timeout : 1; /* URB timed out on FSBR */ @@ -345,11 +351,36 @@ int status; /* Final status */ unsigned long inserttime; /* In jiffies */ - unsigned long fsbrtime; /* In jiffies */ + unsigned long fsbrtime; /* In jiffies */ - struct list_head queue_list; - struct list_head complete_list; + struct list_head queue_list; /* P: uhci->frame_list_lock */ + struct list_head complete_list; /* P: uhci->complete_list_lock */ }; + +/* + * Locking in uhci.c + * + * spinlocks are used extensively to protect the many lists and data + * structures we have. It's not that pretty, but it's necessary. We + * need to be done with all of the locks (except complete_list_lock) when + * we call urb->complete. I've tried to make it simple enough so I don't + * have to spend hours racking my brain trying to figure out if the + * locking is safe. + * + * Here's the safe locking order to prevent deadlocks: + * + * #1 uhci->urb_list_lock + * #2 urb->lock + * #3 uhci->urb_remove_list_lock, uhci->frame_list_lock, + * uhci->qh_remove_list_lock + * #4 uhci->complete_list_lock + * + * If you're going to grab 2 or more locks at once, ALWAYS grab the lock + * at the lowest level FIRST and NEVER grab locks at the same level at the + * same time. + * + * So, if you need uhci->urb_list_lock, grab it before you grab urb->lock + */ /* ------------------------------------------------------------------------- Virtual Root HUB diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/usb-ohci.c linux-2.5/drivers/usb/usb-ohci.c --- linux-2.5.5/drivers/usb/usb-ohci.c Wed Feb 20 02:10:57 2002 +++ linux-2.5/drivers/usb/usb-ohci.c Fri Mar 1 15:07:38 2002 @@ -73,11 +73,13 @@ #define OHCI_USE_NPS // force NoPowerSwitching mode // #define OHCI_VERBOSE_DEBUG /* not always helpful */ +#include "hcd.h" #include "usb-ohci.h" #ifdef CONFIG_PMAC_PBOOK -#include +#include +#include #include #ifndef CONFIG_PM #define CONFIG_PM @@ -205,6 +207,7 @@ urb_free_priv ((struct ohci *)urb->dev->bus->hcpriv, urb_priv); usb_dec_dev_use (urb->dev); urb->dev = NULL; + usb_put_urb (urb); } } @@ -553,6 +556,9 @@ // if(usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) // return -EPIPE; + /* increment the reference count of the urb, as we now also control it */ + urb = usb_get_urb (urb); + usb_inc_dev_use (urb->dev); ohci = (ohci_t *) urb->dev->bus->hcpriv; @@ -568,12 +574,14 @@ * such as powering down ports */ if (ohci->disabled) { usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return -ESHUTDOWN; } /* every endpoint has a ed, locate and fill it */ if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) { usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return -ENOMEM; } @@ -595,6 +603,7 @@ size = urb->number_of_packets; if (size <= 0) { usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return -EINVAL; } for (i = 0; i < urb->number_of_packets; i++) { @@ -615,6 +624,7 @@ urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), mem_flags); if (!urb_priv) { usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return -ENOMEM; } memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (td_t *)); @@ -632,6 +642,7 @@ urb_free_priv (ohci, urb_priv); spin_unlock_irqrestore (&usb_ed_lock, flags); usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return -ENOMEM; } } @@ -640,6 +651,7 @@ urb_free_priv (ohci, urb_priv); spin_unlock_irqrestore (&usb_ed_lock, flags); usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return -EINVAL; } @@ -662,6 +674,7 @@ urb_free_priv (ohci, urb_priv); spin_unlock_irqrestore (&usb_ed_lock, flags); usb_dec_dev_use (urb->dev); + usb_put_urb (urb); return bustime; } usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe)); @@ -2100,6 +2113,7 @@ urb->dev = NULL; if (urb->complete) urb->complete (urb); + usb_put_urb (urb); return 0; } @@ -2123,6 +2137,7 @@ urb->complete (urb); } else urb->status = -ENOENT; + usb_put_urb (urb); } return 0; } @@ -2698,12 +2713,12 @@ pci_write_config_word (dev, PCI_COMMAND, cmd); #ifdef CONFIG_PMAC_PBOOK { - struct device_node *of_node; + struct device_node *of_node; - /* Disable USB PAD & cell clock */ - of_node = pci_device_to_OF_node (ohci->ohci_dev); - if (of_node && _machine == _MACH_Pmac) - feature_set_usb_power (of_node, 0); + /* Disable USB PAD & cell clock */ + of_node = pci_device_to_OF_node (ohci->ohci_dev); + if (of_node) + pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); } #endif return 0; @@ -2728,12 +2743,12 @@ #ifdef CONFIG_PMAC_PBOOK { - struct device_node *of_node; + struct device_node *of_node; - /* Re-enable USB PAD & cell clock */ - of_node = pci_device_to_OF_node (ohci->ohci_dev); - if (of_node && _machine == _MACH_Pmac) - feature_set_usb_power (of_node, 1); + /* Re-enable USB PAD & cell clock */ + of_node = pci_device_to_OF_node (ohci->ohci_dev); + if (of_node) + pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1); } #endif @@ -2859,7 +2874,7 @@ id_table: &ohci_pci_ids [0], probe: ohci_pci_probe, - remove: ohci_pci_remove, + remove: __devexit_p(ohci_pci_remove), #ifdef CONFIG_PM suspend: ohci_pci_suspend, diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/usb-uhci.c linux-2.5/drivers/usb/usb-uhci.c --- linux-2.5.5/drivers/usb/usb-uhci.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/usb/usb-uhci.c Fri Mar 1 15:07:38 2002 @@ -57,6 +57,7 @@ #define VERSTR "$Revision: 1.275 $ time " __TIME__ " " __DATE__ #include +#include "hcd.h" #include "usb-uhci.h" #include "usb-uhci-debug.h" @@ -1217,6 +1218,7 @@ urb->complete ((struct urb *) urb); } usb_dec_dev_use (usb_dev); + usb_put_urb (urb); } else spin_unlock_irqrestore (&s->urb_list_lock, flags); @@ -1305,7 +1307,7 @@ #else kfree (urb_priv); #endif - + usb_put_urb (urb); } } } @@ -1650,6 +1652,9 @@ return -EINVAL; } + /* increment the reference count of the urb, as we now also control it */ + urb = usb_get_urb (urb); + usb_inc_dev_use (urb->dev); spin_lock_irqsave (&s->urb_list_lock, flags); @@ -1665,6 +1670,7 @@ (!(urb->transfer_flags & USB_QUEUE_BULK) || !(queued_urb->transfer_flags & USB_QUEUE_BULK)))) { spin_unlock_irqrestore (&s->urb_list_lock, flags); usb_dec_dev_use (urb->dev); + usb_put_urb (urb); err("ENXIO %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,queued_urb); return -ENXIO; // urb already queued } @@ -1678,6 +1684,7 @@ if (!urb_priv) { usb_dec_dev_use (urb->dev); spin_unlock_irqrestore (&s->urb_list_lock, flags); + usb_put_urb (urb); return -ENOMEM; } @@ -1766,6 +1773,7 @@ #else kfree (urb_priv); #endif + usb_put_urb (urb); return ret; } @@ -2730,6 +2738,7 @@ } usb_dec_dev_use (usb_dev); + usb_put_urb (urb); } } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/usb.c linux-2.5/drivers/usb/usb.c --- linux-2.5.5/drivers/usb/usb.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/usb/usb.c Fri Mar 1 15:07:38 2002 @@ -40,12 +40,7 @@ #endif #include -static const int usb_bandwidth_option = -#ifdef CONFIG_USB_BANDWIDTH - 1; -#else - 0; -#endif +#include "hcd.h" extern int usb_hub_init(void); extern void usb_hub_cleanup(void); @@ -61,13 +56,9 @@ * We have a per-interface "registered driver" list. */ LIST_HEAD(usb_driver_list); -LIST_HEAD(usb_bus_list); -struct semaphore usb_bus_list_lock; devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */ -static struct usb_busmap busmap; - static struct usb_driver *usb_minors[16]; /** @@ -105,6 +96,7 @@ /** * usb_scan_devices - scans all unclaimed USB interfaces + * Context: !in_interrupt () * * Goes through all unclaimed USB interfaces, and offers them to all * registered USB drivers through the 'probe' function. @@ -173,6 +165,7 @@ /** * usb_deregister - unregister a USB driver * @driver: USB operations of the driver to unregister + * Context: !in_interrupt () * * Unlinks the specified driver from the internal USB driver list. */ @@ -258,259 +251,6 @@ } /* - * usb_calc_bus_time: - * - * returns (approximate) USB bus time in nanoseconds for a USB transaction. - */ -static long usb_calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount) -{ - unsigned long tmp; - - if (low_speed) /* no isoc. here */ - { - if (input_dir) - { - tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); - } - else - { - tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); - } - } - - /* for full-speed: */ - - if (!isoc) /* Input or Output */ - { - tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (9107L + BW_HOST_DELAY + tmp); - } /* end not Isoc */ - - /* for isoc: */ - - tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); -} - -/* - * usb_check_bandwidth(): - * - * old_alloc is from host_controller->bandwidth_allocated in microseconds; - * bustime is from calc_bus_time(), but converted to microseconds. - * - * returns if successful, - * or -ENOSPC if bandwidth request fails. - * - * FIXME: - * This initial implementation does not use Endpoint.bInterval - * in managing bandwidth allocation. - * It probably needs to be expanded to use Endpoint.bInterval. - * This can be done as a later enhancement (correction). - * This will also probably require some kind of - * frame allocation tracking...meaning, for example, - * that if multiple drivers request interrupts every 10 USB frames, - * they don't all have to be allocated at - * frame numbers N, N+10, N+20, etc. Some of them could be at - * N+11, N+21, N+31, etc., and others at - * N+12, N+22, N+32, etc. - * However, this first cut at USB bandwidth allocation does not - * contain any frame allocation tracking. - */ -int usb_check_bandwidth (struct usb_device *dev, struct urb *urb) -{ - int new_alloc; - int old_alloc = dev->bus->bandwidth_allocated; - unsigned int pipe = urb->pipe; - long bustime; - - bustime = usb_calc_bus_time (dev->speed == USB_SPEED_LOW, - usb_pipein(pipe), usb_pipeisoc(pipe), - usb_maxpacket(dev, pipe, usb_pipeout(pipe))); - if (usb_pipeisoc(pipe)) - bustime = NS_TO_US(bustime) / urb->number_of_packets; - else - bustime = NS_TO_US(bustime); - - new_alloc = old_alloc + (int)bustime; - /* what new total allocated bus time would be */ - - if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) - dbg("usb-check-bandwidth %sFAILED: was %u, would be %u, bustime = %ld us", - usb_bandwidth_option ? "" : "would have ", - old_alloc, new_alloc, bustime); - - if (!usb_bandwidth_option) /* don't enforce it */ - return (bustime); - return (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? bustime : -ENOSPC; -} - -void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc) -{ - dev->bus->bandwidth_allocated += bustime; - if (isoc) - dev->bus->bandwidth_isoc_reqs++; - else - dev->bus->bandwidth_int_reqs++; - urb->bandwidth = bustime; - -#ifdef USB_BANDWIDTH_MESSAGES - dbg("bandwidth alloc increased by %d to %d for %d requesters", - bustime, - dev->bus->bandwidth_allocated, - dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); -#endif -} - -/* - * usb_release_bandwidth(): - * - * called to release a pipe's bandwidth (in microseconds) - */ -void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, int isoc) -{ - dev->bus->bandwidth_allocated -= urb->bandwidth; - if (isoc) - dev->bus->bandwidth_isoc_reqs--; - else - dev->bus->bandwidth_int_reqs--; - -#ifdef USB_BANDWIDTH_MESSAGES - dbg("bandwidth alloc reduced by %d to %d for %d requesters", - urb->bandwidth, - dev->bus->bandwidth_allocated, - dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); -#endif - urb->bandwidth = 0; -} - -static void usb_bus_get(struct usb_bus *bus) -{ - atomic_inc(&bus->refcnt); -} - -static void usb_bus_put(struct usb_bus *bus) -{ - if (atomic_dec_and_test(&bus->refcnt)) - kfree(bus); -} - -/** - * usb_alloc_bus - creates a new USB host controller structure (usbcore-internal) - * @op: pointer to a struct usb_operations that this bus structure should use - * - * Creates a USB host controller bus structure with the specified - * usb_operations and initializes all the necessary internal objects. - * (For use only by USB Host Controller Drivers.) - * - * If no memory is available, NULL is returned. - * - * The caller should call usb_free_bus() when it is finished with the structure. - */ -struct usb_bus *usb_alloc_bus(struct usb_operations *op) -{ - struct usb_bus *bus; - - bus = kmalloc(sizeof(*bus), GFP_KERNEL); - if (!bus) - return NULL; - - memset(&bus->devmap, 0, sizeof(struct usb_devmap)); - -#ifdef DEVNUM_ROUND_ROBIN - bus->devnum_next = 1; -#endif /* DEVNUM_ROUND_ROBIN */ - - bus->op = op; - bus->root_hub = NULL; - bus->hcpriv = NULL; - bus->busnum = -1; - bus->bandwidth_allocated = 0; - bus->bandwidth_int_reqs = 0; - bus->bandwidth_isoc_reqs = 0; - - INIT_LIST_HEAD(&bus->bus_list); - - atomic_set(&bus->refcnt, 1); - - return bus; -} - -/** - * usb_free_bus - frees the memory used by a bus structure (usbcore-internal) - * @bus: pointer to the bus to free - * - * (For use only by USB Host Controller Drivers.) - */ -void usb_free_bus(struct usb_bus *bus) -{ - if (!bus) - return; - - usb_bus_put(bus); -} - -/** - * usb_register_bus - registers the USB host controller with the usb core (usbcore-internal) - * @bus: pointer to the bus to register - * - * (For use only by USB Host Controller Drivers.) - * - * This call is synchronous, and may not be used in an interrupt context. - */ -void usb_register_bus(struct usb_bus *bus) -{ - int busnum; - - down (&usb_bus_list_lock); - busnum = find_next_zero_bit(busmap.busmap, USB_MAXBUS, 1); - if (busnum < USB_MAXBUS) { - set_bit(busnum, busmap.busmap); - bus->busnum = busnum; - } else - warn("too many buses"); - - usb_bus_get(bus); - - /* Add it to the list of buses */ - list_add(&bus->bus_list, &usb_bus_list); - up (&usb_bus_list_lock); - - usbfs_add_bus(bus); - - info("new USB bus registered, assigned bus number %d", bus->busnum); -} - -/** - * usb_deregister_bus - deregisters the USB host controller (usbcore-internal) - * @bus: pointer to the bus to deregister - * - * (For use only by USB Host Controller Drivers.) - * - * This call is synchronous, and may not be used in an interrupt context. - */ -void usb_deregister_bus(struct usb_bus *bus) -{ - info("USB bus %d deregistered", bus->busnum); - - /* - * NOTE: make sure that all the devices are removed by the - * controller code, as well as having it call this when cleaning - * itself up - */ - down (&usb_bus_list_lock); - list_del(&bus->bus_list); - up (&usb_bus_list_lock); - - usbfs_remove_bus(bus); - - clear_bit(bus->busnum, busmap.busmap); - - usb_bus_put(bus); -} - -/* * This function is for doing a depth-first search for devices which * have support, for dynamic loading of driver modules. */ @@ -1016,6 +756,7 @@ * usb_alloc_dev - allocate a usb device structure (usbcore-internal) * @parent: hub to which device is connected * @bus: bus used to access the device + * Context: !in_interrupt () * * Only hub drivers (including virtual root hub drivers for host * controllers) should ever call this. @@ -1078,14 +819,12 @@ atomic_inc(&dev->refcnt); } -/* ---------------------------------------------------------------------- - * New USB Core Functions - * ----------------------------------------------------------------------*/ /** * usb_alloc_urb - creates a new urb for a USB driver to use * @iso_packets: number of iso packets for this urb - * @mem_flags: the type of memory to allocate, see kmalloc() for a list of valid options for this. + * @mem_flags: the type of memory to allocate, see kmalloc() for a list of + * valid options for this. * * Creates an urb for the USB driver to use, initializes a few internal * structures, incrementes the usage counter, and returns a pointer to it. @@ -1158,7 +897,8 @@ /** * usb_submit_urb - asynchronously issue a transfer request for an endpoint * @urb: pointer to the urb describing the request - * @mem_flags: the type of memory to allocate, see kmalloc() for a list of valid options for this. + * @mem_flags: the type of memory to allocate, see kmalloc() for a list + * of valid options for this. * * This submits a transfer request, and transfers control of the URB * describing that request to the USB subsystem. Request completion will @@ -1393,7 +1133,9 @@ * @index: USB message index value * @data: pointer to the data to send * @size: length in bytes of the data to send - * @timeout: time to wait for the message to complete before timing out (if 0 the wait is forever) + * @timeout: time in jiffies to wait for the message to complete before + * timing out (if 0 the wait is forever) + * Context: !in_interrupt () * * This function sends a simple control message to a specified endpoint * and waits for the message to complete, or timeout. @@ -1401,7 +1143,7 @@ * If successful, it returns 0, otherwise a negative error number. * * Don't use this function from within an interrupt context, like a - * bottom half handler. If you need a asyncronous message, or need to send + * bottom half handler. If you need an asynchronous message, or need to send * a message from within interrupt context, use usb_submit_urb() */ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, @@ -1436,7 +1178,9 @@ * @data: pointer to the data to send * @len: length in bytes of the data to send * @actual_length: pointer to a location to put the actual length transferred in bytes - * @timeout: time to wait for the message to complete before timing out (if 0 the wait is forever) + * @timeout: time in jiffies to wait for the message to complete before + * timing out (if 0 the wait is forever) + * Context: !in_interrupt () * * This function sends a simple bulk message to a specified endpoint * and waits for the message to complete, or timeout. @@ -1446,7 +1190,7 @@ * actual_length paramater. * * Don't use this function from within an interrupt context, like a - * bottom half handler. If you need a asyncronous message, or need to + * bottom half handler. If you need an asynchronous message, or need to * send a message from within interrupt context, use usb_submit_urb() */ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, @@ -1474,6 +1218,11 @@ * Returns the current frame number for the USB host controller * used with the given USB device. This can be used when scheduling * isochronous requests. + * + * Note that different kinds of host controller have different + * "scheduling horizons". While one type might support scheduling only + * 32 frames into the future, others could support scheduling up to + * 1024 frames into the future. */ int usb_get_current_frame_number(struct usb_device *dev) { @@ -1946,6 +1695,7 @@ /** * usb_disconnect - disconnect a device (usbcore-internal) * @pdev: pointer to device being disconnected + * Context: !in_interrupt () * * Something got disconnected. Get rid of it, and all of its children. * @@ -2069,6 +1819,7 @@ * @index: the number of the descriptor * @buf: where to put the descriptor * @size: how big is "buf"? + * Context: !in_interrupt () * * Gets a USB descriptor. Convenience functions exist to simplify * getting some types of descriptors. Use @@ -2110,6 +1861,7 @@ * @index: the number of the descriptor * @buf: where to put the string * @size: how big is "buf"? + * Context: !in_interrupt () * * Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character, * in little-endian byte order). @@ -2135,6 +1887,7 @@ /** * usb_get_device_descriptor - (re)reads the device descriptor * @dev: the device whose device descriptor is being updated + * Context: !in_interrupt () * * Updates the copy of the device descriptor stored in the device structure, * which dedicates space for this purpose. Note that several fields are @@ -2169,6 +1922,7 @@ * @type: USB_RECIP_*; for device, interface, or endpoint * @target: zero (for device), else interface or endpoint number * @data: pointer to two bytes of bitmap data + * Context: !in_interrupt () * * Returns device, interface, or endpoint status. Normally only of * interest to see if the device is self powered, or has enabled the @@ -2227,6 +1981,7 @@ * usb_clear_halt - tells device to clear endpoint halt/stall condition * @dev: device whose endpoint is halted * @pipe: endpoint "pipe" being cleared + * Context: !in_interrupt () * * This is used to clear halt conditions for bulk and interrupt endpoints, * as reported by URB completion status. Endpoints that are halted are @@ -2298,6 +2053,7 @@ * @dev: the device whose interface is being updated * @interface: the interface being updated * @alternate: the setting being chosen. + * Context: !in_interrupt () * * This is used to enable data transfers on interfaces that may not * be enabled by default. Not all devices support such configurability. @@ -2378,6 +2134,7 @@ * usb_set_configuration - Makes a particular device setting be current * @dev: the device whose configuration is being updated * @configuration: the configuration being chosen. + * Context: !in_interrupt () * * This is used to enable non-default device modes. Not all devices * support this kind of configurability. By default, configuration @@ -2540,6 +2297,7 @@ * @index: the number of the descriptor * @buf: where to put the string * @size: how big is "buf"? + * Context: !in_interrupt () * * This converts the UTF-16LE encoded strings returned by devices, from * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones @@ -2619,8 +2377,11 @@ * @dev: the device whose path is being constructed * @buf: where to put the string * @size: how big is "buf"? + * Context: !in_interrupt () * * Returns length of the string (>= 0) or out of memory status (< 0). + * + * NOTE: prefer to use use dev->devpath directly. */ int usb_make_path(struct usb_device *dev, char *buf, size_t size) { @@ -2768,29 +2529,6 @@ return 0; } -/** - * usb_register_root_hub - called by a usb host controller to register the root hub device in the system - * @usb_dev: the usb root hub device to be registered. - * @parent_dev: the parent device of this root hub. - * - * The USB host controller calls this function to register the root hub - * properly with the USB subsystem. It sets up the device properly in - * the driverfs tree, and then calls usb_new_device() to register the - * usb device. - */ -int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev) -{ - int retval; - - usb_dev->dev.parent = parent_dev; - strcpy (&usb_dev->dev.name[0], "usb_name"); - strcpy (&usb_dev->dev.bus_id[0], "usb_bus"); - retval = usb_new_device (usb_dev); - if (retval) - put_device (&usb_dev->dev); - return retval; -} - static int usb_open(struct inode * inode, struct file * file) { int minor = minor(inode->i_rdev); @@ -2859,7 +2597,6 @@ */ static int __init usb_init(void) { - init_MUTEX(&usb_bus_list_lock); usb_major_init(); usbfs_init(); usb_hub_init(); @@ -2892,11 +2629,7 @@ EXPORT_SYMBOL(usb_register); EXPORT_SYMBOL(usb_deregister); EXPORT_SYMBOL(usb_scan_devices); -EXPORT_SYMBOL(usb_alloc_bus); -EXPORT_SYMBOL(usb_free_bus); -EXPORT_SYMBOL(usb_register_bus); -EXPORT_SYMBOL(usb_deregister_bus); -EXPORT_SYMBOL(usb_register_root_hub); + EXPORT_SYMBOL(usb_alloc_dev); EXPORT_SYMBOL(usb_free_dev); EXPORT_SYMBOL(usb_inc_dev_use); @@ -2911,10 +2644,6 @@ EXPORT_SYMBOL(usb_reset_device); EXPORT_SYMBOL(usb_connect); EXPORT_SYMBOL(usb_disconnect); - -EXPORT_SYMBOL(usb_check_bandwidth); -EXPORT_SYMBOL(usb_claim_bandwidth); -EXPORT_SYMBOL(usb_release_bandwidth); EXPORT_SYMBOL(__usb_get_extra_descriptor); diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/usbvideo.c linux-2.5/drivers/usb/usbvideo.c --- linux-2.5.5/drivers/usb/usbvideo.c Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/usb/usbvideo.c Tue Feb 26 21:24:49 2002 @@ -59,33 +59,26 @@ /* Memory management functions */ /*******************************/ -#define MDEBUG(x) do { } while(0) /* Debug memory management */ - /* * Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ unsigned long usbvideo_kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = page_address(vmalloc_to_page(va)); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); return ret; } void *usbvideo_rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (!mem) return NULL; @@ -93,13 +86,9 @@ memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = usbvideo_kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; @@ -107,23 +96,16 @@ void usbvideo_rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - adr=(unsigned long) mem; - while (size > 0) { - page = usbvideo_kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + adr = (unsigned long) mem; + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree(mem); } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/usb/vicam.c linux-2.5/drivers/usb/vicam.c --- linux-2.5.5/drivers/usb/vicam.c Wed Feb 20 02:11:00 2002 +++ linux-2.5/drivers/usb/vicam.c Tue Feb 26 21:24:49 2002 @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include #include #include @@ -91,83 +93,25 @@ * ******************************************************************************/ -/* [DaveM] I've recoded most of this so that: - * 1) It's easier to tell what is happening - * 2) It's more portable, especially for translating things - * out of vmalloc mapped areas in the kernel. - * 3) Less unnecessary translations happen. - * - * The code used to assume that the kernel vmalloc mappings - * existed in the page tables of every process, this is simply - * not guarenteed. We now use pgd_offset_k which is the - * defined way to get at the kernel page tables. - */ - -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - preempt_disable(); - ptep = pte_offset_map(pmd, adr); - pte = *ptep; - pte_unmap(pte); - preempt_enable(); - if(pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - - } - } - } - return ret; -} - -static inline unsigned long uvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - - kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); - ret = virt_to_bus((void *)kva); - return ret; -} - -static inline unsigned long kvirt_to_bus(unsigned long adr) -{ - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); - ret = virt_to_bus((void *)kva); - return ret; -} - /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); return ret; } -static void * rvmalloc(signed long size) +static void * rvmalloc(unsigned long size) { void * mem; - unsigned long adr, page; + unsigned long adr; + size=PAGE_ALIGN(size); mem=vmalloc_32(size); if (mem) { @@ -175,8 +119,7 @@ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -184,17 +127,16 @@ return mem; } -static void rvfree(void * mem, signed long size) +static void rvfree(void * mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (mem) { adr=(unsigned long) mem; - while (size > 0) + while ((long) size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/video/Config.help linux-2.5/drivers/video/Config.help --- linux-2.5.5/drivers/video/Config.help Wed Feb 20 02:10:58 2002 +++ linux-2.5/drivers/video/Config.help Fri Mar 1 15:07:38 2002 @@ -516,6 +516,19 @@ Please read the file Documentation/fb/README-sstfb.txt for supported options and other important info support. +CONFIG_FB_TRIDENT + This driver is supposed to support graphics boards with the + Trident CyberXXXX/Image/CyberBlade chips mostly found in laptops + but also on some motherboards. For more information, read + + + Say Y if you have such a graphics board. + + The driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called rivafb.o. If you want to compile it as a + module, say M here and read . + CONFIG_FB_SBUS Say Y if you want support for SBUS or UPA based frame buffer device. @@ -573,6 +586,12 @@ CONFIG_FB_IMSTT The IMS Twin Turbo is a PCI-based frame buffer card bundled with many Macintosh and compatible computers. + +CONFIG_FB_TX3912 + The TX3912 is a Toshiba RISC processor based on the MIPS 3900 core; + see . + + Say Y here to enable kernel support for the on-board framebuffer. CONFIG_FB_VIRTUAL This is a `virtual' frame buffer device. It operates on a chunk of diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/video/Config.in linux-2.5/drivers/video/Config.in --- linux-2.5.5/drivers/video/Config.in Wed Feb 20 02:11:03 2002 +++ linux-2.5/drivers/video/Config.in Tue Feb 26 01:23:17 2002 @@ -26,6 +26,9 @@ fi fi fi + if [ "$CONFIG_PCI" = "y" ]; then + tristate ' Permedia3 support (EXPERIMENTAL)' CONFIG_FB_PM3 + fi fi if [ "$CONFIG_ARCH_ACORN" = "y" ]; then bool ' Acorn VIDC support' CONFIG_FB_ACORN @@ -146,6 +149,7 @@ tristate ' NeoMagic display support (EXPERIMENTAL)' CONFIG_FB_NEOMAGIC tristate ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX tristate ' 3Dfx Voodoo Graphics (sst1) support (EXPERIMENTAL)' CONFIG_FB_VOODOO1 + tristate ' Trident support (EXPERIMENTAL)' CONFIG_FB_TRIDENT fi fi if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then @@ -263,6 +267,7 @@ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ + "$CONFIG_FB_PM3" = "y" -o \ "$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \ "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \ @@ -283,6 +288,7 @@ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ + "$CONFIG_FB_PM3" = "m" -o \ "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \ @@ -302,6 +308,7 @@ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ + "$CONFIG_FB_PM3" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \ @@ -318,6 +325,7 @@ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \ + "$CONFIG_FB_PM3" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ @@ -348,6 +356,7 @@ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ + "$CONFIG_FB_PM3" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ "$CONFIG_FB_RADEON" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \ @@ -360,6 +369,7 @@ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ + "$CONFIG_FB_PM3" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_3DFX" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ @@ -367,6 +377,13 @@ define_tristate CONFIG_FBCON_CFB32 m fi fi + if [ "$CONFIG_FB_NEOMAGIC" = "y" ]; then + define_tristate CONFIG_FBCON_ACCEL y + else + if [ "$CONFIG_FB_NEOMAGIC" = "m" ]; then + define_tristate CONFIG_FBCON_ACCEL m + fi + fi if [ "$CONFIG_FB_AMIGA" = "y" ]; then define_tristate CONFIG_FBCON_AFB y define_tristate CONFIG_FBCON_ILBM y diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/video/Makefile linux-2.5/drivers/video/Makefile --- linux-2.5.5/drivers/video/Makefile Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/video/Makefile Mon Feb 25 22:08:53 2002 @@ -10,11 +10,11 @@ # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. export-objs := fbmem.o fbcmap.o fbcon.o fbmon.o modedb.o \ - fbcon-afb.o fbcon-ilbm.o \ + fbgen.o fbcon-afb.o fbcon-ilbm.o \ fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \ fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \ fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \ - fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \ + fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o fbcon-accel.o \ cyber2000fb.o sa1100fb.o fbcon-hga.o # Each configuration option enables a list of files. @@ -35,7 +35,7 @@ obj-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o # Add fbmon.o back into obj-$(CONFIG_FB) in 2.5.x -obj-$(CONFIG_FB) += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o +obj-$(CONFIG_FB) += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o fbgen.o # Only include macmodes.o if we have FB support and are PPC ifeq ($(CONFIG_FB),y) obj-$(CONFIG_PPC) += macmodes.o @@ -43,7 +43,8 @@ obj-$(CONFIG_FB_ACORN) += acornfb.o obj-$(CONFIG_FB_AMIGA) += amifb.o -obj-$(CONFIG_FB_PM2) += pm2fb.o fbgen.o +obj-$(CONFIG_FB_PM2) += pm2fb.o +obj-$(CONFIG_FB_PM3) += pm3fb.o obj-$(CONFIG_FB_APOLLO) += dnfb.o obj-$(CONFIG_FB_Q40) += q40fb.o obj-$(CONFIG_FB_ATARI) += atafb.o @@ -64,9 +65,10 @@ obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_IMSTT) += imsttfb.o obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o -obj-$(CONFIG_FB_CLGEN) += clgenfb.o fbgen.o +obj-$(CONFIG_FB_CLGEN) += clgenfb.o +obj-$(CONFIG_FB_TRIDENT) += tridentfb.o obj-$(CONFIG_FB_S3TRIO) += S3triofb.o -obj-$(CONFIG_FB_TGA) += tgafb.o fbgen.o +obj-$(CONFIG_FB_TGA) += tgafb.o obj-$(CONFIG_FB_VESA) += vesafb.o obj-$(CONFIG_FB_VGA16) += vga16fb.o fbcon-vga-planes.o obj-$(CONFIG_FB_VIRGE) += virgefb.o @@ -80,7 +82,7 @@ obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o -obj-$(CONFIG_FB_STI) += stifb.o sticore.o fbgen.o +obj-$(CONFIG_FB_STI) += stifb.o sticore.o obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o obj-$(CONFIG_FB_MAXINE) += maxinefb.o @@ -109,11 +111,11 @@ obj-$(CONFIG_FB_SUN3) += sun3fb.o obj-$(CONFIG_FB_BWTWO) += bwtwofb.o -obj-$(CONFIG_FB_HGA) += hgafb.o +obj-$(CONFIG_FB_HGA) += hgafb.o obj-$(CONFIG_FB_SA1100) += sa1100fb.o obj-$(CONFIG_FB_VIRTUAL) += vfb.o -obj-$(CONFIG_FB_HIT) += hitfb.o fbgen.o -obj-$(CONFIG_FB_E1355) += epson1355fb.o fbgen.o +obj-$(CONFIG_FB_HIT) += hitfb.o +obj-$(CONFIG_FB_E1355) += epson1355fb.o obj-$(CONFIG_FB_PVR2) += pvr2fb.o obj-$(CONFIG_FB_VOODOO1) += sstfb.o @@ -136,6 +138,7 @@ obj-$(CONFIG_FBCON_VGA) += fbcon-vga.o obj-$(CONFIG_FBCON_HGA) += fbcon-hga.o obj-$(CONFIG_FBCON_STI) += fbcon-sti.o +obj-$(CONFIG_FBCON_ACCEL) += fbcon-accel.o include $(TOPDIR)/Rules.make diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/video/S3triofb.c linux-2.5/drivers/video/S3triofb.c --- linux-2.5.5/drivers/video/S3triofb.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/video/S3triofb.c Sat Jan 26 00:14:25 2002 @@ -60,7 +60,6 @@ #define IO_OUT16VAL(v, r) (((v) << 8) | (r)) -static int currcon = 0; static struct display disp; static struct fb_info fb_info; static struct { u_char red, green, blue, pad; } palette[256]; @@ -84,11 +83,11 @@ struct fb_info *info); static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); -static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); +static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); static int s3trio_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info); - +static int s3triofb_blank(int blank, struct fb_info *info); /* * Interface to the low level console driver @@ -97,10 +96,6 @@ int s3triofb_init(void); static int s3triofbcon_switch(int con, struct fb_info *info); static int s3triofbcon_updatevar(int con, struct fb_info *info); -static void s3triofbcon_blank(int blank, struct fb_info *info); -#if 0 -static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con); -#endif /* * Text console acceleration @@ -130,10 +125,6 @@ static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); -static void do_install_cmap(int con, struct fb_info *info); - static struct fb_ops s3trio_ops = { owner: THIS_MODULE, @@ -141,8 +132,10 @@ fb_get_var: s3trio_get_var, fb_set_var: s3trio_set_var, fb_get_cmap: s3trio_get_cmap, - fb_set_cmap: s3trio_set_cmap, + fb_set_cmap: fbgen_set_cmap, + fb_setcolreg: s3trio_setcolreg, fb_pan_display: s3trio_pan_display, + fb_blank: s3triofb_blank, }; /* @@ -227,7 +220,7 @@ static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - if (con == currcon) /* current console? */ + if (con == info->currcon) /* current console? */ return fb_get_cmap(cmap, kspc, s3trio_getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); @@ -237,29 +230,6 @@ return 0; } - /* - * Set the Colormap - */ - -static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - int err; - - - if (!fb_display[con].cmap.len) { /* no colormap allocated? */ - if ((err = fb_alloc_cmap(&fb_display[con].cmap, - 1<full_name, sizeof(fb_info.modename)); fb_info.node = NODEV; fb_info.fbops = &s3trio_ops; + fb_info.screen_base = s3trio_base; #if 0 fb_info.fbvar_num = 1; fb_info.fbvar = &fb_var; @@ -565,7 +535,6 @@ fb_info.changevar = NULL; fb_info.switch_con = &s3triofbcon_switch; fb_info.updatevar = &s3triofbcon_updatevar; - fb_info.blank = &s3triofbcon_blank; #if 0 fb_info.setcmap = &s3triofbcon_setcmap; #endif @@ -598,10 +567,10 @@ static int s3triofbcon_switch(int con, struct fb_info *info) { /* Do we have to save the colormap? */ - if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, 1, s3trio_getcolreg, info); + if (fb_display[info->currcon].cmap.len) + fb_get_cmap(&fb_display[info->currcon].cmap, 1, s3trio_getcolreg, info); - currcon = con; + info->currcon = con; /* Install new colormap */ do_install_cmap(con,info); return 0; @@ -621,13 +590,14 @@ * Blank the display. */ -static void s3triofbcon_blank(int blank, struct fb_info *info) +static int s3triofb_blank(int blank, struct fb_info *info) { unsigned char x; mem_out8(0x1, s3trio_base+0x1008000 + 0x03c4); x = mem_in8(s3trio_base+0x1008000 + 0x03c5); mem_out8((x & (~0x20)) | (blank << 5), s3trio_base+0x1008000 + 0x03c5); + return 0; } /* @@ -683,18 +653,6 @@ mem_out8((blue & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9); return 0; -} - - -static void do_install_cmap(int con, struct fb_info *info) -{ - if (con != currcon) - return; - if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, s3trio_setcolreg, &fb_info); - else - fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), 1, - s3trio_setcolreg, &fb_info); } static void Trio_WaitQueue(u_short fifo) { diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/video/acornfb.c linux-2.5/drivers/video/acornfb.c --- linux-2.5.5/drivers/video/acornfb.c Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/video/acornfb.c Sat Jan 26 00:14:25 2002 @@ -737,7 +737,7 @@ u_int trans, struct fb_info *info) { union palette pal; - int bpp = fb_display[current_par.currcon].var.bits_per_pixel; + int bpp = fb_display[info->currcon].var.bits_per_pixel; if (regno >= current_par.palette_size) return 1; @@ -780,7 +780,7 @@ { int err = 0; - if (con == current_par.currcon) + if (con == info->currcon) err = fb_get_cmap(cmap, kspc, acornfb_getcolreg, info); else if (fb_display[con].cmap.len) fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); @@ -800,9 +800,8 @@ err = fb_alloc_cmap(&fb_display[con].cmap, current_par.palette_size, 0); if (!err) { - if (con == current_par.currcon) - err = fb_set_cmap(cmap, kspc, acornfb_setcolreg, - info); + if (con == info->currcon) + err = fb_set_cmap(cmap, kspc, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); @@ -1037,7 +1036,7 @@ break; } - display->screen_base = (char *)current_par.screen_base; + info->screen_base = (char *)current_par.screen_base; display->type = FB_TYPE_PACKED_PIXELS; display->type_aux = 0; display->ypanstep = 1; @@ -1050,7 +1049,7 @@ if (chgvar && info && info->changevar) info->changevar(con); - if (con == current_par.currcon) { + if (con == info->currcon) { struct fb_cmap *cmap; unsigned long start, size; int control; @@ -1087,7 +1086,7 @@ else cmap = fb_default_cmap(current_par.palette_size); - fb_set_cmap(cmap, 1, acornfb_setcolreg, info); + fb_set_cmap(cmap, 1, info); } return 0; } @@ -1166,14 +1165,16 @@ fb_set_var: acornfb_set_var, fb_get_cmap: acornfb_get_cmap, fb_set_cmap: acornfb_set_cmap, + fb_setcolreg: acornfb_setcolreg, fb_pan_display: acornfb_pan_display, + fb_blank: acornfb_blank, fb_mmap: acornfb_mmap, }; static int acornfb_updatevar(int con, struct fb_info *info) { - if (con == current_par.currcon) + if (con == info->currcon) acornfb_update_dma(&fb_display[con].var); return 0; @@ -1184,14 +1185,14 @@ { struct fb_cmap *cmap; - if (current_par.currcon >= 0) { - cmap = &fb_display[current_par.currcon].cmap; + if (info->currcon >= 0) { + cmap = &fb_display[info->currcon].cmap; if (cmap->len) fb_get_cmap(cmap, 1, acornfb_getcolreg, info); } - current_par.currcon = con; + info->currcon = con; fb_display[con].var.activate = FB_ACTIVATE_NOW; @@ -1200,11 +1201,11 @@ return 0; } -static void +static int acornfb_blank(int blank, struct fb_info *info) { union palette p; - int i, bpp = fb_display[current_par.currcon].var.bits_per_pixel; + int i, bpp = fb_display[info->currcon].var.bits_per_pixel; #ifdef FBCON_HAS_CFB16 if (bpp == 16) { @@ -1232,6 +1233,7 @@ acornfb_palette_write(i, p); } } + return 0; } /* @@ -1324,7 +1326,6 @@ fb_info.changevar = NULL; fb_info.switch_con = acornfb_switch; fb_info.updatevar = acornfb_updatevar; - fb_info.blank = acornfb_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; global_disp.dispsw = &fbcon_dummy; @@ -1635,7 +1636,7 @@ } } - current_par.currcon = -1; + fb_info.currcon = -1; current_par.screen_base = SCREEN_BASE; current_par.screen_base_p = SCREEN_START; current_par.using_vram = 0; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/video/acornfb.h linux-2.5/drivers/video/acornfb.h --- linux-2.5.5/drivers/video/acornfb.h Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/video/acornfb.h Wed Jan 16 20:56:13 2002 @@ -55,7 +55,6 @@ unsigned int vram_half_sam; unsigned int palette_size; signed int montype; - signed int currcon; unsigned int using_vram : 1; unsigned int dpms : 1; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/video/amifb.c linux-2.5/drivers/video/amifb.c --- linux-2.5.5/drivers/video/amifb.c Wed Feb 20 02:10:59 2002 +++ linux-2.5/drivers/video/amifb.c Mon Feb 18 20:50:38 2002 @@ -739,8 +739,6 @@ u_short fmode; /* vmode */ } currentpar; -static int currcon = 0; - static struct display disp; static struct fb_info fb_info; @@ -1100,8 +1098,10 @@ struct fb_info *info); static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); -static int amifb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); +static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static void ami_update_display(void); +static int amifb_blank(int blank, struct fb_info *info); static int amifb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con, struct fb_info *info); @@ -1121,18 +1121,15 @@ static void amifb_deinit(void); static int amifbcon_switch(int con, struct fb_info *info); static int amifbcon_updatevar(int con, struct fb_info *info); -static void amifbcon_blank(int blank, struct fb_info *info); /* * Internal routines */ -static void do_install_cmap(int con, struct fb_info *info); static int flash_cursor(void); static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp); static u_long chipalloc(u_long size); static void chipfree(void); -static char *strtoke(char *s,const char *ct); /* * Hardware routines @@ -1153,8 +1150,6 @@ static int ami_update_par(void); static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); -static int ami_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); static void ami_update_display(void); static void ami_init_display(void); static void ami_do_blank(void); @@ -1176,8 +1171,10 @@ fb_get_var: amifb_get_var, fb_set_var: amifb_set_var, fb_get_cmap: amifb_get_cmap, - fb_set_cmap: amifb_set_cmap, + fb_set_cmap: fbgen_set_cmap, + fb_setcolreg: amifb_setcolreg, fb_pan_display: amifb_pan_display, + fb_blank: amifb_blank, fb_ioctl: amifb_ioctl, }; @@ -1224,22 +1221,22 @@ * horizontal freq. in kHz */ - if (!(p = strtoke(mcap_spec, ";")) || !*p) + if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid; vmin = simple_strtoul(p, NULL, 10); if (vmin <= 0) goto cap_invalid; - if (!(p = strtoke(NULL, ";")) || !*p) + if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid; vmax = simple_strtoul(p, NULL, 10); if (vmax <= 0 || vmax <= vmin) goto cap_invalid; - if (!(p = strtoke(NULL, ";")) || !*p) + if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid; hmin = 1000 * simple_strtoul(p, NULL, 10); if (hmin <= 0) goto cap_invalid; - if (!(p = strtoke(NULL, "")) || !*p) + if (!(p = strsep(&mcap_spec, "")) || !*p) goto cap_invalid; hmax = 1000 * simple_strtoul(p, NULL, 10); if (hmax <= 0 || hmax <= hmin) @@ -1337,7 +1334,6 @@ struct fb_fix_screeninfo fix; ami_encode_fix(&fix, &par); - display->screen_base = (char *)videomemory; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; @@ -1373,7 +1369,7 @@ return err; do_install_cmap(con, info); } - if (con == currcon) + if (con == info->currcon) ami_set_var(&display->var); } return 0; @@ -1400,7 +1396,7 @@ var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual) return -EINVAL; } - if (con == currcon) + if (con == info->currcon) ami_pan_var(var); fb_display[con].var.xoffset = var->xoffset; fb_display[con].var.yoffset = var->yoffset; @@ -1418,7 +1414,7 @@ static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - if (con == currcon) /* current console? */ + if (con == info->currcon) /* current console? */ return fb_get_cmap(cmap, kspc, ami_getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); @@ -1429,28 +1425,6 @@ } /* - * Set the Colormap - */ - -static int amifb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - int err; - - if (!fb_display[con].cmap.len) { /* no colormap allocated? */ - if ((err = fb_alloc_cmap(&fb_display[con].cmap, - 1<currcon].cmap.len) + fb_get_cmap(&fb_display[info->currcon].cmap, 1, ami_getcolreg, info); - currcon = con; + info->currcon = con; ami_set_var(&fb_display[con].var); /* Install new colormap */ do_install_cmap(con, info); @@ -1844,24 +1819,10 @@ * Blank the display. */ -static void amifbcon_blank(int blank, struct fb_info *info) +static int amifb_blank(int blank, struct fb_info *info) { do_blank = blank ? blank : -1; -} - - /* - * Set the colormap - */ - -static void do_install_cmap(int con, struct fb_info *info) -{ - if (con != currcon) - return; - if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, ami_setcolreg, info); - else - fb_set_cmap(fb_default_cmap(1< 255) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/video/atafb.c linux-2.5/drivers/video/atafb.c --- linux-2.5.5/drivers/video/atafb.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/video/atafb.c Mon Feb 18 20:50:38 2002 @@ -173,8 +173,6 @@ static int current_par_valid=0; -static int currcon=0; - static int mono_moni=0; static struct display disp; @@ -285,13 +283,6 @@ * void (*set_par)( struct atafb_par *par ) * Set the hardware according to 'par'. * - * int (*setcolreg)( unsigned regno, unsigned red, - * unsigned green, unsigned blue, - * unsigned transp, struct fb_info *info ) - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - * * int (*getcolreg)( unsigned regno, unsigned *red, * unsigned *green, unsigned *blue, * unsigned *transp, struct fb_info *info ) @@ -324,9 +315,6 @@ int (*getcolreg)( unsigned regno, unsigned *red, unsigned *green, unsigned *blue, unsigned *transp, struct fb_info *info ); - int (*setcolreg)( unsigned regno, unsigned red, - unsigned green, unsigned blue, - unsigned transp, struct fb_info *info ); void (*set_screen_base)(void *s_base); int (*blank)( int blank_mode ); int (*pan_display)( struct fb_var_screeninfo *var, @@ -1597,7 +1585,7 @@ struct atafb_par *par ) { int xoffset; - int bpp = fb_display[currcon].var.bits_per_pixel; + int bpp = fb_display[fb_info.currcon].var.bits_per_pixel; if (bpp == 1) var->xoffset = up(var->xoffset, 32); @@ -1608,13 +1596,13 @@ var->xoffset = up(var->xoffset, 2); } par->hw.falcon.line_offset = bpp * - (fb_display[currcon].var.xres_virtual - fb_display[currcon].var.xres) / 16; + (fb_display[fb_info.currcon].var.xres_virtual - fb_display[fb_info.currcon].var.xres) / 16; if (par->hw.falcon.xoffset) par->hw.falcon.line_offset -= bpp; xoffset = var->xoffset - par->hw.falcon.xoffset; par->screen_base = screen_base + - (var->yoffset * fb_display[currcon].var.xres_virtual + xoffset) * bpp / 8; + (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + xoffset) * bpp / 8; if (fbhw->set_screen_base) fbhw->set_screen_base (par->screen_base); else @@ -2313,8 +2301,8 @@ return -EINVAL; var->xoffset = up(var->xoffset, 16); par->screen_base = screen_base + - (var->yoffset * fb_display[currcon].var.xres_virtual + var->xoffset) - * fb_display[currcon].var.bits_per_pixel / 8; + (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + var->xoffset) + * fb_display[fb_info.currcon].var.bits_per_pixel / 8; fbhw->set_screen_base (par->screen_base); return 0; } @@ -2326,7 +2314,7 @@ #ifdef ATAFB_TT static struct fb_hwswitch tt_switch = { tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var, - tt_get_par, tt_set_par, tt_getcolreg, tt_setcolreg, + tt_get_par, tt_set_par, tt_getcolreg, set_screen_base, NULL, pan_display }; #endif @@ -2335,14 +2323,14 @@ static struct fb_hwswitch falcon_switch = { falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var, falcon_get_par, falcon_set_par, falcon_getcolreg, - falcon_setcolreg, set_screen_base, falcon_blank, falcon_pan_display + set_screen_base, falcon_blank, falcon_pan_display }; #endif #ifdef ATAFB_STE static struct fb_hwswitch st_switch = { stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var, - stste_get_par, stste_set_par, stste_getcolreg, stste_setcolreg, + stste_get_par, stste_set_par, stste_getcolreg, stste_set_screen_base, NULL, pan_display }; #endif @@ -2350,7 +2338,7 @@ #ifdef ATAFB_EXT static struct fb_hwswitch ext_switch = { ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var, - ext_get_par, ext_set_par, ext_getcolreg, ext_setcolreg, NULL, NULL, NULL + ext_get_par, ext_set_par, ext_getcolreg, NULL, NULL, NULL }; #endif @@ -2410,20 +2398,6 @@ return 0; } -/* Functions for handling colormap */ - -static void -do_install_cmap(int con, struct fb_info *info) -{ - if (con != currcon) - return; - if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, fbhw->setcolreg, info); - else - fb_set_cmap(fb_default_cmap(1<setcolreg, info); -} - static int atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) { @@ -2468,7 +2442,7 @@ atafb_get_var(&var, con, info); if (con == -1) con=0; - display->screen_base = (void *)fix.smem_start; + fb_info->screen_base = (void *)fix.smem_start; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; @@ -2530,7 +2504,7 @@ { int err,oldxres,oldyres,oldbpp,oldxres_virtual, oldyres_virtual,oldyoffset; - if ((err=do_fb_set_var(var, con==currcon))) + if ((err=do_fb_set_var(var, con==info->currcon))) return err; if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { oldxres=fb_display[con].var.xres; @@ -2560,7 +2534,7 @@ static int atafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - if (con == currcon) /* current console ? */ + if (con == info->currcon) /* current console ? */ return fb_get_cmap(cmap, kspc, fbhw->getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap ? */ @@ -2572,23 +2546,6 @@ } static int -atafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) -{ - int err; - if (! fb_display[con].cmap.len) { /* no colormap allocated ? */ - if ((err = fb_alloc_cmap(&fb_display[con].cmap, - 1 << fb_display[con].var.bits_per_pixel, - 0))) - return err; - } - if (con == currcon) /* current console ? */ - return fb_set_cmap(cmap, kspc, fbhw->setcolreg, info); - else - fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); - return 0; -} - -static int atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info) { int xoffset = var->xoffset; @@ -2599,7 +2556,7 @@ || yoffset < 0 || yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual) return -EINVAL; - if (con == currcon) { + if (con == info->currcon) { if (fbhw->pan_display) { if ((err = fbhw->pan_display(var, ¤t_par))) return err; @@ -2642,8 +2599,9 @@ fb_get_var: atafb_get_var, fb_set_var: atafb_set_var, fb_get_cmap: atafb_get_cmap, - fb_set_cmap: atafb_set_cmap, + fb_set_cmap: fbgen_set_cmap, fb_pan_display: atafb_pan_display, + fb_blank: atafb_blank, fb_ioctl: atafb_ioctl, }; @@ -2692,11 +2650,11 @@ atafb_switch(int con, struct fb_info *info) { /* Do we have to save the colormap ? */ - if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, 1, fbhw->getcolreg, + if (fb_display[info->currcon].cmap.len) + fb_get_cmap(&fb_display[info->currcon].cmap, 1, fbhw->getcolreg, info); do_fb_set_var(&fb_display[con].var,1); - currcon=con; + info->currcon=con; /* Install new colormap */ do_install_cmap(con, info); return 0; @@ -2709,7 +2667,7 @@ * 3 = suspend hsync * 4 = off */ -static void +static int atafb_blank(int blank, struct fb_info *info) { unsigned short black[16]; @@ -2724,10 +2682,11 @@ cmap.transp=NULL; cmap.start=0; cmap.len=16; - fb_set_cmap(&cmap, 1, fbhw->setcolreg, info); + fb_set_cmap(&cmap, 1, info); } else - do_install_cmap(currcon, info); + do_install_cmap(info->currcon, info); + return 0; } int __init atafb_init(void) @@ -2743,18 +2702,21 @@ #ifdef ATAFB_EXT if (external_addr) { fbhw = &ext_switch; + fb_info.fb_setcolreg = &ext_setcolreg; break; } #endif #ifdef ATAFB_TT if (ATARIHW_PRESENT(TT_SHIFTER)) { fbhw = &tt_switch; + fb_info.fb_setcolreg = &tt_setcolreg; break; } #endif #ifdef ATAFB_FALCON if (ATARIHW_PRESENT(VIDEL_SHIFTER)) { fbhw = &falcon_switch; + fb_info.fb_setcolreg = &falcon_setcolreg; request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, "framebuffer/modeswitch", falcon_vbl_switcher); break; @@ -2764,9 +2726,11 @@ if (ATARIHW_PRESENT(STND_SHIFTER) || ATARIHW_PRESENT(EXTD_SHIFTER)) { fbhw = &st_switch; + fb_info.fb_setcolreg = &stste_setcolreg; break; } fbhw = &st_switch; + fb_info.fb_setcolreg = &stste_setcolreg; printk("Cannot determine video hardware; defaulting to ST(e)\n"); #else /* ATAFB_STE */ /* no default driver included */ @@ -2833,7 +2797,6 @@ fb_info.disp = &disp; fb_info.switch_con = &atafb_switch; fb_info.updatevar = &fb_update_var; - fb_info.blank = &atafb_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; do_fb_set_var(&atafb_predefined[default_par-1], 1); strcat(fb_info.modename, fb_var_names[default_par-1][0]); @@ -2860,28 +2823,6 @@ return 0; } -/* a strtok which returns empty strings, too */ - -static char * strtoke(char * s,const char * ct) -{ - char *sbegin, *send; - static char *ssave = NULL; - - sbegin = s ? s : ssave; - if (!sbegin) { - return NULL; - } - if (*sbegin == '\0') { - ssave = NULL; - return NULL; - } - send = strpbrk(sbegin, ct); - if (send && *send != '\0') - *send++ = '\0'; - ssave = send; - return sbegin; -} - int __init atafb_setup( char *options ) { char *this_opt; @@ -2899,7 +2840,7 @@ if (!options || !*options) return 0; - for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) { + while ((this_opt = strsep(&options, ",")) != NULL) { if (!*this_opt) continue; if ((temp=get_video_mode(this_opt))) default_par=temp; @@ -2956,18 +2897,18 @@ int xres; char *p; - if (!(p = strtoke(int_str, ";")) ||!*p) goto int_invalid; + if (!(p = strsep(&int_str, ";")) || !*p) goto int_invalid; xres = simple_strtoul(p, NULL, 10); - if (!(p = strtoke(NULL, ";")) || !*p) goto int_invalid; + if (!(p = strsep(&int_str, ";")) || !*p) goto int_invalid; sttt_xres=xres; tt_yres=st_yres=simple_strtoul(p, NULL, 10); - if ((p=strtoke(NULL, ";")) && *p) { + if ((p=strsep(&int_str, ";")) && *p) { sttt_xres_virtual=simple_strtoul(p, NULL, 10); } - if ((p=strtoke(NULL, ";")) && *p) { + if ((p=strsep(&int_str, ";")) && *p) { sttt_yres_virtual=simple_strtoul(p, NULL, 0); } - if ((p=strtoke(NULL, ";")) && *p) { + if ((p=strsep(&int_str, ";")) && *p) { ovsc_offset=simple_strtoul(p, NULL, 0); } @@ -2993,20 +2934,20 @@ * * Even xres_virtual is available, we neither support panning nor hw-scrolling! */ - if (!(p = strtoke(ext_str, ";")) ||!*p) goto ext_invalid; + if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid; xres_virtual = xres = simple_strtoul(p, NULL, 10); if (xres <= 0) goto ext_invalid; - if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid; + if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid; yres = simple_strtoul(p, NULL, 10); if (yres <= 0) goto ext_invalid; - if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid; + if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid; depth = simple_strtoul(p, NULL, 10); if (depth != 1 && depth != 2 && depth != 4 && depth != 8 && depth != 16 && depth != 24) goto ext_invalid; - if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid; + if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid; if (*p == 'i') planes = FB_TYPE_INTERLEAVED_PLANES; else if (*p == 'p') @@ -3019,19 +2960,19 @@ goto ext_invalid; - if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid; + if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid; addr = simple_strtoul(p, NULL, 0); - if (!(p = strtoke(NULL, ";")) ||!*p) + if (!(p = strsep(&ext_str, ";")) || !*p) len = xres*yres*depth/8; else len = simple_strtoul(p, NULL, 0); - if ((p = strtoke(NULL, ";")) && *p) { + if ((p = strsep(&ext_str, ";")) && *p) { external_vgaiobase=simple_strtoul(p, NULL, 0); } - if ((p = strtoke(NULL, ";")) && *p) { + if ((p = strsep(&ext_str, ";")) && *p) { external_bitspercol = simple_strtoul(p, NULL, 0); if (external_bitspercol > 8) external_bitspercol = 8; @@ -3039,14 +2980,14 @@ external_bitspercol = 1; } - if ((p = strtoke(NULL, ";")) && *p) { + if ((p = strsep(&ext_str, ";")) && *p) { if (!strcmp(p, "vga")) external_card_type = IS_VGA; if (!strcmp(p, "mv300")) external_card_type = IS_MV300; } - if ((p = strtoke(NULL, ";")) && *p) { + if ((p = strsep(&ext_str, ";")) && *p) { xres_virtual = simple_strtoul(p, NULL, 10); if (xres_virtual < xres) xres_virtual = xres; @@ -3089,16 +3030,16 @@ * vertical freq. in Hz * horizontal freq. in kHz */ - if (!(p = strtoke(mcap_spec, ";")) || !*p) goto cap_invalid; + if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid; vmin = simple_strtoul(p, NULL, 10); if (vmin <= 0) goto cap_invalid; - if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid; + if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid; vmax = simple_strtoul(p, NULL, 10); if (vmax <= 0 || vmax <= vmin) goto cap_invalid; - if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid; + if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid; hmin = 1000 * simple_strtoul(p, NULL, 10); if (hmin <= 0) goto cap_invalid; - if (!(p = strtoke(NULL, "")) || !*p) goto cap_invalid; + if (!(p = strsep(&mcap_spec, "")) || !*p) goto cap_invalid; hmax = 1000 * simple_strtoul(p, NULL, 10); if (hmax <= 0 || hmax <= hmin) goto cap_invalid; @@ -3117,11 +3058,11 @@ char *p; int xres, yres, depth, temp; - if (!(p = strtoke(user_mode, ";")) || !*p) goto user_invalid; + if (!(p = strsep(&user_mode, ";")) || !*p) goto user_invalid; xres = simple_strtoul(p, NULL, 10); - if (!(p = strtoke(NULL, ";")) || !*p) goto user_invalid; + if (!(p = strsep(&user_mode, ";")) || !*p) goto user_invalid; yres = simple_strtoul(p, NULL, 10); - if (!(p = strtoke(NULL, "")) || !*p) goto user_invalid; + if (!(p = strsep(&user_mode, "")) || !*p) goto user_invalid; depth = simple_strtoul(p, NULL, 10); if ((temp=get_video_mode("user0"))) { default_par=temp; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/video/aty/atyfb.h linux-2.5/drivers/video/aty/atyfb.h --- linux-2.5.5/drivers/video/aty/atyfb.h Wed Feb 20 02:10:55 2002 +++ linux-2.5/drivers/video/aty/atyfb.h Sun Jan 20 17:34:03 2002 @@ -112,17 +112,6 @@ const struct aty_pll_ops *pll_ops; struct display disp; struct display_switch dispsw; - union { -#ifdef FBCON_HAS_CFB16 - u16 cfb16[16]; -#endif -#ifdef FBCON_HAS_CFB24 - u32 cfb24[16]; -#endif -#ifdef FBCON_HAS_CFB32 - u32 cfb32[16]; -#endif - } fbcon_cmap; u8 blitter_may_be_busy; #ifdef __sparc__ u8 mmaped; diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/video/aty/atyfb_base.c linux-2.5/drivers/video/aty/atyfb_base.c --- linux-2.5.5/drivers/video/aty/atyfb_base.c Wed Feb 20 02:10:56 2002 +++ linux-2.5/drivers/video/aty/atyfb_base.c Mon Feb 25 18:54:27 2002 @@ -88,6 +88,9 @@ #include #include #endif +#ifdef CONFIG_BOOTX_TEXT +#include +#endif #ifdef CONFIG_NVRAM #include #endif @@ -149,10 +152,11 @@ struct fb_info *fb); static int atyfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *fb); +static int atyfb_blank(int blank, struct fb_info *fb); static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); -static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); +static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *fb); static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con, struct fb_info *info); #ifdef __sparc__ @@ -168,8 +172,6 @@ static int atyfbcon_switch(int con, struct fb_info *fb); static int atyfbcon_updatevar(int con, struct fb_info *fb); -static void atyfbcon_blank(int blank, struct fb_info *fb); - /* * Internal routines @@ -178,7 +180,6 @@ static int aty_init(struct fb_info_aty *info, const char *name); #ifdef CONFIG_ATARI static int store_video_par(char *videopar, unsigned char m64_num); -static char *strtoke(char *s, const char *ct); #endif static void aty_set_crtc(const struct fb_info_aty *info, @@ -206,9 +207,6 @@ int bpp, int accel); static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *fb); -static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *fb); -static void do_install_cmap(int con, struct fb_info *info); #ifdef CONFIG_PPC static int read_aty_sense(const struct fb_info_aty *info); #endif @@ -223,8 +221,6 @@ int atyfb_setup(char*); #endif -static int currcon = 0; - static struct fb_ops atyfb_ops = { owner: THIS_MODULE, fb_open: atyfb_open, @@ -233,8 +229,10 @@ fb_get_var: atyfb_get_var, fb_set_var: atyfb_set_var, fb_get_cmap: atyfb_get_cmap, - fb_set_cmap: atyfb_set_cmap, + fb_set_cmap: fbgen_set_cmap, + fb_setcolreg: atyfb_setcolreg, fb_pan_display: atyfb_pan_display, + fb_blank: atyfb_blank, fb_ioctl: atyfb_ioctl, #ifdef __sparc__ fb_mmap: atyfb_mmap, @@ -251,11 +249,11 @@ static int default_mclk __initdata = 0; #ifndef MODULE -static const char *mode_option __initdata = NULL; +static char *mode_option __initdata = NULL; #endif #ifdef CONFIG_PPC -#ifdef CONFIG_NVRAM_NOT_DEFINED +#ifndef CONFIG_NVRAM static int default_vmode __initdata = VMODE_NVRAM; static int default_cmode __initdata = CMODE_NVRAM; #else @@ -271,31 +269,35 @@ static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, }; #endif -static const char m64n_gx[] __initdata = "mach64GX (ATI888GX00)"; -static const char m64n_cx[] __initdata = "mach64CX (ATI888CX00)"; -static const char m64n_ct[] __initdata = "mach64CT (ATI264CT)"; -static const char m64n_et[] __initdata = "mach64ET (ATI264ET)"; -static const char m64n_vta3[] __initdata = "mach64VTA3 (ATI264VT)"; -static const char m64n_vta4[] __initdata = "mach64VTA4 (ATI264VT)"; -static const char m64n_vtb[] __initdata = "mach64VTB (ATI264VTB)"; -static const char m64n_vt4[] __initdata = "mach64VT4 (ATI264VT4)"; -static const char m64n_gt[] __initdata = "3D RAGE (GT)"; -static const char m64n_gtb[] __initdata = "3D RAGE II+ (GTB)"; -static const char m64n_iic_p[] __initdata = "3D RAGE IIC (PCI)"; -static const char m64n_iic_a[] __initdata = "3D RAGE IIC (AGP)"; -static const char m64n_lt[] __initdata = "3D RAGE LT"; -static const char m64n_ltg[] __initdata = "3D RAGE LT-G"; -static const char m64n_gtc_ba[] __initdata = "3D RAGE PRO (BGA, AGP)"; -static const char m64n_gtc_ba1[] __initdata = "3D RAGE PRO (BGA, AGP, 1x only)"; -static const char m64n_gtc_bp[] __initdata = "3D RAGE PRO (BGA, PCI)"; -static const char m64n_gtc_pp[] __initdata = "3D RAGE PRO (PQFP, PCI)"; -static const char m64n_gtc_ppl[] __initdata = "3D RAGE PRO (PQFP, PCI, limited 3D)"; -static const char m64n_xl[] __initdata = "3D RAGE (XL)"; -static const char m64n_ltp_a[] __initdata = "3D RAGE LT PRO (AGP)"; -static const char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)"; -static const char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)"; -static const char m64n_mob_a[] __initdata = "3D RAGE Mobility (AGP)"; +#ifdef CONFIG_FB_ATY_GX +static char m64n_gx[] __initdata = "mach64GX (ATI888GX00)"; +static char m64n_cx[] __initdata = "mach64CX (ATI888CX00)"; +#endif /* CONFIG_FB_ATY_GX */ +#ifdef CONFIG_FB_ATY_CT +static char m64n_ct[] __initdata = "mach64CT (ATI264CT)"; +static char m64n_et[] __initdata = "mach64ET (ATI264ET)"; +static char m64n_vta3[] __initdata = "mach64VTA3 (ATI264VT)"; +static char m64n_vta4[] __initdata = "mach64VTA4 (ATI264VT)"; +static char m64n_vtb[] __initdata = "mach64VTB (ATI264VTB)"; +static char m64n_vt4[] __initdata = "mach64VT4 (ATI264VT4)"; +static char m64n_gt[] __initdata = "3D RAGE (GT)"; +static char m64n_gtb[] __initdata = "3D RAGE II+ (GTB)"; +static char m64n_iic_p[] __initdata = "3D RAGE IIC (PCI)"; +static char m64n_iic_a[] __initdata = "3D RAGE IIC (AGP)"; +static char m64n_lt[] __initdata = "3D RAGE LT"; +static char m64n_ltg[] __initdata = "3D RAGE LT-G"; +static char m64n_gtc_ba[] __initdata = "3D RAGE PRO (BGA, AGP)"; +static char m64n_gtc_ba1[] __initdata = "3D RAGE PRO (BGA, AGP, 1x only)"; +static char m64n_gtc_bp[] __initdata = "3D RAGE PRO (BGA, PCI)"; +static char m64n_gtc_pp[] __initdata = "3D RAGE PRO (PQFP, PCI)"; +static char m64n_gtc_ppl[] __initdata = "3D RAGE PRO (PQFP, PCI, limited 3D)"; +static char m64n_xl[] __initdata = "3D RAGE (XL)"; +static char m64n_ltp_a[] __initdata = "3D RAGE LT PRO (AGP)"; +static char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)"; +static char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)"; +static char m64n_mob_a[] __initdata = "3D RAGE Mobility (AGP)"; +#endif /* CONFIG_FB_ATY_CT */ static const struct { u16 pci_id, chip_type; @@ -357,29 +359,38 @@ #endif /* CONFIG_FB_ATY_CT */ }; -static const char ram_dram[] __initdata = "DRAM"; -static const char ram_vram[] __initdata = "VRAM"; -static const char ram_edo[] __initdata = "EDO"; -static const char ram_sdram[] __initdata = "SDRAM"; -static const char ram_sgram[] __initdata = "SGRAM"; -static const char ram_wram[] __initdata = "WRAM"; -static const char ram_off[] __initdata = "OFF"; -static const char ram_resv[] __initdata = "RESV"; +#if defined(CONFIG_FB_ATY_GX) || defined(CONFIG_FB_ATY_CT) +static char ram_dram[] __initdata = "DRAM"; +static char ram_resv[] __initdata = "RESV"; +#endif /* CONFIG_FB_ATY_GX || CONFIG_FB_ATY_CT */ + +#ifdef CONFIG_FB_ATY_GX +static char ram_vram[] __initdata = "VRAM"; +#endif /* CONFIG_FB_ATY_GX */ + +#ifdef CONFIG_FB_ATY_CT +static char ram_edo[] __initdata = "EDO"; +static char ram_sdram[] __initdata = "SDRAM"; +static char ram_sgram[] __initdata = "SGRAM"; +static char ram_wram[] __initdata = "WRAM"; +static char ram_off[] __initdata = "OFF"; +#endif /* CONFIG_FB_ATY_CT */ #ifdef CONFIG_FB_ATY_GX -static const char *aty_gx_ram[8] __initdata = { +static char *aty_gx_ram[8] __initdata = { ram_dram, ram_vram, ram_vram, ram_dram, ram_dram, ram_vram, ram_vram, ram_resv }; #endif /* CONFIG_FB_ATY_GX */ #ifdef CONFIG_FB_ATY_CT -static const char *aty_ct_ram[8] __initdata = { +static char *aty_ct_ram[8] __initdata = { ram_off, ram_dram, ram_edo, ram_edo, ram_sdram, ram_sgram, ram_wram, ram_resv }; #endif /* CONFIG_FB_ATY_CT */ +static u32 pseudo_palette[17]; #if defined(CONFIG_PPC) @@ -819,6 +830,13 @@ display_info.disp_reg_address = info->ati_regbase_phys; } #endif /* CONFIG_FB_COMPAT_XPMAC */ +#ifdef CONFIG_BOOTX_TEXT + btext_update_display(info->frame_buffer_phys, + (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8, + ((par->crtc.v_tot_disp>>16) & 0x7ff)+1, + par->crtc.bpp, + par->crtc.vxres*par->crtc.bpp/8); +#endif /* CONFIG_BOOTX_TEXT */ } static int atyfb_decode_var(const struct fb_var_screeninfo *var, @@ -922,7 +940,7 @@ fb->mmaped = 0; if (fb->vtconsole != -1) - vt_cons[fb->vtconsole]->vc_mode = KD_TEXT; + vt_cons->vc_cons[fb->vtconsole]->vc_mode = KD_TEXT; fb->vtconsole = -1; if (was_mmaped) { @@ -1050,21 +1068,21 @@ case 16: info->dispsw = accel ? fbcon_aty16 : fbcon_cfb16; disp->dispsw = &info->dispsw; - disp->dispsw_data = info->fbcon_cmap.cfb16; + disp->dispsw_data = info->fb_info.pseudo_palette; break; #endif #ifdef FBCON_HAS_CFB24 case 24: info->dispsw = accel ? fbcon_aty24 : fbcon_cfb24; disp->dispsw = &info->dispsw; - disp->dispsw_data = info->fbcon_cmap.cfb24; + disp->dispsw_data = info->fb_info.pseudo_palette; break; #endif #ifdef FBCON_HAS_CFB32 case 32: info->dispsw = accel ? fbcon_aty32 : fbcon_cfb32; disp->dispsw = &info->dispsw; - disp->dispsw_data = info->fbcon_cmap.cfb32; + disp->dispsw_data = info->fb_info.pseudo_palette; break; #endif default: @@ -1117,7 +1135,6 @@ struct fb_fix_screeninfo fix; encode_fix(&fix, &par, info); - display->screen_base = (char *)info->frame_buffer; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; @@ -1192,33 +1209,6 @@ return 0; } - /* - * Set the Colormap - */ - -static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - int err; - struct display *disp; - - if (con >= 0) - disp = &fb_display[con]; - else - disp = info->disp; - if (!disp->cmap.len) { /* no colormap allocated? */ - int size = disp->var.bits_per_pixel == 16 ? 32 : 256; - if ((err = fb_alloc_cmap(&disp->cmap, size, 0))) - return err; - } - if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */ - return fb_set_cmap(cmap, kspc, atyfb_setcolreg, info); - else - fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); - return 0; -} - - #ifdef DEBUG #define ATYIO_CLKR 0x41545900 /* ATY\00 */ #define ATYIO_CLKW 0x41545901 /* ATY\01 */ @@ -1414,7 +1404,7 @@ fb->mmaped = 1; if (fb->consolecnt && fb_display[lastconsole].fb_info == info) { fb->vtconsole = lastconsole; - vt_cons[lastconsole]->vc_mode = KD_GRAPHICS; + vt_cons->vc_cons[lastconsole]->vc_mode = KD_GRAPHICS; } } return 0; @@ -1638,6 +1628,8 @@ } break; case PBOOK_SLEEP_NOW: + if (info->fb_info.currcon >= 0) + fb_display[info->fb_info.currcon].dispsw = &fbcon_dummy; if (info->blitter_may_be_busy) wait_for_idle(info); /* Stop accel engine (stop bus mastering) */ @@ -1650,7 +1642,7 @@ (void *)info->frame_buffer, nb); /* Blank display and LCD */ - atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info); + atyfb_blank(VESA_POWERDOWN+1, (struct fb_info *)info); /* Set chip to "suspend" mode */ result = aty_power_mgmt(1, info); @@ -1667,8 +1659,12 @@ info->save_framebuffer = 0; } /* Restore display */ - atyfb_set_par(&info->current_par, info); - atyfbcon_blank(0, (struct fb_info *)info); + if (info->fb_info.currcon >= 0) { + atyfb_set_dispsw(&fb_display[info->fb_info.currcon], + info, info->current_par.crtc.bpp, + info->current_par.accel_flags & FB_ACCELF_TEXT); + } + atyfb_blank(0, (struct fb_info *)info); break; } } @@ -1989,11 +1985,11 @@ info->fb_info.node = NODEV; info->fb_info.fbops = &atyfb_ops; info->fb_info.disp = disp; + info->fb_info.pseudo_palette = pseudo_palette; strcpy(info->fb_info.fontname, fontname); info->fb_info.changevar = NULL; info->fb_info.switch_con = &atyfbcon_switch; info->fb_info.updatevar = &atyfbcon_updatevar; - info->fb_info.blank = &atyfbcon_blank; info->fb_info.flags = FBINFO_FLAG_DEFAULT; #ifdef CONFIG_PMAC_BACKLIGHT @@ -2020,13 +2016,6 @@ if (!mac_find_mode(&var, &info->fb_info, mode_option, 8)) var = default_var; } else { -#ifdef CONFIG_NVRAM - if (default_vmode == VMODE_NVRAM) { - default_vmode = nvram_read_byte(NV_VMODE); - if (default_vmode <= 0 || default_vmode > VMODE_MAX) - default_vmode = VMODE_CHOOSE; - } -#endif if (default_vmode == VMODE_CHOOSE) { if (M64_HAS(G3_PB_1024x768)) /* G3 PowerBook with 1024x768 LCD */ @@ -2139,11 +2128,16 @@ return -ENXIO; #else u16 tmp; + int aux_app; + unsigned long raddr; #endif while ((pdev = pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, pdev))) { if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { struct resource *rp; +#ifndef __sparc__ + struct resource *rrp; +#endif for (i = sizeof(aty_chips)/sizeof(*aty_chips)-1; i >= 0; i--) if (pdev->device == aty_chips[i].pci_id) @@ -2180,7 +2174,7 @@ /* * Map in big-endian aperture. */ - info->frame_buffer = (unsigned long) addr + 0x800000UL; + info->fb_info.screen_base = (unsigned long) addr + 0x800000UL; info->frame_buffer_phys = addr + 0x800000UL; /* @@ -2375,9 +2369,19 @@ } #else /* __sparc__ */ - info->ati_regbase_phys = 0x7ff000 + addr; - info->ati_regbase = (unsigned long) - ioremap(info->ati_regbase_phys, 0x1000); + aux_app = 0; + raddr = addr + 0x7ff000UL; + rrp = &pdev->resource[2]; + if ((rrp->flags & IORESOURCE_MEM) + && request_mem_region(rrp->start, rrp->end - rrp->start + 1, + "atyfb")) { + aux_app = 1; + raddr = rrp->start; + printk(KERN_INFO "atyfb: using auxiliary register aperture\n"); + } + + info->ati_regbase_phys = raddr; + info->ati_regbase = (unsigned long) ioremap(raddr, 0x1000); if(!info->ati_regbase) { kfree(info); @@ -2385,8 +2389,8 @@ return -ENOMEM; } - info->ati_regbase_phys += 0xc00; - info->ati_regbase += 0xc00; + info->ati_regbase_phys += aux_app? 0x400: 0xc00; + info->ati_regbase += aux_app? 0x400: 0xc00; /* * Enable memory-space accesses using config-space @@ -2405,9 +2409,9 @@ /* Map in frame buffer */ info->frame_buffer_phys = addr; - info->frame_buffer = (unsigned long)ioremap(addr, 0x800000); + info->fb_info.screen_base = ioremap(addr, 0x800000); - if(!info->frame_buffer) { + if(!info->fb_info.screen_base) { kfree(info); release_mem_region(res_start, res_size); return -ENXIO; @@ -2431,7 +2435,7 @@ * Add /dev/fb mmap values. */ info->mmap_map[0].voff = 0x8000000000000000UL; - info->mmap_map[0].poff = info->frame_buffer & PAGE_MASK; + info->mmap_map[0].poff = info->fb_info.screen_base & PAGE_MASK; info->mmap_map[0].size = info->total_vram; info->mmap_map[0].prot_mask = _PAGE_CACHE; info->mmap_map[0].prot_flag = _PAGE_E; @@ -2480,7 +2484,7 @@ * Map the video memory (physical address given) to somewhere in the * kernel address space. */ - info->frame_buffer = ioremap(phys_vmembase[m64_num], phys_size[m64_num]); + info->fb_info.screen_base = ioremap(phys_vmembase[m64_num], phys_size[m64_num]); info->frame_buffer_phys = info->frame_buffer; /* Fake! */ info->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000)+0xFC00ul; info->ati_regbase_phys = info->ati_regbase; /* Fake! */ @@ -2522,6 +2526,8 @@ return 0; while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; if (!strncmp(this_opt, "font:", 5)) { char *p; int i; @@ -2595,13 +2601,13 @@ printk("store_video_par() '%s' \n", video_str); - if (!(p = strtoke(video_str, ";")) || !*p) + if (!(p = strsep(&video_str, ";")) || !*p) goto mach64_invalid; vmembase = simple_strtoul(p, NULL, 0); - if (!(p = strtoke(NULL, ";")) || !*p) + if (!(p = strsep(&video_str, ";")) || !*p) goto mach64_invalid; size = simple_strtoul(p, NULL, 0); - if (!(p = strtoke(NULL, ";")) || !*p) + if (!(p = strsep(&video_str, ";")) || !*p) goto mach64_invalid; guiregbase = simple_strtoul(p, NULL, 0); @@ -2616,25 +2622,6 @@ phys_vmembase[m64_num] = 0; return -1; } - -static char __init *strtoke(char *s, const char *ct) -{ - static char *ssave = NULL; - char *sbegin, *send; - - sbegin = s ? s : ssave; - if (!sbegin) - return NULL; - if (*sbegin == '\0') { - ssave = NULL; - return NULL; - } - send = strpbrk(sbegin, ct); - if (send && *send != '\0') - *send++ = '\0'; - ssave = send; - return sbegin; -} #endif /* CONFIG_ATARI */ static int atyfbcon_switch(int con, struct fb_info *fb) @@ -2643,17 +2630,17 @@ struct atyfb_par par; /* Do we have to save the colormap? */ - if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, 1, atyfb_getcolreg, fb); + if (fb_display[fb->currcon].cmap.len) + fb_get_cmap(&fb_display[fb->currcon].cmap, 1, atyfb_getcolreg, fb); #ifdef CONFIG_FB_ATY_CT /* Erase HW Cursor */ if (info->cursor) - atyfb_cursor(&fb_display[currcon], CM_ERASE, + atyfb_cursor(&fb_display[fb->currcon], CM_ERASE, info->cursor->pos.x, info->cursor->pos.y); #endif /* CONFIG_FB_ATY_CT */ - currcon = con; + fb->currcon = con; atyfb_decode_var(&fb_display[con].var, &par, info); atyfb_set_par(&par, info); @@ -2677,7 +2664,7 @@ * Blank the display. */ -static void atyfbcon_blank(int blank, struct fb_info *fb) +static int atyfb_blank(int blank, struct fb_info *fb) { struct fb_info_aty *info = (struct fb_info_aty *)fb; u8 gen_cntl; @@ -2711,6 +2698,7 @@ if ((_machine == _MACH_Pmac) && !blank) set_backlight_enable(1); #endif /* CONFIG_PMAC_BACKLIGHT */ + return 0; } @@ -2768,39 +2756,24 @@ switch (info->current_par.crtc.bpp) { #ifdef FBCON_HAS_CFB16 case 16: - info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | - regno; + ((u16 *)(info->fb_info.pseudo_palette))[regno] = (regno << 10) | (regno << 5) | regno; break; #endif #ifdef FBCON_HAS_CFB24 case 24: - info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | - regno; + ((u32 *)(info->fb_info.pseudo_palette))[regno] = (regno << 16) | (regno << 8) | regno; break; #endif #ifdef FBCON_HAS_CFB32 case 32: i = (regno << 8) | regno; - info->fbcon_cmap.cfb32[regno] = (i << 16) | i; + + ((u32 *)(info->fb_info.pseudo_palette))[regno] = (i << 16) | i; break; #endif } return 0; } - - -static void do_install_cmap(int con, struct fb_info *info) -{ - if (con != currcon) - return; - if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, atyfb_setcolreg, info); - else { - int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_set_cmap(fb_default_cmap(size), 1, atyfb_setcolreg, info); - } -} - /* * Update the `var' structure (called by fbcon.c) diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/video/aty/mach64_cursor.c linux-2.5/drivers/video/aty/mach64_cursor.c --- linux-2.5.5/drivers/video/aty/mach64_cursor.c Wed Feb 20 02:11:05 2002 +++ linux-2.5/drivers/video/aty/mach64_cursor.c Sat Jan 26 00:14:25 2002 @@ -246,14 +246,14 @@ cursor->offset = fb->total_vram; #ifdef __sparc__ - addr = fb->frame_buffer - 0x800000 + cursor->offset; + addr =(unsigned long) fb->fb_info.screen_base - 0x800000 + cursor->offset; cursor->ram = (u8 *)addr; #else #ifdef __BIG_ENDIAN addr = fb->frame_buffer_phys - 0x800000 + cursor->offset; cursor->ram = (u8 *)ioremap(addr, 1024); #else - addr = fb->frame_buffer + cursor->offset; + addr =(unsigned long) fb->fb_info.screen_base + cursor->offset; cursor->ram = (u8 *)addr; #endif #endif diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/video/aty128.h linux-2.5/drivers/video/aty128.h --- linux-2.5.5/drivers/video/aty128.h Wed Feb 20 02:11:01 2002 +++ linux-2.5/drivers/video/aty128.h Tue Jan 8 01:17:10 2002 @@ -13,6 +13,7 @@ #define CLOCK_CNTL_DATA 0x000c #define BIOS_0_SCRATCH 0x0010 #define BUS_CNTL 0x0030 +#define BUS_CNTL1 0x0034 #define GEN_INT_CNTL 0x0040 #define CRTC_GEN_CNTL 0x0050 #define CRTC_EXT_CNTL 0x0054 @@ -24,6 +25,7 @@ #define GEN_RESET_CNTL 0x00f0 #define CONFIG_MEMSIZE 0x00f8 #define MEM_CNTL 0x0140 +#define MEM_POWER_MISC 0x015c #define AGP_BASE 0x0170 #define AGP_CNTL 0x0174 #define AGP_APER_OFFSET 0x0178 @@ -37,6 +39,9 @@ #define CRTC_H_SYNC_STRT_WID 0x0204 #define CRTC_V_TOTAL_DISP 0x0208 #define CRTC_V_SYNC_STRT_WID 0x020c +#define CRTC_VLINE_CRNT_VLINE 0x0210 +#define CRTC_CRNT_FRAME 0x0214 +#define CRTC_GUI_TRIG_VLINE 0x0218 #define CRTC_OFFSET 0x0224 #define CRTC_OFFSET_CNTL 0x0228 #define CRTC_PITCH 0x022c @@ -48,6 +53,20 @@ #define DDA_ON_OFF 0x02e4 #define VGA_DDA_CONFIG 0x02e8 #define VGA_DDA_ON_OFF 0x02ec +#define CRTC2_H_TOTAL_DISP 0x0300 +#define CRTC2_H_SYNC_STRT_WID 0x0304 +#define CRTC2_V_TOTAL_DISP 0x0308 +#define CRTC2_V_SYNC_STRT_WID 0x030c +#define CRTC2_VLINE_CRNT_VLINE 0x0310 +#define CRTC2_CRNT_FRAME 0x0314 +#define CRTC2_GUI_TRIG_VLINE 0x0318 +#define CRTC2_OFFSET 0x0324 +#define CRTC2_OFFSET_CNTL 0x0328 +#define CRTC2_PITCH 0x032c +#define DDA2_CONFIG 0x03e0 +#define DDA2_ON_OFF 0x03e4 +#define CRTC2_GEN_CNTL 0x03f8 +#define CRTC2_STATUS 0x03fc #define OV0_SCALE_CNTL 0x0420 #define SUBPIC_CNTL 0x0540 #define PM4_BUFFER_OFFSET 0x0700 @@ -237,6 +256,10 @@ #define AGP_PLL_CNTL 0x0010 #define FCP_CNTL 0x0012 #define PLL_TEST_CNTL 0x0013 +#define P2PLL_CNTL 0x002a +#define P2PLL_REF_DIV 0x002b +#define P2PLL_DIV_0 0x002b +#define POWER_MANAGEMENT 0x002f #define PPLL_RESET 0x01 #define PPLL_ATOMIC_UPDATE_EN 0x10000 @@ -254,6 +277,14 @@ /* CRTC control values (CRTC_GEN_CNTL) */ #define CRTC_CSYNC_EN 0x00000010 +#define CRTC2_DBL_SCAN_EN 0x00000001 +#define CRTC2_DISPLAY_DIS 0x00800000 +#define CRTC2_FIFO_EXTSENSE 0x00200000 +#define CRTC2_ICON_EN 0x00100000 +#define CRTC2_CUR_EN 0x00010000 +#define CRTC2_EN 0x02000000 +#define CRTC2_DISP_REQ_EN_B 0x04000000 + #define CRTC_PIX_WIDTH_MASK 0x00000700 #define CRTC_PIX_WIDTH_4BPP 0x00000100 #define CRTC_PIX_WIDTH_8BPP 0x00000200 @@ -267,10 +298,14 @@ #define DAC_MASK 0xFF000000 #define DAC_BLANKING 0x00000004 #define DAC_RANGE_CNTL 0x00000003 -#define DAC_RANGE_CNTL 0x00000003 +#define DAC_CLK_SEL 0x00000010 #define DAC_PALETTE_ACCESS_CNTL 0x00000020 +#define DAC_PALETTE2_SNOOP_EN 0x00000040 #define DAC_PDWN 0x00008000 +/* CRTC_EXT_CNTL */ +#define CRT_CRTC_ON 0x00008000 + /* GEN_RESET_CNTL bit constants */ #define SOFT_RESET_GUI 0x00000001 #define SOFT_RESET_VCLK 0x00000100 @@ -348,5 +383,37 @@ #define LVDS_BL_MOD_EN 0x00010000 #define LVDS_DIGION 0x00040000 #define LVDS_BLON 0x00080000 +#define LVDS_ON 0x00000001 +#define LVDS_DISPLAY_DIS 0x00000002 +#define LVDS_PANEL_TYPE_2PIX_PER_CLK 0x00000004 +#define LVDS_PANEL_24BITS_TFT 0x00000008 +#define LVDS_FRAME_MOD_NO 0x00000000 +#define LVDS_FRAME_MOD_2_LEVELS 0x00000010 +#define LVDS_FRAME_MOD_4_LEVELS 0x00000020 +#define LVDS_RST_FM 0x00000040 +#define LVDS_EN 0x00000080 + +/* CRTC2_GEN_CNTL constants */ +#define CRTC2_EN 0x02000000 + +/* POWER_MANAGEMENT constants */ +#define PWR_MGT_ON 0x00000001 +#define PWR_MGT_MODE_MASK 0x00000006 +#define PWR_MGT_MODE_PIN 0x00000000 +#define PWR_MGT_MODE_REGISTER 0x00000002 +#define PWR_MGT_MODE_TIMER 0x00000004 +#define PWR_MGT_MODE_PCI 0x00000006 +#define PWR_MGT_AUTO_PWR_UP_EN 0x00000008 +#define PWR_MGT_ACTIVITY_PIN_ON 0x00000010 +#define PWR_MGT_STANDBY_POL 0x00000020 +#define PWR_MGT_SUSPEND_POL 0x00000040 +#define PWR_MGT_SELF_REFRESH 0x00000080 +#define PWR_MGT_ACTIVITY_PIN_EN 0x00000100 +#define PWR_MGT_KEYBD_SNOOP 0x00000200 +#define PWR_MGT_TRISTATE_MEM_EN 0x00000800 +#define PWR_MGT_SELW4MS 0x00001000 +#define PWR_MGT_SLOWDOWN_MCLK 0x00002000 + +#define PMI_PMSCR_REG 0x60 #endif /* REG_RAGE128_H */ diff -urN --exclude-from=/home/davej/.exclude linux-2.5.5/drivers/video/aty128fb.c linux-2.5/drivers/video/aty128fb.c --- linux-2.5.5/drivers/video/aty128fb.c Wed Feb 20 02:11:02 2002 +++ linux-2.5/drivers/video/aty128fb.c Sun Mar 3 17:54:36 2002 @@ -7,13 +7,19 @@ * Ani Joshi / Jeff Garzik * - Code cleanup * + * Michel Dänzer + * - 15/16 bit cleanup + * - fix panning + * + * Benjamin Herrenschmidt + * - pmac-specific PM stuff + * * Andreas Hundt * - FB_ACTIVATE fixes * * Based off of Geert's atyfb.c and vfb.c. * * TODO: - * - panning * - monitor sensing (DDC) * - virtual display * - other platform support (only ppc/x86 supported) @@ -70,6 +76,9 @@ #ifdef CONFIG_FB_COMPAT_XPMAC #include #endif +#ifdef CONFIG_BOOTX_TEXT +#include +#endif /* CONFIG_BOOTX_TEXT */ #include